353 lines
9.4 KiB
C
353 lines
9.4 KiB
C
/*****************************************************************************
|
||
*
|
||
* COPYRIGHT 1993 - COLORADO MEMORY SYSTEMS, INC.
|
||
* ALL RIGHTS RESERVED.
|
||
*
|
||
******************************************************************************
|
||
*
|
||
* FILE: \SE\DRIVER\Q117KDI\NT\SRC\0X15A09.C
|
||
*
|
||
* FUNCTION: kdi_InitializeController
|
||
*
|
||
* PURPOSE:
|
||
*
|
||
* HISTORY:
|
||
* $Log: J:\se.vcs\driver\q117kdi\nt\src\0x15a09.c $
|
||
*
|
||
* Rev 1.3 10 Aug 1994 09:53:14 BOBLEHMA
|
||
* Added a cast to thread_handle to remove compiler warning.
|
||
*
|
||
* Rev 1.2 26 Apr 1994 16:17:36 KEVINKES
|
||
* Changed timeout to an SDDWord.
|
||
*
|
||
* Rev 1.1 18 Jan 1994 16:23:58 KEVINKES
|
||
* Updated the debug code and fixed compile errors.
|
||
*
|
||
* Rev 1.0 02 Dec 1993 15:07:26 KEVINKES
|
||
* Initial Revision.
|
||
*
|
||
*****************************************************************************/
|
||
#define FCT_ID 0x15A09
|
||
#include "include\public\adi_api.h"
|
||
#include "include\public\frb_api.h"
|
||
#include "q117kdi\include\kdiwhio.h"
|
||
#include "q117kdi\include\kdiwpriv.h"
|
||
#include "include\private\kdi_pub.h"
|
||
#include "include\private\cqd_pub.h"
|
||
/*endinclude*/
|
||
|
||
NTSTATUS kdi_InitializeController
|
||
(
|
||
/* INPUT PARAMETERS: */
|
||
|
||
ConfigDataPtr config_data_ptr,
|
||
dUByte controller_number,
|
||
PDRIVER_OBJECT driver_object_ptr,
|
||
PUNICODE_STRING registry_path_ptr
|
||
|
||
/* UPDATE PARAMETERS: */
|
||
|
||
/* OUTPUT PARAMETERS: */
|
||
|
||
)
|
||
/* COMMENTS: *****************************************************************
|
||
*
|
||
* Routine Description:
|
||
*
|
||
* This routine is called at initialization time by DriverEntry() -
|
||
* once for each controller that the configuration manager tells it we
|
||
* have to support.
|
||
*
|
||
* When this routine is called, the configuration data has already been
|
||
* filled in.
|
||
*
|
||
* Arguments:
|
||
*
|
||
* config_data_ptr - a pointer to the structure that describes the
|
||
* controller and the disks attached to it, as given to us by the
|
||
* configuration manager.
|
||
*
|
||
* controller_number - which controller in config_data_ptr we are
|
||
* initializing.
|
||
*
|
||
* driver_object_ptr - a pointer to the object that represents this device
|
||
* driver.
|
||
*
|
||
* Return Value:
|
||
*
|
||
* STATUS_SUCCESS if this controller and at least one of its disks were
|
||
* initialized; an error otherwise.
|
||
*
|
||
* DEFINITIONS: *************************************************************/
|
||
{
|
||
|
||
/* DATA: ********************************************************************/
|
||
|
||
KdiContextPtr kdi_context;
|
||
dVoidPtr thread_object_ptr;
|
||
NTSTATUS nt_status;
|
||
NTSTATUS nt_status_2;
|
||
HANDLE thread_handle = 0;
|
||
dBoolean partly_successful;
|
||
dSDDWord timeout;
|
||
dUByte nt_name_buffer[256];
|
||
STRING nt_name_string;
|
||
UNICODE_STRING nt_unicode_string;
|
||
dVoidPtr cqd_context;
|
||
|
||
/* CODE: ********************************************************************/
|
||
|
||
kdi_CheckedDump(QIC117INFO,
|
||
"Q117iInitializeController...\n", 0l);
|
||
|
||
/* This routine will take attempt to "append" the resources */
|
||
/* used by this controller into the resource map of the */
|
||
/* registry. If there was a conflict with previously "declared" */
|
||
/* data, then this routine will return false, in which case we */
|
||
/* will NOT try to initialize this particular controller. */
|
||
|
||
/* Allocate and zero-initialize data to describe this controller */
|
||
|
||
kdi_context = (KdiContextPtr) ExAllocatePool(
|
||
NonPagedPool,
|
||
sizeof( KdiContext ) );
|
||
|
||
if ( kdi_context == NULL ) {
|
||
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
RtlZeroMemory( kdi_context, sizeof( KdiContext ) );
|
||
|
||
/* Allocate and zero-initialize data for the QIC driver. */
|
||
|
||
cqd_context = ExAllocatePool(
|
||
NonPagedPool,
|
||
cqd_ReportContextSize());
|
||
|
||
if ( cqd_context == NULL ) {
|
||
|
||
ExFreePool( kdi_context );
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
RtlZeroMemory( cqd_context, cqd_ReportContextSize() );
|
||
|
||
|
||
(dVoid) sprintf(
|
||
nt_name_buffer,
|
||
"\\Device\\FloppyControllerEvent%d",
|
||
controller_number );
|
||
|
||
RtlInitString( &nt_name_string, nt_name_buffer );
|
||
|
||
nt_status = RtlAnsiStringToUnicodeString(
|
||
&nt_unicode_string,
|
||
&nt_name_string,
|
||
dTRUE );
|
||
|
||
kdi_context->controller_event = IoCreateSynchronizationEvent(
|
||
&nt_unicode_string,
|
||
&kdi_context->controller_event_handle);
|
||
|
||
RtlFreeUnicodeString( &nt_unicode_string );
|
||
|
||
if ( kdi_context->controller_event == dNULL_PTR ) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
/* Fill in some items that we got from configuration management and */
|
||
/* the HAL. */
|
||
|
||
kdi_context->base_address =
|
||
config_data_ptr->controller[controller_number].controller_base_address;
|
||
kdi_context->actual_controller_number =
|
||
config_data_ptr->controller[controller_number].actual_controller_number;
|
||
|
||
switch (config_data_ptr->controller[controller_number].interface_type) {
|
||
|
||
case Isa:
|
||
kdi_context->interface_type = ISA;
|
||
break;
|
||
case Eisa:
|
||
kdi_context->interface_type = EISA;
|
||
break;
|
||
case MicroChannel:
|
||
kdi_context->interface_type = MICRO_CHANNEL;
|
||
break;
|
||
case PCIBus:
|
||
kdi_context->interface_type = PCI_BUS;
|
||
break;
|
||
case PCMCIABus:
|
||
kdi_context->interface_type = PCMCIA;
|
||
break;
|
||
default:
|
||
kdi_context->interface_type = ISA;
|
||
|
||
}
|
||
|
||
|
||
/* Initialize the interlocked request queue, including a */
|
||
/* counting semaphore to indicate items in the queue */
|
||
|
||
KeInitializeSemaphore(
|
||
&kdi_context->request_semaphore,
|
||
0L,
|
||
MAXLONG );
|
||
|
||
KeInitializeSpinLock( &kdi_context->list_spin_lock );
|
||
|
||
InitializeListHead( &kdi_context->list_entry );
|
||
|
||
/* Initialize events to signal interrupts and adapter object */
|
||
/* allocation */
|
||
|
||
KeInitializeEvent(
|
||
&kdi_context->interrupt_event,
|
||
SynchronizationEvent,
|
||
FALSE);
|
||
|
||
|
||
KeInitializeEvent(
|
||
&kdi_context->allocate_adapter_channel_event,
|
||
NotificationEvent,
|
||
FALSE );
|
||
|
||
|
||
KeInitializeEvent(
|
||
&kdi_context->clear_queue_event,
|
||
SynchronizationEvent,
|
||
FALSE);
|
||
|
||
|
||
|
||
/* Create a thread with entry point Q117iTapeThread() */
|
||
|
||
nt_status = PsCreateSystemThread(
|
||
&thread_handle,
|
||
(ACCESS_MASK) 0L,
|
||
(POBJECT_ATTRIBUTES) NULL,
|
||
(HANDLE) 0L,
|
||
(PCLIENT_ID) NULL,
|
||
(PKSTART_ROUTINE) kdi_ThreadRun,
|
||
(PVOID) kdi_context );
|
||
|
||
#if DBG
|
||
if ( !NT_SUCCESS( nt_status ) ) {
|
||
|
||
kdi_CheckedDump(QIC117DBGP,
|
||
"q117i: error creating thread: %08x\n",
|
||
nt_status );
|
||
}
|
||
#endif
|
||
|
||
if ( NT_SUCCESS( nt_status ) ) {
|
||
|
||
kdi_CheckedDump(QIC117INFO,
|
||
"Q117iThread = %08x\n",
|
||
(dUDWord)thread_handle);
|
||
|
||
/* Call Q117iInitializeDrive() for each drive on the */
|
||
/* controller */
|
||
|
||
config_data_ptr->controller[controller_number].number_of_tape_drives++;
|
||
|
||
nt_status = STATUS_NO_SUCH_DEVICE;
|
||
partly_successful = FALSE;
|
||
|
||
nt_status = kdi_InitializeDrive(
|
||
config_data_ptr,
|
||
kdi_context,
|
||
cqd_context,
|
||
controller_number,
|
||
driver_object_ptr,
|
||
registry_path_ptr );
|
||
}
|
||
|
||
|
||
/* If we're exiting with an error, clean up first. */
|
||
|
||
if ( !NT_SUCCESS( nt_status ) ) {
|
||
|
||
kdi_CheckedDump(QIC117DBGP,
|
||
"q117i: InitializeController failing\n", 0l);
|
||
|
||
/* If we created the thread, wake it up and tell it to kill itself. */
|
||
/* Wait until it's dead. (Note that since it's a system thread, */
|
||
/* it has to kill itself - we can't do it). */
|
||
|
||
if ( thread_handle != 0 ) {
|
||
|
||
kdi_context->unloading_driver = TRUE;
|
||
|
||
nt_status_2 = ObReferenceObjectByHandle(
|
||
thread_handle,
|
||
THREAD_ALL_ACCESS,
|
||
NULL,
|
||
KernelMode,
|
||
(PVOID *) &thread_object_ptr,
|
||
NULL );
|
||
|
||
(VOID) KeReleaseSemaphore(
|
||
&kdi_context->request_semaphore,
|
||
(KPRIORITY) 0,
|
||
1,
|
||
FALSE );
|
||
|
||
if ( NT_SUCCESS( nt_status_2 ) ) {
|
||
|
||
/* The thread object will be signalled when it dies. */
|
||
|
||
nt_status_2 = KeWaitForSingleObject(
|
||
(PVOID) thread_object_ptr,
|
||
Suspended,
|
||
KernelMode,
|
||
FALSE,
|
||
(PLARGE_INTEGER) NULL );
|
||
|
||
ASSERT( nt_status_2 == STATUS_SUCCESS );
|
||
|
||
ObDereferenceObject( thread_object_ptr );
|
||
|
||
} else {
|
||
|
||
/* We can't get the thread object for some reason; just */
|
||
/* block for a while to give the thread a chance to run */
|
||
/* and die. */
|
||
|
||
kdi_CheckedDump(QIC117DBGP,
|
||
"q117i: couldn't get thread object\n", 0l);
|
||
|
||
|
||
timeout =
|
||
RtlLargeIntegerNegate(
|
||
RtlEnlargedIntegerMultiply(
|
||
10,
|
||
10l * 1000l
|
||
)
|
||
);
|
||
(VOID) KeDelayExecutionThread(
|
||
KernelMode,
|
||
FALSE,
|
||
&timeout );
|
||
}
|
||
}
|
||
|
||
|
||
if ( kdi_context->controller_event != NULL ) {
|
||
// Tell others that it is safe to use the controller
|
||
(VOID) KeSetEvent(
|
||
kdi_context->controller_event,
|
||
(KPRIORITY) 0,
|
||
FALSE );
|
||
|
||
}
|
||
|
||
ExFreePool( kdi_context );
|
||
ExFreePool( cqd_context );
|
||
|
||
}
|
||
|
||
return nt_status;
|
||
}
|