/*++

Copyright (c) 1995 Microsoft Corporation

Module Name:

    initunlo.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"




NTSTATUS
IrCommAddDevice(
    IN PDRIVER_OBJECT DriverObject,
    IN PDEVICE_OBJECT Pdo
    )

{
    NTSTATUS       Status;

    WCHAR          TempBuffer[256];

    PDEVICE_OBJECT Fdo = NULL;

    PDEVICE_OBJECT LowerDevice=NULL;

    //
    // Pointer to the device extension created for this
    // device
    //
    PFDO_DEVICE_EXTENSION DeviceExtension = NULL;

    D_PNP(DbgPrint("IrComm: AddDevice\n");)


    //
    // Create the device object for this device.
    //

    Status = IoCreateDevice(
                 DriverObject,
                 sizeof(FDO_DEVICE_EXTENSION),
                 NULL,
                 FILE_DEVICE_NULL,
                 FILE_AUTOGENERATED_DEVICE_NAME,
                 FALSE,
                 &Fdo
                 );

    if (!NT_SUCCESS(Status)) {

        goto CleanUp;
    }

    LowerDevice=IoAttachDeviceToDeviceStack(
        Fdo,
        Pdo
        );

    if (LowerDevice == NULL) {

        D_ERROR(DbgPrint("IRCOMM: Could not attach to PDO\n");)

        Status=STATUS_INSUFFICIENT_RESOURCES;

        goto CleanUp;
    }

    Fdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
    Fdo->Flags &= ~DO_DEVICE_INITIALIZING;

    Fdo->StackSize=LowerDevice->StackSize+1;

    DeviceExtension=Fdo->DeviceExtension;

    D_ERROR(DbgPrint("IRCOMM: Device Extension %p\n",DeviceExtension);)

    DeviceExtension->DeviceObject = Fdo;
    DeviceExtension->Pdo=Pdo;
    DeviceExtension->LowerDevice=LowerDevice;

    KeInitializeTimer(
        &DeviceExtension->Read.IntervalTimer
        );

    KeInitializeDpc(
        &DeviceExtension->Read.IntervalTimerDpc,
        IntervalTimeProc,
        DeviceExtension
        );

    KeInitializeTimer(
        &DeviceExtension->Read.TotalTimer
        );

    KeInitializeDpc(
        &DeviceExtension->Read.TotalTimerDpc,
        TotalTimerProc,
        DeviceExtension
        );


    KeInitializeSpinLock(
        &DeviceExtension->SpinLock
        );



    KeInitializeSpinLock(
        &DeviceExtension->Read.ReadLock
        );


    KeInitializeSpinLock(
        &DeviceExtension->Mask.Lock
        );



    IrCommHandleSymbolicLink(
        Pdo,
        &DeviceExtension->InterfaceName,
        TRUE
        );


    {
        IRCOMM_BUS_INFO    BusInfo;

        QueryPdoInformation(
            Pdo,
            IRENUM_CONFIG_SPACE_INFO,
            &BusInfo,
            sizeof(BusInfo)
            );

        DeviceExtension->DeviceAddress=BusInfo.DeviceAddress;
    }

    InitializePacketQueue(
        &DeviceExtension->Write.Queue,
        DeviceExtension,
        WriteStartRoutine
        );

    InitializePacketQueue(
        &DeviceExtension->Read.Queue,
        DeviceExtension,
        ReadStartRoutine
        );

    InitializePacketQueue(
        &DeviceExtension->Mask.Queue,
        DeviceExtension,
        MaskStartRoutine
        );

    InitializePacketQueue(
        &DeviceExtension->Uart.Queue,
        DeviceExtension,
        UartStartRoutine
        );

#if 0
    DeviceExtension->LineControl.StopBits=1;
    DeviceExtension->LineControl.Parity=0;
    DeviceExtension->LineControl.WordLength=8;

    DeviceExtension->BaudRate=115200;
#endif
    DeviceExtension->Read.BytesInBuffer=0;
    DeviceExtension->Read.NextFilledByte=&DeviceExtension->Read.InputBuffer[0];
    DeviceExtension->Read.NextEmptyByte=&DeviceExtension->Read.InputBuffer[0];

    return STATUS_SUCCESS;

CleanUp:

    IoDeleteDevice(Fdo);

    return Status;

}

NTSTATUS
IrCommPnP(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )

{

    PFDO_DEVICE_EXTENSION   DeviceExtension = DeviceObject->DeviceExtension;
    PIO_STACK_LOCATION      irpSp = IoGetCurrentIrpStackLocation(Irp);
    NTSTATUS                status;
    ULONG                   i;



    switch (irpSp->MinorFunction) {

        case IRP_MN_START_DEVICE:

            D_PNP(DbgPrint("IRCOMM: IRP_MN_START_DEVICE\n");)

            Irp->IoStatus.Status = STATUS_SUCCESS;

            return ForwardIrp(DeviceExtension->LowerDevice, Irp);


        case IRP_MN_QUERY_STOP_DEVICE:

            D_PNP(DbgPrint("IRCOMM: IRP_MN_QUERY_STOP_DEVICE\n");)

            Irp->IoStatus.Status = STATUS_SUCCESS;

            return ForwardIrp(DeviceExtension->LowerDevice, Irp);


        case IRP_MN_CANCEL_STOP_DEVICE:

            D_PNP(DbgPrint("IRCOMM: IRP_MN_CANCEL_STOP_DEVICE\n");)

            Irp->IoStatus.Status = STATUS_SUCCESS;

            return ForwardIrp(DeviceExtension->LowerDevice, Irp);


        case IRP_MN_STOP_DEVICE:

            D_PNP(DbgPrint("IRCOMM: IRP_MN_STOP_DEVICE\n");)

            Irp->IoStatus.Status = STATUS_SUCCESS;

            return ForwardIrp(DeviceExtension->LowerDevice, Irp);


        case IRP_MN_QUERY_REMOVE_DEVICE:

            D_PNP(DbgPrint("IrComm: IRP_MN_QUERY_REMOVE_DEVICE\n");)

            Irp->IoStatus.Status = STATUS_SUCCESS;

            return ForwardIrp(DeviceExtension->LowerDevice, Irp);


        case IRP_MN_CANCEL_REMOVE_DEVICE:

            D_PNP(DbgPrint("IrComm: IRP_MN_CANCEL_REMOVE_DEVICE\n");)

            Irp->IoStatus.Status = STATUS_SUCCESS;

            return ForwardIrp(DeviceExtension->LowerDevice, Irp);

        case IRP_MN_SURPRISE_REMOVAL: {

            D_PNP(DbgPrint("IrComm: IRP_MN_SURPRISE_REMOVAL\n");)

            DeviceExtension->Removing=TRUE;

            //
            //  now that new io is blocked, flush out all pended irps
            //
            CleanupIoRequests(DeviceExtension);

            Irp->IoStatus.Status = STATUS_SUCCESS;

            return ForwardIrp(DeviceExtension->LowerDevice, Irp);

        }
        break;


        case IRP_MN_REMOVE_DEVICE: {

            ULONG    NewReferenceCount;

            D_PNP(DbgPrint("IrComm: IRP_MN_REMOVE_DEVICE\n");)
            //
            //  removing now for sure
            //
            DeviceExtension->Removing=TRUE;
            DeviceExtension->Removed=TRUE;


            if (DeviceExtension->InterfaceName.Buffer != NULL) {

                IrCommHandleSymbolicLink(
                    DeviceExtension->Pdo,
                    &DeviceExtension->InterfaceName,
                    FALSE
                    );
            }

            IoCopyCurrentIrpStackLocationToNext(Irp);

            status=IoCallDriver(DeviceExtension->LowerDevice, Irp);

            //
            //  detach from the driver below
            //
            IoDetachDevice(DeviceExtension->LowerDevice);

            //
            //  delete our device object
            //
            IoDeleteDevice(DeviceObject);

            D_PNP(DbgPrint("IrComm: IRP_MN_REMOVE_DEVICE exit, %08lx\n",status);)

            return status;

        }


        default:
            D_PNP(DbgPrint("IrComm: Sending to PDO PnP IRP, MN func=%d\n",irpSp->MinorFunction);)

            return ForwardIrp(DeviceExtension->LowerDevice, Irp);
    }



    IoCompleteRequest(Irp,IO_NO_INCREMENT);

    return STATUS_SUCCESS;

}

NTSTATUS
IrCommPower(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )

{
    PFDO_DEVICE_EXTENSION   DeviceExtension = DeviceObject->DeviceExtension;

    PoStartNextPowerIrp(Irp);

    IoSkipCurrentIrpStackLocation(Irp);

    return PoCallDriver(DeviceExtension->LowerDevice, Irp);

}

NTSTATUS
IrCommWmi(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )

{

    IoCompleteRequest(Irp,IO_NO_INCREMENT);

    return STATUS_SUCCESS;

}
