home *** CD-ROM | disk | FTP | other *** search
- /* semfisdd.c */
-
- /* Device Driver for IBM SDLC adapter. */
-
- #ifndef IMADRIVER
- #error - driver code requires IMADRIVER be defined on command line
- #endif
-
- #include <stddef.h>
- #include <ntddk.h>
-
- #include <semfismi.h>
- #include <semfistr.h>
- #include <semfisnt.h>
- #include <semfisdm.h>
- #include <semfis73.h>
- #include <semfissp.h>
- #include <semfisis.h>
- #include <semfisrb.h>
- #include <semfisfs.h>
- #include <seclink.h>
- #include <semfisdo.h>
- #include <semfispr.h>
- #include <semfisda.h>
- #include <semfisel.h>
-
-
- // Temporary Usage : function prototype declaration should be pulled in
-
- extern NTSTATUS
- ZwOpenKey(
- OUT PHANDLE KeyHandle,
- IN ACCESS_MASK DesiredAccess,
- IN POBJECT_ATTRIBUTES ObjectAttributes
- );
-
-
-
- /* semfiddd.c - NT Device Driver for IBM SDLC adapter */
-
-
- /**PROC+**********************************************************************/
- /* */
- /* Name AdapterExistenceCheck ( */
- /* PCONFIGDATA pConfigData */
- /* ); */
- /* */
- /* Purpose Hardware-specific of initialising */
- /* */
- /* Params IN pConfigData: the config data record for adapter to be checked*/
- /* */
- /* Return Value BOOLean: TRUE if the adapter is present and responding */
- /* */
- /* Side Effect: For MPAA, sets dma channel in config data! This will then */
- /* immediately be copied to the Device Object config data ( so */
- /* no danger of it being used by another configdata record in */
- /* error. */
- /* */
- /* Operation: Tries to read ports confirming the presence of the adapter */
- /* This is a trivial check of one port, suitable for start of */
- /* day checks just to tell us if the device should be created. */
- /* Real hardware initialisation is done on open. */
- /* */
- /* Notes We do as little as we can get away with here because a) we */
- /* don't have a full device extension set up and b) to avoid */
- /* causing interrupts hopefully. */
- /* */
- /**PROC-**********************************************************************/
-
- BOOLean AdapterExistenceCheck (
- PCONFIGDATA pConfigData
- )
- {
- BOOLean FoundMPA;
-
- if (pConfigData->AdapterType EQ AT_SDLC ||
- pConfigData->AdapterType EQ AT_MPCA1 ||
- pConfigData->AdapterType EQ AT_MPCA2)
- {
- if (pConfigData->MPCAModePort NE 0)
- {
- /***********************************************************************/
- /* This is an MPCA adapter, we hope. Disable and reenable it */
- /***********************************************************************/
- WR_N_DELAY (pConfigData->MPCAModePort, AC_MPCAD);
- WR_N_DELAY (pConfigData->MPCAModePort, pConfigData->MPCAModeValue);
-
- TRACE_DATABYTE (Mpc, pConfigData->MPCAModeValue);
- }
-
- /*************************************************************************/
- /* There isn't a reliable way of determining if the MPCA/SDLC cards */
- /* are present. So at this stage say they are and let non-existence */
- /* show up later as an Open error. */
- /*************************************************************************/
-
- return (TRUE);
- }
-
- if (pConfigData->AdapterType EQ AT_MPAA1 ||
- pConfigData->AdapterType EQ AT_MPAA2)
- {
- IO_ADDRESS AdapterSelector;
-
- for (
- FoundMPA = FALSE,
- AdapterSelector = (IO_ADDRESS) 8;
- AdapterSelector < (IO_ADDRESS) 0x10;
- AdapterSelector++
- )
- {
- WR_N_DELAY (POS_Adapter_Select, (UCHAR) AdapterSelector);
-
- if (IO_IN (POS_AdapterID_HiByte) EQ HIBYTE(POS_MPAATypeID) &&
- IO_IN (POS_AdapterID_LoByte) EQ LOBYTE(POS_MPAATypeID) &&
- ((UCHAR)
- (IO_IN(POS_ConfigByte2) & 0x1F)
- ) EQ pConfigData->MPAAAdapterIdentifier)
- {
- FoundMPA = TRUE;
- pConfigData->DMAChannel = (UCHAR) (IO_IN (POS_ConfigByte3) & 7);
- break;
- }
- }
-
- WR_N_DELAY (POS_Adapter_Select, 7);
-
- return (FoundMPA);
- }
- }
-
- /*****************************************************************************/
- /* */
- /* Name AdapterReset */
- /* */
- /* Purpose Reset an adapter and prime it */
- /* */
- /* Params IN pDX */
- /* */
- /* OUT None */
- /* */
- /* Modified: 31/03/88 Initial coding */
- /* */
- /*****************************************************************************/
-
- void AdapterReset (PDX pDX)
- {
- TRACE_EVENT (<ARs); /* every body needs one... */
-
- pDX->HardwareError = FALSE; /* if user screwed up on hardware */
- /* previously, we'll let him try */
- /* again this time */
-
- /***************************************************************************/
- /* If an MPCA has been configured then write out the mode set byte. */
- /***************************************************************************/
-
- if (pDX->ConfigData.MPCAModePort NE 0)
- {
- WR_N_DELAY (pDX->ConfigData.MPCAModePort, pDX->ConfigData.MPCAModeValue);
- TRACE_DATABYTE (Mpc, pDX->ConfigData.MPCAModeValue);
- }
-
- /***************************************************************************/
- /* Now mode set the 8255. */
- /***************************************************************************/
-
- WR_N_DELAY (pDX->ADAPTERBASE+AR_8255, A55_ModeSet);
-
- IO_OUT (pDX->ADAPTERBASE+AR_8255B,A55_Reset8273On);
- KeStallExecutionProcessor (10L); /* a long delay for reset on */
-
- WR_N_DELAY (pDX->ADAPTERBASE+AR_8255B,A55_Reset8273Off);
-
- IO_OUT (pDX->ADAPTERBASE+AR_8255C, A55_InitPortC);
-
- TRACE_EVENT (ARs>);
- }
-
- /**PROC+**********************************************************************/
- /* */
- /* Name AllocateDMAMemory ( */
- /* int BufferSize */
- /* PVOID *pBufferPtr */
- /* PMDL *pMdl */
- /* PHYSICAL_A *pPhysAddr */
- /* ULONG *ErrorInformation */
- /* ); */
- /* */
- /* Purpose Modularise the steps to allocate/deallocate and check DMA mem*/
- /* Also, make freeing up easy (like, free everything on failure)*/
- /* */
- /* Params IN BufferSize */
- /* OUT BufferPtr pointer to actual memory */
- /* OUT pMdl the allocated mdl */
- /* OUT pPhysAddr physical memory's address */
- /* OUT ErrorInformation: suitable for IoStatus.Information */
- /* */
- /* Return Value BOOLean: TRUE if everything allocated OK */
- /* */
- /**PROC-**********************************************************************/
-
- BOOLean AllocateDMAMemory (
- ULONG BufferSize,
- PVOID *pBufferPtr,
- PMDL *ppMdl,
- PHYSICAL_ADDRESS * pPhysAddr,
- ULONG *ErrorInformation
- )
- {
- BOOLean ReturnCode = TRUE;
-
- TRACE_EVENT (<Dma);
-
- *pBufferPtr = NULL;
- *ppMdl = NULL;
-
- *pBufferPtr = MmAllocateContiguousMemory (BufferSize,
- RtlConvertUlongToLargeInteger (0xFFFFFFL) );
- if (*pBufferPtr EQ NULL)
- {
- ReturnCode = FALSE;
- *ErrorInformation = IO_ERR_CANT_ALLOCATE_MEMORY;
- }
-
- if (ReturnCode)
- {
- *ppMdl = IoAllocateMdl(*pBufferPtr,
- BufferSize,
- FALSE, /* this is not a secondary buffer */
- FALSE, /* no charge to quota */
- (PIRP)NULL /* not attached to IRP */
- );
- if (*ppMdl EQ NULL)
- {
- ReturnCode = FALSE;
- *ErrorInformation = IO_ERR_CANT_ALLOCATE_MDL;
- }
- }
- if (ReturnCode)
- {
- MmProbeAndLockPages (*ppMdl, KernelMode, IoModifyAccess);
-
- *pPhysAddr = MmGetPhysicalAddress(*pBufferPtr);
- ASSERT ((pPhysAddr->LowPart | pPhysAddr->HighPart) NE 0L);
-
- /* check our understanding of MmAllocateContiguousMemory */
-
- ASSERT (BITSOFF(pPhysAddr->LowPart, 0xFF000000L));
- if (DMACrosses64K(pPhysAddr->LowPart, BufferSize))
- {
- ReturnCode = FALSE;
- *ErrorInformation = IO_ERR_DMA_BUFFER_UNUSABLE;
- }
- }
- if (!ReturnCode)
- {
- if (*ppMdl NE NULL)
- {
- IoFreeMdl (*ppMdl);
- *ppMdl = NULL;
- }
- if (*pBufferPtr NE NULL)
- {
- MmFreeContiguousMemory (*pBufferPtr);
- *pBufferPtr = NULL;
- }
- }
-
- TRACE_EVENT (Dma>);
- return (ReturnCode);
- }
-
- /**PROC+**********************************************************************/
- /* */
- /* Name: Close8273Sequence (PDX pDX) */
- /* */
- /* Purpose: To gracefully close down the 8273 */
- /* */
- /* Params: IN pDX */
- /* */
- /* Implicit input: Must not be called at interrupt or Synchronised level!!! */
- /* */
- /* Return Value:none */
- /* */
- /**PROC-**********************************************************************/
-
- void Close8273Sequence (PDX pDX)
- {
- TRACE_EVENT (<C73);
- /*************************************************************************/
- /* Clear down the transmitter and receiver and release the h/w. */
- /*************************************************************************/
-
- IoctlAbortTransmitter (pDX);
- IoctlAbortReceiver (pDX);
-
- KeSynchronizeExecution(pDX->Interrupt, SynchReset8273, (PVOID) pDX);
-
- /*************************************************************************/
- /* Drop back down to non-interrupt level to allow pending interrupts in. */
- /* The SynchReset8273 call above sets the Closing flag */
- /*************************************************************************/
-
- KeSynchronizeExecution(pDX->Interrupt, SynchTerminateAdapter, (PVOID) pDX);
-
- pDX->AdapterIsClosing = FALSE;
- TRACE_EVENT (C73>);
- }
-
- /**PROC+**********************************************************************/
- /* */
- /* Name: CompleteIoRequest (PIRP pIrp) */
- /* */
- /* Purpose: The Io request must be completed for each entry point. */
- /* */
- /* Params: IN pIrp The Io Request to be completed */
- /* */
- /* Return Value:none */
- /* */
- /* Operation: The Io request must be completed at despatch level */
- /* */
- /**PROC-**********************************************************************/
-
- void CompleteIoRequest (PIRP pIrp)
- {
- /***************************************************************************/
- /* IoCompleteRequest used to need a RaiseIrql ... but no longer does. */
- /* Keep this as a subroutine for now - could become a macro later. */
- /***************************************************************************/
-
- //KIRQL PreviousIrql;
-
- //KeRaiseIrql (DISPATCH_LEVEL, &PreviousIrql);
-
- IoCompleteRequest (pIrp, 0); /* 0 => no priority boost for APC */
-
- //KeLowerIrql (PreviousIrql);
-
- TRACE_EVENT (S+I:);
- TRACE_DWORD (pIrp->IoStatus.Status);
- TRACE_DWORD (pIrp->IoStatus.Information);
-
- }
-
- /**PROC+**********************************************************************/
- /* */
- /* Name: DeviceInit ( */
- /* PDRIVER_OBJECT DriverObject */
- /* CHAR * DeviceName, */
- /* PCONFIGDATA pConfigData, */
- /* ) */
- /* */
- /* Purpose: Initialise the next device (from GetDriverSpec) */
- /* Called for each configured device from DriverEntry. */
- /* */
- /* Params: IN DriverObject: Us! */
- /* IN DeviceName: COMDL$0x (from GetDriverSpec()) */
- /* IN pConfigData: config data to use */
- /* */
- /* Return Value:BOOLean: TRUE if device successfully initialised */
- /* */
- /* Operation: The general principle is: do as little as possible to here - */
- /* just establish the device exists and allocate a device */
- /* object for it. Any allocation of resources is done on open */
- /* to avoid using resources unnecessarily. This applies to */
- /* interrupt objects, */
- /* */
- /* 0. On input, driver and flavour name read from cfg register */
- /* */
- /* 1. If */
- /* |--> HardwareExistenceCheck */
- /* fails, */
- /* return failure */
- /* */
- /* 2. Init for NT */
- /* - allocate DeviceObject */
- /* - DO_DIRECT_IO */
- /* - IoInitializeDpcRequest */
- /* */
- /* 3. Init the device extension fields we need to know now: */
- /* - DeviceIsOpen = FALSE */
- /* - pointer to config data */
- /* */
- /* Note: The parallel driver returns an NT status from an equivalent */
- /* routine. Eventually, we may do the same via ErrorCode param.*/
- /* But for now we don't set error code, because the NTSTATUS */
- /* returned from the parallel driver routine is ignored. */
- /* */
- /**PROC-**********************************************************************/
-
- BOOLean DeviceInit (
- PDRIVER_OBJECT pDriverObject,
- CHAR * DeviceName,
- PCONFIGDATA pConfigData
- )
- {
- STRING NameString; /* counted string for NT */
- PDEVICE_OBJECT pDeviceObject; /* allocated by NT for our device */
- PDX pDX; /* pointer to our device extension */
- NTSTATUS Status;
- UNICODE_STRING UniNameString; /* same thing in UniCode */
-
- if (!AdapterExistenceCheck(pConfigData))
- {
- TRACE_EVENT (DiNa); /* DeviceInit: No adapter */
- DEBUG_PRINT (("IBMSYNC: Existence check failed for Adapter %s\n",
- pConfigData->FlavourName));
- return (FALSE); /* no device so can't initialise devc*/
- }
-
- RtlInitString (&NameString, DeviceName);
- Status = RtlAnsiStringToUnicodeString (&UniNameString, &NameString, TRUE);
- ASSERT(NT_SUCCESS(Status)); /* UniNameString now has unicode dvnm*/
-
- Status = IoCreateDevice(
- pDriverObject,
- sizeof( IBMSYNC_DEVICE_EXTENSION ),
- &UniNameString,
- FILE_DEVICE_DATALINK,
- 0,
- TRUE, /* open exclusively */
- &pDeviceObject
- );
- RtlFreeUnicodeString (&UniNameString);
-
- /***************************************************************************/
- /* Note that we cannot log an error here since we do not hace a Device */
- /* Object. */
- /***************************************************************************/
- if (!NT_SUCCESS(Status))
- {
- TRACE_EVENT (DiNd); /* DeviceInit: No device */
- DEBUG_PRINT (("IBMSYNC: Cannot create Device : %s\n", DeviceName));
- return (FALSE);
- }
-
- /***************************************************************************/
- /* We have a device object OK - which is the main thing to do at device */
- /* init time. Other initialisation stuff we leave till device opened. */
- /***************************************************************************/
-
- pDeviceObject->Flags |=DO_DIRECT_IO;
- pDX = pDeviceObject->DeviceExtension;
- pDX->DeviceIsOpen = FALSE;
- pDX->AdapterIsClosing = FALSE;
- pDX->PowerFailed = FALSE;
-
- /***************************************************************************/
- /* In theory, we don't have to do this config data copying (we could just */
- /* use a pointer to it, but that would be a) slower; b) tedious to code */
- /***************************************************************************/
-
- pDX->pDeviceObject = pDeviceObject;
- pDX->ConfigData = *pConfigData;
- pDX->Name[0] = 'A'; /* adapter */
- pDX->Name[1] = pConfigData->FlavourName[4];
-
- IoInitializeDpcRequest(pDeviceObject, DPCRoutine);
-
- DEBUG_PRINT (("IBMSYNC: Created Device : %s\n", DeviceName));
- return (TRUE);
- }
-
- /**PROC+**********************************************************************/
- /* */
- /* Name: DPCRoutine */
- /* */
- /* Purpose: */
- /* */
- /* Params: */
- /* */
- /* Return Value:None */
- /* */
- /**PROC-**********************************************************************/
-
-
- VOID DPCRoutine(
- IN PKDPC pDpc,
- IN PDEVICE_OBJECT pDeviceObject,
- IN PIRP pIrp,
- IN PVOID DeferredContext
- )
- {
- PDX pDX = pDeviceObject->DeviceExtension;
-
- TRACE_EVENT (<DPC);
-
- UNREFERENCED_PARAMETER (pDpc);
- UNREFERENCED_PARAMETER (pIrp);
- UNREFERENCED_PARAMETER (DeferredContext);
-
- ASSERT (pDX->DeviceIsOpen);
-
- if (pDX->DeviceIsOpen &&
- pDX->DPCAction & DPC_ACTION_PULSE &&
- pDX->pUserEvent NE NULL)
- {
- // KePulseEvent (pDX->pUserEvent, 0, FALSE); /* 0 pri boost, no wait */
- // KePulseEvent missing from API?
- KeSetEvent (pDX->pUserEvent, 0, FALSE);
- }
- pDX->DPCAction = 0; /* we've done all requested actions */
-
- TRACE_EVENT (DPC>);
- }
-
- /**PROC+**********************************************************************/
- /* */
- /* Name: DriverEntry( */
- /* PDRIVER_OBJECT DriverObject */
- /* IN PUNICODE_STRING RegistryPath */
- /* ) */
- /* */
- /* Purpose: As defined by NT. Called once only when NT loads driver */
- /* */
- /* Params: PDRIVER_OBJECT: pointer to us */
- /* */
- /* Return Value:NTSTATUS: STATUS_SUCCESS / STATUS_UNSUCCESSFUL */
- /* Unsuccessful if no devices initialised */
- /* */
- /**PROC-**********************************************************************/
-
-
- NTSTATUS DriverEntry (IN PDRIVER_OBJECT DriverObject,
- IN PUNICODE_STRING RegistryPath
- )
- {
- CHAR DeviceName [80];
- BOOLean GotADevice = FALSE;
- NTSTATUS RetStatus = STATUS_UNSUCCESSFUL;
- CONFIGDATA *pConfigData;
-
- // _asm int 3;
-
- TRACE_INIT();
- TRACE_EVENT(Entr);
-
- while (GetDriverSpec (DeviceName, &pConfigData))
- {
- if (DeviceInit (DriverObject, DeviceName, pConfigData))
- {
- GotADevice = TRUE;
- TRACE_EVENT (DevI);
- }
- }
-
- if ((GotADevice) && (GetInterfaceType (DriverObject)))
- {
- DriverObject->MajorFunction[IRP_MJ_CLOSE] = EntryPointClose;
- DriverObject->MajorFunction[IRP_MJ_CREATE] = EntryPointOpen;
- DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = EntryPointDevIoctl;
- DriverObject->DriverUnload = EntryPointUnload;
-
- RetStatus = STATUS_SUCCESS;
- }
- else
- {
- TRACE_EVENT (DrvF);
- }
-
- return (RetStatus);
- }
-
- /*****************************************************************************/
- /* */
- /* Name EntryPointClose */
- /* */
- /* Purpose Close Request Packet Handler */
- /* */
- /* This is the CLOSE processor. It flushes pending requests */
- /* and ensures that the hardware and LCB fields are tidily */
- /* closed down. */
- /* */
- /* Params IN None */
- /* */
- /* OUT Link hardware closed and pending requests flushed. */
- /* */
- /*****************************************************************************/
-
- NTSTATUS EntryPointClose
- (
- PDEVICE_OBJECT pDeviceObject,
- PIRP pIrp
- )
- {
- PDX pDX = pDeviceObject->DeviceExtension;
-
- NTSTATUS Status;
-
- TRACE_NEWLINE();
- TRACE_EVENT ({EPC);
-
- pIrp->IoStatus.Information = 0;
-
- if (pDX->DeviceIsOpen) /* use can close OK */
- {
- pIrp->IoStatus.Status = STATUS_SUCCESS;
-
- /*************************************************************************/
- /* Clear down the transmitter and receiver and release the h/w. */
- /*************************************************************************/
-
- Close8273Sequence (pDX); /* orderly close-down of adapter */
-
- IoDisconnectInterrupt (pDX->Interrupt);
-
- if (pDX->ConfigData.Irql2)
- {
- IoDisconnectInterrupt (pDX->Interrupt2);
- }
-
- TRACE_EVENT (EPC1);
- MmUnlockPages (pDX->RcvInfo.pRcvMdl);
- TRACE_EVENT (EPC2);
- IoFreeMdl (pDX->RcvInfo.pRcvMdl);
- TRACE_EVENT (EPC3);
- MmFreeContiguousMemory (pDX->RcvInfo.pRcvBufArray);
-
- TRACE_EVENT (EPC4);
- MmUnlockPages (pDX->pSendMdl);
- TRACE_EVENT (EPC5);
- IoFreeMdl (pDX->pSendMdl);
- TRACE_EVENT (EPC6);
- pDX->pSendMdl = NULL;
- MmFreeContiguousMemory (pDX->pSendBuf);
- TRACE_EVENT (EPC7);
- pDX->pSendBuf = NULL;
- TRACE_EVENT (EPC8);
-
- // if (pDX->pIRMdl != NULL) /*IRMdl?*/
- // { /*IRMdl?*/
- // MmUnmapLockedPages (pDX->pIR, pDX->pIRMdl); /*IRMdl?*/
- // MmUnlockPages (pDX->pIRMdl); /*IRMdl?*/
- // TRACE_EVENT (EPC9); /*IRMdl?*/
- // IoFreeMdl (pDX->pIRMdl); /*IRMdl?*/
- // TRACE_EVENT (EPC0); /*IRMdl?*/
- // pDX->pIRMdl = NULL; /*IRMdl?*/
- // } /*IRMdl?*/
-
- pDX->pIR = &pDX->OurIR;
-
- pDX->GrabbedResources = 0;
- pDX->DeviceIsOpen = FALSE;
- pDX->pUserEvent = NULL;
- }
- else
- {
- pIrp->IoStatus.Status = STATUS_FILE_CLOSED;
- }
-
- Status = pIrp->IoStatus.Status;
- CompleteIoRequest (pIrp);
-
- TRACE_EVENT (EPC});
- return (Status);
- }
-
-
- /**PROC+**********************************************************************/
- /* */
- /* Name: EntryPointDevIoctl ( */
- /* PDEVICE_OBJECT pDeviceObject */
- /* PIRP pIrp */
- /* ) */
- /* */
- /* Purpose: Main ioctl entry point. */
- /* */
- /* Params: IN DeviceObject: Our device. */
- /* IN PIrp The IRP in question. */
- /* */
- /* Return Value:depends on called routine */
- /* */
- /* Operation: */
- /* */
- /**PROC-**********************************************************************/
-
- NTSTATUS EntryPointDevIoctl (
- PDEVICE_OBJECT pDeviceObject,
- PIRP pIrp
- )
- {
- BOOLean OKToContinue = TRUE;
- PDX pDX = pDeviceObject->DeviceExtension;
- PIO_STACK_LOCATION
- pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
- UCHAR * UserBufferPtr;
- #ifdef IBMSYNC_TRACE
- UCHAR * OriginalTrcPtr = TrcPtr;
- BOOLEAN ResetTrcPtr = FALSE;
- #endif
-
- ASSERT (pDX->DeviceIsOpen); /* open before any Ioctls please */
-
- TRACE_NEWLINE();
- TRACE_EVENT({EPD);
- TRACE_DWORD (pDeviceObject);
- TRACE_DWORD (pDX);
- TRACE_DWORD (pIrp);
- TRACE_DWORD (pIrpSp->IRS_CODE);
- TRACE_ACTION (Op,CAST(pDX->ADAPTERBASE,ULONG) & 0xFFFF);
-
- pDX->IoctlRetStatus = STATUS_SUCCESS;
- pDX->Information = 0L;
- pDX->IoctlCurrentIrp= pIrp;
-
- /***************************************************************************/
- /* The subroutines return the success/fail indication as their return */
- /* value, and additional information in pDX->Information */
- /***************************************************************************/
-
- switch (pIrpSp->IRS_CODE)
- {
-
- // case IoctlCodeSetInterfaceRecord /*IRMdl?*/
- // : IoctlSetInterfaceRecord(pDX); /*IRMdl?*/
- // break; /*IRMdl?*/
-
- case IoctlCodeReadInterfaceRecord /*IRMdl?*/
- : if (pIrpSp->IRS_OUTLEN NE sizeof(IR))
- {
- pDX->IoctlRetStatus = STATUS_INVALID_PARAMETER;
- pDX->Information = IO_ERR_READ_IR_BUFFER_WRONG_SIZE;
- }
- else
- {
- #ifdef IBMSYNC_TRACE
- ResetTrcPtr = TRUE;
- #endif
- UserBufferPtr = MmMapLockedPages
- (pIrp->MdlAddress, KernelMode);
- memcpy (UserBufferPtr, pDX->pIR, sizeof(IR));
- }
- break;
-
- case IoctlCodeSetEvent : if (pIrp->UserEvent NE NULL)
- {
- pDX->pUserEvent = pIrp->UserEvent;
- KeSetEvent (pDX->pUserEvent, 0, FALSE);
- }
- else
- {
- pDX->IoctlRetStatus = STATUS_INVALID_PARAMETER;
- pDX->Information = IO_ERR_SET_EVENT_NO_EVENT;
- }
- break;
-
- case IoctlCodeSetLinkChar : KeSynchronizeExecution
- ( pDX->Interrupt,
- (PKSYNCHRONIZE_ROUTINE)
- IoctlSetLinkConfig,
- (PVOID) pDX
- );
- break;
-
- case IoctlCodeRxFrame : KeSynchronizeExecution
- ( pDX->Interrupt,
- (PKSYNCHRONIZE_ROUTINE) IoctlRxFrame,
- (PVOID) pDX
- );
- break;
-
- case IoctlCodeAbortReceiver : IoctlAbortReceiver (pDX);
- break;
-
- case IoctlCodeGetV24 : KeSynchronizeExecution
- ( pDX->Interrupt,
- (PKSYNCHRONIZE_ROUTINE) GetV24Input,
- (PVOID) pDX
- );
- /* data-> pDX->IR; no return status */
- #ifdef IBMSYNC_TRACE
- {
- static UCHAR LastV24In = 0;
- ResetTrcPtr = CAST(
- pDX->pIR->V24In EQ LastV24In,
- BOOLEAN);
- LastV24In = pDX->pIR->V24In;
- }
- #endif
- break;
-
- case IoctlCodeTxFrame : KeSynchronizeExecution
- ( pDX->Interrupt,
- (PKSYNCHRONIZE_ROUTINE) IoctlTxFrame,
- (PVOID) pDX
- );
- break;
-
- case IoctlCodeAbortTransmit : KeSynchronizeExecution
- ( pDX->Interrupt,
- (PKSYNCHRONIZE_ROUTINE)
- IoctlAbortTransmitter,
- (PVOID) pDX
- );
- break;
-
- case IoctlCodeSetV24 : if (!KeSynchronizeExecution
- ( pDX->Interrupt,
- (PKSYNCHRONIZE_ROUTINE)
- IoctlSetV24Output,
- (PVOID) pDX
- )
- )
- {
- pDX->IoctlRetStatus = STATUS_DATA_ERROR;
- pDX->Information = IO_ERR_HARDWARE_CMD_TIMEOUT_1;
- }
- break;
-
- default:
- // _asm int 3; // break into kernel debugger
- pDX->IoctlRetStatus =
- STATUS_INVALID_DEVICE_REQUEST;
- pDX->Information = IO_ERR_INVALID_IOCTL_CODE;
- }
-
- if (NT_SUCCESS(pDX->IoctlRetStatus))
- {
- // The Ioctl worked OK, but how about 8273 commands - check the
- // timeout flag, which is set by 8273 WAITUNTIL macro. Signal a fatal
- // hardware error if it's set.
-
- if (pDX->HardwareError)
- {
- pDX->IoctlRetStatus = STATUS_DATA_ERROR;
- pDX->Information = IO_ERR_HARDWARE_CMD_TIMEOUT_2;
- }
- }
- else
- {
- TRACE_NTFAILURE(pDX->IoctlRetStatus);
- TRACE_ACTION (Ii,pDX->Information & 0xFFFF);
- }
-
- /***************************************************************************/
- /* Note that at this point a non-zero value of pDX->Information does not */
- /* mean an error - it could be a byte count of info returned in a buffer. */
- /***************************************************************************/
- if (!NT_SUCCESS(pDX->IoctlRetStatus))
- {
- LogDriverError( pDeviceObject,
- pDX->IoctlRetStatus,
- pDX->Information,
- pIrpSp->MajorFunction,
- pIrpSp->IRS_CODE );
- }
-
- pIrp->IoStatus.Status = pDX->IoctlRetStatus;
- pIrp->IoStatus.Information = pDX->Information;
-
- TRACE_EVENT(EPD});
- CompleteIoRequest (pIrp);
-
- #ifdef IBMSYNC_TRACE
- if (ResetTrcPtr)
- TrcPtr = OriginalTrcPtr;
- #endif
-
- return(pDX->IoctlRetStatus);
- }
-
- /**PROC+**********************************************************************/
- /* */
- /* Name: EntryPointISR ( */
- /* PKINTERRUPT pInterrupt */
- /* PVOID Context = pDeviceObject */
- /* ) */
- /* */
- /* Purpose: Handle interrupt. */
- /* */
- /* Params: IN pInterrupt */
- /* IN Context */
- /* */
- /* Return Value:BOOLean: TRUE if device successfully initialised */
- /* */
- /* Operation: */
- /* */
- /* Notes 1. The OS/2 device driver shares interrupts; this version does */
- /* not because the interrupt object needs to be attached to a */
- /* device. I hope we can get away it. */
- /* 2. Return value is meant to indicate some powerfail stuff ... */
- /* not bothering with it for now. */
- /* */
- /**PROC-**********************************************************************/
-
- BOOLEAN EntryPointISR (
- PKINTERRUPT pInterrupt,
- PVOID Context
- )
- {
- PDEVICE_OBJECT pDeviceObject= (PDEVICE_OBJECT) Context;
- PDX pDX = pDeviceObject->DeviceExtension;
- BOOLean OriginalDPCAction = pDX->DPCAction;
- UCHAR Status; /* the 8273 status, not the NT Status*/
- BOOLEAN ReturnValue;
-
- UNREFERENCED_PARAMETER (pInterrupt);
-
- //TRACE_NEWLINE();
- //TRACE_EVENT (<ISR);
-
- ASSERT (pDX != NULL);
- //TRACE_OBJECT(Ad,(*pDX));
-
- ASSERT (pDX->DeviceIsOpen);
-
- if (pDX->AdapterIsClosing ||
- !pDX->DeviceIsOpen)
- {
- // We reset the 8273 but there was an interrupt still pending... ignore it.
- // This is safe because by resetting the 8273 we should have removed the
- // cause of the interrupt.
- return(TRUE);
- }
-
- ReturnValue = CAST ( \
- (IO_IN (pDX->ADAPTERBASE+AR_8273S) & (AS_RXINT|AS_TXINT)) != 0,\
- BOOLEAN \
- ); /* return true if we expected the interrupt */
- do /* while we have an interrupt result avail. */
- {
-
- /*************************************************************************/
- /* To be on the safe side, don't do anything further until the command */
- /* busy bit in the status register has gone off. */
- /*************************************************************************/
- WAITUNTIL (pDX, AS_CMBSY, EQ, 0); /* wait for busy bit to go off */
-
- Status = IO_IN (pDX->ADAPTERBASE+AR_8273S);
- ASSERT (BITSOFF(Status, AS_CRBFF | AS_CPBFF | AS_CMBFF | AS_CMBSY));
-
- if (Status & AS_RXINT) /* receiver action */
- {
- /***********************************************************************/
- /* Note we don't stop DMA on receiver. The design of the buffers has */
- /* taken into account receiving a full 8 frames+RR in DMA mode - so */
- /* that we can take account of the 8273 feature of continuing to */
- /* recieve when in DMA mode. */
- /***********************************************************************/
-
- if (Status & AS_RXIRA)
- {
- /*********************************************************************/
- /* We have a receiver result. Read the result bytes into the */
- /* device extension and after reading, action immediately */
- /*********************************************************************/
- for (pDX->RxResultCount = 0;
- pDX->RxResultCount < (sizeof (pDX->RxResultBuffer) - 1);
- /* last byte never gets filled in ! */
- )
- {
- pDX->RxResultBuffer[pDX->RxResultCount++] =
- IO_IN (pDX->ADAPTERBASE + AR_8273R);
-
- KeStallExecutionProcessor (1L); /* let the chip settle down again*/
- WAITUNTIL(pDX, (AS_RXIRA | AS_RXINT), NE, AS_RXINT);
-
- TRACE_DATABYTE (RxR, pDX->RxResultBuffer[pDX->RxResultCount]);
-
- /*******************************************************************/
- /* either the INT bit went off or IRA went on */
- /* If INT went off, ignore the rest - even if IRA went on */
- /* (shouldn't have) */
- /*******************************************************************/
-
- if (BITSOFF(LastWaitUntilStatus, AS_RXINT))
- break;
- }
-
- /*********************************************************************/
- /* We do nothing if receiver is not active. This sitn. arises when */
- /* */
- /* - we prepare to disable the recver (start into synchronized execn)*/
- /* - a result becomes available */
- /* - the synchronized execution carries on and disables the receiver */
- /* */
- /* This only arises when we are in DMA mode - for SDLC. (For PIO, */
- /* receiver kept active). Make life simple by ignoring result */
- /* otherwise we get FSM's knickers in a twist. */
- /*********************************************************************/
-
- if (pDX->RxFSMCurState EQ RxFSMStateReady)
- {
- while (pDX->RxResultCount > 0)
- {
- /*****************************************************************/
- /* There will either be one or two result groups set. The case */
- /* of two groups arises when one result has occurred but not */
- /* been read by the time another result comes in. */
- /* */
- /* The second result is only one byte so we special case this to */
- /* make it easier get the rxresults down to the start again. */
- /*****************************************************************/
-
- if (pDX->RxResultBuffer[0] EQ ARxR_A1OK ||/* A1/A2 match, rcv OK */
- pDX->RxResultBuffer[0] EQ ARxR_A2OK)
- {
- RxFSMEvent (pDX, RxFSMInputGoodReceive);
- pDX->RxResultBuffer[0] = pDX->RxResultBuffer[5];
- pDX->RxResultCount -= 5;
- }
- else
- {
- RxFSMEvent (pDX, RxFSMInputReceiverError);
- pDX->RxResultBuffer[0] = pDX->RxResultBuffer[1];
- pDX->RxResultCount -= 1;
- }
- }
- }
- }
- else
- {
- /*********************************************************************/
- /* IRA not set - no result available, must be for received character */
- /* */
- /* Not that neither here nor below in tx do check for overrunning */
- /* the buffer - we just believe 8273 is OK (and it hasn't failed in */
- /* this area yet. ASSERTions to guard against buffer overruns */
- /* should be done in completion code. */
- /*********************************************************************/
- ASSERT (BITSOFF(pDX->GrabbedResources, GRABBEDRESOURCE_GOTDMA));
- /* must be PIO then */
- *(pDX->pRxPIOData++) = IO_IN (pDX->ADAPTERBASE+AR_8273D);
-
- // TRACE_DATABYTE(RxD, *(pDX->pRxPIOData-1));
- }
- }
-
- if (Status & AS_TXINT) /* transmitter action */
- {
-
- if (Status & AS_TXIRA)
- {
- /*********************************************************************/
- /* We have a transmitter result. Read the result bytes into the */
- /* device extension and after reading, request a DPC. */
- /* */
- /* The DPCAction tells the DPC why it is being called */
- /* */
- /* This implementation also assumes that only one transmitter result */
- /* will be outstanding at any one time, so there is only one */
- /* TxResult byte. */
- /*********************************************************************/
-
- pDX->TxResult = IO_IN (pDX->ADAPTERBASE + AR_8273T);
- TRACE_DATABYTE (TxR, pDX->TxResult);
- if (pDX->TxResult EQ ATxR_TxCompleteOK)
- {
- TxFSMEvent (pDX, TxFSMInputEOTx);
- }
- else if (pDX->TxResult EQ ATxR_ErrTxFrameAborted)
- {
- TxFSMEvent (pDX, TxFSMInputAbortd);
- }
- else
- {
- TxFSMEvent (pDX, TxFSMInputEOTx_Err);
- }
- }
- else
- {
- /*********************************************************************/
- /* IRA not set - no result available, must be to tx next character */
- /*********************************************************************/
- ASSERT (BITSOFF(pDX->GrabbedResources, GRABBEDRESOURCE_GOTDMA));
- /* must be PIO then */
- // TRACE_DATABYTE (TxD, *pDX->pTxPIOData);
- IO_OUT(pDX->ADAPTERBASE+AR_8273D, *(pDX->pTxPIOData++));
- }
- }
- Status = IO_IN (pDX->ADAPTERBASE + AR_8273S);
- }
- while (Status & (AS_TXINT|AS_RXINT));
-
- if (!OriginalDPCAction && /* on entry, no dpc actions */
- pDX->DPCAction) /* but on exit, we have DPC actions */
- {
- IoRequestDpc (pDeviceObject, NULL, NULL); /* DPC will pulse event for us */
- }
-
- //XTRACE_EVENT (ISR>);
- return(ReturnValue);
- }
-
- /**PROC+**********************************************************************/
- /* */
- /* Name: EntryPointOpen ( */
- /* PDEVICE_OBJECT pDeviceObject */
- /* PIRP pIrp */
- /* ) */
- /* */
- /* Purpose: Initialise the next device (from GetDriverSpec) */
- /* */
- /* Params: IN DeviceObject: Our device. */
- /* IN PIrp The IRP in question. */
- /* */
- /* Return Value:BOOLean: TRUE if device successfully initialised */
- /* */
- /* Operation: */
- /* 1. Copy over pre-initialised data sequences */
- /* */
- /* 2. Init for NT */
- /* - allocate transmit and receive buffers DMA-able */
- /* - DeviceObject */
- /* - DO_DIRECT_IO */
- /* - IoInitializeDpcRequest */
- /* - ConnectInterrupt */
- /* */
- /* 3. Init our own data */
- /* - DeviceIsOpen = FALSE */
- /* */
- /**PROC-**********************************************************************/
-
- NTSTATUS EntryPointOpen (
- PDEVICE_OBJECT pDeviceObject,
- PIRP pIrp
- )
- {
- //ULONG AddressSpace;
- KAFFINITY Affinity;
- int Information = 0;
- KIRQL InterruptLevel;
- CCHAR InterruptVector;
- BOOLean OKToContinue = TRUE;
- PDX pDX = pDeviceObject->DeviceExtension;
- NTSTATUS Status = STATUS_UNSUCCESSFUL;
- int WindDownLevel= 0;
-
- ASSERT (!pDX->DeviceIsOpen); /* device defined as exclusive usage!*/
-
- TRACE_NEWLINE();
- TRACE_EVENT({EPO);
- TRACE_ACTION (Op,CAST(pDX->ADAPTERBASE, ULONG) & 0xFFFF);
-
- pIrp->IoStatus.Information = 0L;
-
- pDX->GrabbedResources = 0; /* clear the list of resources */
-
-
-
- if (InterfaceType == MicroChannel)
- {
- if (!pDX->ConfigData.MPAAAdapterIdentifier)
- {
- OKToContinue = FALSE;
- Status = STATUS_INSUFFICIENT_RESOURCES;
- Information = IO_ERR_NEEDS_ISA_BUS;
- TRACE_EVENT (OcWb);
- }
- }
- else
- {
- if (pDX->ConfigData.MPAAAdapterIdentifier)
- {
- OKToContinue = FALSE;
- Status = STATUS_INSUFFICIENT_RESOURCES;
- Information = IO_ERR_NEEDS_MCA_BUS;
- TRACE_EVENT (OcWb);
- }
- }
-
-
- //
- // Map the memory for the control registers for the parallel device
- // into virtual memory. This code needs to be activated when moving to
- // a platform with memory-mapped I/O.
- //
-
- // AddressSpace = pDX->ConfigData.AddressSpace;
- // CardAddress = HalTranslateBusAddress(
- // InterfaceType,
- // pDX->ConfigData->BusNumber,
- // pDX->ConfigData->AdapterBaseAddress,
- // &AddressSpace
- // );
- //
- // if (!AddressSpace)
- // {
- // ParDeviceObject->UnMapRegisters = TRUE;
- // ParDeviceObject->DeviceRegisters = MmMapIoSpace(
- // CardAddress,
- // PARALLEL_REGISTER_LENGTH,
- // FALSE
- // );
- //
- // } else {
- //
- // ParDeviceObject->UnMapRegisters = FALSE;
- // ParDeviceObject->DeviceRegisters = (PVOID)CardAddress.LowPart;
- //
- // }
- //
- // if (!ParDeviceObject->DeviceRegisters) {
- //
- // DbgPrint("Couldn't map the device registers.\n");
- // IoDeleteDevice(DeviceObject);
- // return STATUS_NONE_MAPPED;
- //
- // }
-
-
- /***************************************************************************/
- /* 1. NT-related device initialisation */
- /***************************************************************************/
-
- if (OKToContinue)
- {
- InterruptVector = HalGetInterruptVector(
- InterfaceType,
- pDX->ConfigData.BusNumber,
- pDX->ConfigData.Irql,
- pDX->ConfigData.Vector,
- &InterruptLevel,
- &Affinity
- );
-
- Status = IoConnectInterrupt (
- &pDX->Interrupt,
- EntryPointISR,
- pDeviceObject,
- NULL,
- InterruptVector,
- InterruptLevel, /* interrupt IRQ level */
- InterruptLevel, /* synchronize IRQ level */
- pDX->ConfigData.InterruptMode,
- pDX->ConfigData.Shareable,
- Affinity, /* processor number */
- FALSE /* no save floating pt contxt*/
- );
-
- if (!NT_SUCCESS(Status))
- {
- OKToContinue = FALSE;
- Status = STATUS_INSUFFICIENT_RESOURCES;
- Information = IO_ERR_CANT_CONNECT_INTERRUPT_1;
- TRACE_EVENT (OcCi);
- }
- }
-
- if (OKToContinue)
- {
- WindDownLevel = 15;
-
- if (pDX->ConfigData.Irql2)
- {
- /***********************************************************************/
- /* A second interrupt is required */
- /***********************************************************************/
- ASSERT (pDX->ConfigData.FlavourName[0] EQ 'S');
- /* only the SDLC card is so dumb */
-
-
- if (OKToContinue)
- {
- InterruptVector = HalGetInterruptVector(
- InterfaceType,
- pDX->ConfigData.BusNumber,
- pDX->ConfigData.Irql2,
- pDX->ConfigData.Vector2,
- &InterruptLevel,
- &Affinity
- );
-
- Status = IoConnectInterrupt (
- &pDX->Interrupt2,
- EntryPointRogueInterrupt,
- pDeviceObject,
- NULL,
- InterruptVector,
- InterruptLevel, /* interrupt IRQ level */
- InterruptLevel, /* synchronize IRQ level */
- pDX->ConfigData.InterruptMode2,
- pDX->ConfigData.Shareable2,
- 1, /* processor number */
- FALSE /* no save floating pt contxt*/
- );
-
- if (!NT_SUCCESS(Status))
- {
- OKToContinue = FALSE;
- Status = STATUS_INSUFFICIENT_RESOURCES;
- Information = IO_ERR_CANT_CONNECT_INTERRUPT_2;
- TRACE_EVENT (OcCi);
- }
- }
- }
- }
-
- /***************************************************************************/
- /* 2. Buffer allocation and init */
- /***************************************************************************/
-
- if (OKToContinue)
- {
- WindDownLevel = 20;
- OKToContinue = AllocateDMAMemory (sizeof(RCVBUFARRAY),
- (PVOID *)&pDX->RcvInfo.pRcvBufArray,
- &pDX->RcvInfo.pRcvMdl,
- &pDX->RcvInfo.RcvBufPhysAddr,
- &Information
- );
- if (!OKToContinue)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- // Information set in above call to AllocateDmaMemory
- }
- }
- if (OKToContinue)
- {
- WindDownLevel = 30;
-
- RCVINFO_INIT(pDX);
-
- pDX->RxFSMCurState = RxFSMStateIdle;
- OKToContinue = AllocateDMAMemory (SENDBUF_SIZE,
- (PVOID *)&pDX->pSendBuf,
- &pDX->pSendMdl,
- &pDX->SendBufPhysAddr,
- &Information
- );
- if (!OKToContinue)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- // Information set in above call to AllocateDmaMemory
- }
- }
- if (OKToContinue)
- {
- WindDownLevel = 40;
- pDX->TxFSMCurState = TxFSMStateIdle;
- pDX->TxConsecutiveUnderrunCount = 0;
-
- COPY8273CMD (pDX, CmdStringReadPortA );
- COPY8273CMD (pDX, CmdStringResetOpMode );
- COPY8273CMD (pDX, CmdStringResetSerialIOMode);
- COPY8273CMD (pDX, CmdStringSetOpMode );
- COPY8273CMD (pDX, CmdStringSetSerialIOMode );
- COPY8273CMD (pDX, CmdStringDataTransferMode );
- COPY8273CMD (pDX, CmdStringResetPortB );
- COPY8273CMD (pDX, CmdStringSetPortB );
- COPY8273CMD (pDX, CmdStringReceive );
- COPY8273CMD (pDX, CmdStringTransmit );
- COPY8273CMD (pDX, CmdStringAbortTransmit );
- COPY8273CMD (pDX, CmdStringDisableReceiver );
-
- pDX->pIR = &pDX->OurIR; /* use dummy IR for now until real */
-
- pDX->pIR->V24In = 0;
- pDX->pIR->V24Out = 0;
- pDX->pIR->RxFrameCount= 0;
- pDX->pIR->TxMaxFrSizeNow = INIT_MAXFRSIZENOW;
-
- // pDX->pIRMdl = NULL; /*IRMdl?*/
-
- pDX->pUserEvent = NULL; /* null until Ioctl: SetEvent */
- }
-
- /***************************************************************************/
- /* SDLC device initialisation */
- /***************************************************************************/
- if (OKToContinue)
- {
- if (!KeSynchronizeExecution(pDX->Interrupt,
- SynchEntryPointOpen,
- (PVOID)pDX))
- {
- Status = STATUS_DATA_ERROR;
- Information = pDX->Information;
- OKToContinue = FALSE;
- }
- }
-
- if (OKToContinue)
- {
- if (pDX->HardwareError)
- {
- Status = STATUS_DATA_ERROR;
- Information = IO_ERR_HARDWARE_CMD_TIMEOUT_3;
- OKToContinue = FALSE;
- }
- }
-
- if (!OKToContinue)
- {
- TRACE_ACTION (Wl, WindDownLevel & 0xFFFF);
-
- if (WindDownLevel >= 15)
- IoDisconnectInterrupt( pDX->Interrupt);
-
- if (pDX->ConfigData.Irql2)
- {
- if (WindDownLevel >= 20)
- IoDisconnectInterrupt( pDX->Interrupt2);
- }
-
- if (WindDownLevel >= 30)
- {
- MmUnlockPages (pDX->RcvInfo.pRcvMdl);
- IoFreeMdl (pDX->RcvInfo.pRcvMdl);
- MmFreeContiguousMemory (pDX->RcvInfo.pRcvBufArray);
- }
- if (WindDownLevel >= 40)
- {
- MmUnlockPages (pDX->pSendMdl);
- IoFreeMdl (pDX->pSendMdl);
- pDX->pSendMdl = NULL;
- MmFreeContiguousMemory (pDX->pSendBuf);
- pDX->pSendBuf = NULL;
- }
-
- LogDriverError( pDeviceObject,
- Status,
- Information,
- IoGetCurrentIrpStackLocation(pIrp)->MajorFunction,
- 0L );
- }
-
- pIrp->IoStatus.Status = Status;
- pIrp->IoStatus.Information = Information;
- if (Status EQ STATUS_SUCCESS)
- {
- pDX->DeviceIsOpen = TRUE;
- }
-
- TRACE_EVENT(EPO});
- TRACE_NTFAILURE (Status);
-
- CompleteIoRequest (pIrp);
- return (Status);
- }
-
- /*****************************************************************************/
- /* */
- /* Name EntryPointRogueInterrupt */
- /* */
- /* Purpose Mode Status ISR. */
- /* */
- /* Should never be called!!! This ISR is used to handle int4 */
- /* on SDLC cards (modem status and timers). Since the int is */
- /* explicitly masked off in adapter set-up, it is a severe err */
- /* if we actually get one! */
- /* */
- /* */
- /* Params IN None */
- /* */
- /* OUT DLC appl hardware status updated. */
- /* */
- /*****************************************************************************/
-
- BOOLEAN EntryPointRogueInterrupt (
- PKINTERRUPT pInterrupt,
- PVOID Context
- )
- {
- PDEVICE_OBJECT pDeviceObject= (PDEVICE_OBJECT) Context;
- PDX pDX = pDeviceObject->DeviceExtension;
-
- UNREFERENCED_PARAMETER (pInterrupt);
-
- TRACE_EVENT ({EP?);
-
- /***************************************************************************/
- /* Update hardware error status and trigger an event for Link process via */
- /* DPC */
- /***************************************************************************/
-
- pDX->pIR->StatusArray[SA_HardwareError]++;
- pDX->pIR->StatusCount++;
-
- pDX->DPCAction |= DPC_ACTION_PULSE;
- IoRequestDpc (pDeviceObject, NULL, NULL); /* DPC will pulse event for us */
-
- /***************************************************************************/
- /* Reset the modem status logic and turn the 8273 off - it is being too */
- /* disruptive to keep active! */
- /***************************************************************************/
-
- WR_N_DELAY (pDX->ADAPTERBASE + AR_8255B, A55_ResetModemStatusCh+
- A55_Reset8273Off);
- WR_N_DELAY (pDX->ADAPTERBASE + AR_8255B, A55_Reset8273Off);
-
- TRACE_EVENT (EP?});
- return(FALSE); /* interrupt wasn't expected */
- }
-
- /**PROC+**********************************************************************/
- /* */
- /* Name: EntryPointUnload ( */
- /* PDRIVER_OBJECT pDriverObject */
- /* ) */
- /* */
- /* Purpose: Unload the device - don't need to do anything? */
- /* */
- /* Params: IN DriverObject: Our device. */
- /* */
- /* Return Value:None */
- /* */
- /* Operation: */
- /* */
- /**PROC-**********************************************************************/
-
- VOID
- EntryPointUnload (
- IN PDRIVER_OBJECT pDriverObject
- )
- {
- IoDeleteDevice( pDriverObject->DeviceObject );
- return;
- }
-
- /**PROC+**********************************************************************/
- /* */
- /* Name GetInterfaceType ( */
- /* PDRIVER_OBJECT pDriverObject */
- /* ) */
- /* */
- /* Purpose Hide the vagaries of roasting squirrels */
- /* */
- /* Return Value BOOLean : TRUE if InterfaceType (global) set up OK */
- /* */
- /**PROC-**********************************************************************/
-
- BOOLean GetInterfaceType (
- IN PDRIVER_OBJECT pDriverObject
- )
- {
-
- PUNICODE_STRING RegistryPath = pDriverObject->HardwareDatabase;
- PRTL_QUERY_REGISTRY_TABLE Parameters = NULL;
- UNICODE_STRING ParametersPath;
- OBJECT_ATTRIBUTES ParametersAttributes;
- HANDLE ParametersKey;
- UNICODE_STRING Identifier;
- UNICODE_STRING MCAString;
- NTSTATUS Status = STATUS_SUCCESS;
- ULONG Information;
-
-
- TRACE_EVENT([GIT);
-
- Identifier.Buffer = NULL;
-
- /***************************************************************************/
- /* Set up the Registry path to check if \EisaAdapter\0 key exists. */
- /***************************************************************************/
-
- RtlInitUnicodeString (&ParametersPath, NULL);
-
- ParametersPath.MaximumLength = RegistryPath->Length +
- sizeof(L"\\MultifunctionAdapter\\0") +
- 4;
-
- ParametersPath.Buffer = ExAllocatePool(
- PagedPool,
- ParametersPath.MaximumLength
- );
-
- if (!ParametersPath.Buffer)
- {
- TRACE_EVENT (GIT1);
- Information = IO_ERR_GET_IF_TYPE_1;
- Status = STATUS_UNSUCCESSFUL;
- }
- else
- {
-
- RtlZeroMemory(
- ParametersPath.Buffer,
- ParametersPath.MaximumLength
- );
- RtlAppendUnicodeStringToString(
- &ParametersPath,
- RegistryPath
- );
- RtlAppendUnicodeToString(
- &ParametersPath,
- L"\\EisaAdapter\\0"
- );
-
- /*************************************************************************/
- /* Attempt to open the key - if we can this is Eisa bus. */
- /*************************************************************************/
-
- InitializeObjectAttributes(
- &ParametersAttributes,
- &ParametersPath,
- OBJ_CASE_INSENSITIVE,
- NULL,
- NULL
- );
-
- if (NT_SUCCESS(ZwOpenKey(
- &ParametersKey,
- MAXIMUM_ALLOWED,
- &ParametersAttributes
- )))
- {
- InterfaceType = Eisa;
- TRACE_EVENT (Eisa);
- DEBUG_PRINT (("IBMSYNC: Bus type is Eisa\n"));
- TRACE_EVENT(GIT]);
-
- ExFreePool(ParametersPath.Buffer);
- return(TRUE);
- }
- }
-
-
-
- if (NT_SUCCESS(Status))
- {
- /*************************************************************************/
- /* Reset the Registry path to check for Identifier string in key */
- /* \MultifunctionAdapter\0. */
- /*************************************************************************/
-
- RtlZeroMemory(
- ParametersPath.Buffer,
- ParametersPath.MaximumLength
- );
-
- ParametersPath.Length = 0;
-
- RtlAppendUnicodeStringToString(
- &ParametersPath,
- RegistryPath
- );
- RtlAppendUnicodeToString(
- &ParametersPath,
- L"\\MultifunctionAdapter\\0"
- );
-
- /*************************************************************************/
- /* Allocate the Rtl query table. */
- /*************************************************************************/
-
- Parameters = ExAllocatePool(
- PagedPool,
- sizeof(RTL_QUERY_REGISTRY_TABLE) * 2
- );
-
- if (!Parameters)
- {
- TRACE_EVENT (GIT2);
- Information = IO_ERR_GET_IF_TYPE_2;
- Status = STATUS_UNSUCCESSFUL;
- }
- else
- {
-
- /***********************************************************************/
- /* Allocate memory to except Identifier type. */
- /***********************************************************************/
- RtlInitUnicodeString (&Identifier, NULL);
-
- Identifier.MaximumLength = 20; /* Room for "EISA", "MCA" or "ISA" */
-
- Identifier.Buffer = ExAllocatePool(
- PagedPool,
- Identifier.MaximumLength
- );
-
- if (!Identifier.Buffer)
- {
- TRACE_EVENT (GIT3);
- Information = IO_ERR_GET_IF_TYPE_3;
- Status = STATUS_UNSUCCESSFUL;
- }
- else
- {
- /*********************************************************************/
- /* OK now finally pick up the Bus Type (Identifier) string from the */
- /* Registry. */
- /*********************************************************************/
-
- RtlZeroMemory(
- Parameters,
- sizeof(RTL_QUERY_REGISTRY_TABLE) * 2
- );
-
- Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
- Parameters[0].Name = L"Identifier";
- Parameters[0].EntryContext = &Identifier;
- Parameters[0].DefaultType = REG_SZ;
- Parameters[0].DefaultData = L"None";
- Parameters[0].DefaultLength = 8;
-
-
- if (!NT_SUCCESS(RtlQueryRegistryValues(
- RTL_REGISTRY_ABSOLUTE,
- ParametersPath.Buffer,
- Parameters,
- NULL,
- NULL
- )))
- {
- TRACE_EVENT (GIT4);
- Information = IO_ERR_GET_IF_TYPE_4;
- Status = STATUS_UNSUCCESSFUL;
- }
- else
- {
- RtlInitUnicodeString (&MCAString, L"MCA");
-
- if (!RtlCompareUnicodeString(&MCAString, &Identifier, TRUE))
- {
- InterfaceType = MicroChannel;
- TRACE_EVENT (MCA );
- DEBUG_PRINT (("IBMSYNC: Bus type is MicroChannel\n"));
- }
- else
- {
- InterfaceType = Isa;
- TRACE_EVENT (ISA );
- DEBUG_PRINT (("IBMSYNC: Bus type is Isa\n"));
- }
- }
- }
- }
- }
-
- /***************************************************************************/
- /* Free any allocated memory before returning. */
- /***************************************************************************/
-
- if (ParametersPath.Buffer)
- ExFreePool(ParametersPath.Buffer);
-
- if (Identifier.Buffer)
- ExFreePool(Identifier.Buffer);
-
- if (Parameters)
- ExFreePool(Parameters);
-
- /***************************************************************************/
- /* OK, so which Device Object do we use here? The driver can have */
- /* multiple Device Objects set up; also the reading of the bus type from */
- /* the Registry is done just once (i.e not on a per-Device basis). */
- /* */
- /* We use the last one hanging from the list - to get to this stage we */
- /* must have at least one. */
- /***************************************************************************/
- if (!NT_SUCCESS(Status))
- {
- LogDriverError( pDriverObject->DeviceObject,
- Status,
- Information,
- 0L,
- 0L );
- }
-
-
- TRACE_EVENT(GIT]);
-
- return(Status == STATUS_SUCCESS);
-
- }
-
- /**PROC+**********************************************************************/
- /* */
- /* Name GetDriverSpec ( */
- /* CHAR *DriverName, */
- /* PCONFIGDATA *pConfigData */
- /* ); */
- /* */
- /* Purpose Hide the vagaries of initialising */
- /* */
- /* Params OUT DriverName: e.g. COM$DL01, null-terminated, 8+1 chars */
- /* OUT FlavourName: e.g. SDLC or MPAA1, null-terminated, 5+1 chars */
- /* OUT pConfigData: the config data record to be set up */
- /* (a pointer is passed, not the structure itself) */
- /* */
- /* Return Value BOOLean: TRUE if there was another driver spec to get */
- /* */
- /* Operation At a guess, this will */
- /* - enumerate all SDLC device drivers in CFG Reg. */
- /* (RegEnumKeyEx(Key:Master\Software\CS\Drivers) */
- /* or CS\SDLCDrivers? */
- /* - if necessary, check the driver is an SDLC one */
- /* - read config info to extract device name and type */
- /* - get other config data into ConfigData */
- /* */
- /* Notes Uses static variables to indicate position in config; so */
- /* no indication from user that this is first time is required. */
- /* */
- /* Called only during DriverEntry. */
- /* */
- /* The fact that a driver/flavour is returned does not imply */
- /* the device is usable - this must be checked by calling */
- /* DeviceInit. */
- /* */
- /**PROC-**********************************************************************/
-
- BOOLean GetDriverSpec (CHAR *DeviceName,
- PCONFIGDATA *pConfigData
- )
- {
- static int DeviceNumber = 0;
-
- /* very temporary - until we find out how to read config registry. */
-
- if (++DeviceNumber > AT_COUNT)
- return (FALSE);
-
- strcpy (DeviceName, "\\Device\\COMDL$00");
- DeviceName[strlen(DeviceName)-1] = ((char) ('0' + DeviceNumber));
- *pConfigData = &ConfigData[DeviceNumber-1];
- return(TRUE);
-
- }
-
- /**PROC+**********************************************************************/
- /* */
- /* Name GetV24Input ( */
- /* PDX pDX */
- /* ); */
- /* */
- /* Purpose Interpret pin inputs as presented by SDLC cards and stuff */
- /* into IR fields */
- /* */
- /* Params IN pDX - the device extension */
- /* */
- /* Return Value None */
- /* */
- /**PROC-**********************************************************************/
-
- void GetV24Input (PDX pDX)
- {
- UCHAR o;
-
- TRACE_EVENT (<GV2);
-
- pDX->pIR->V24In = 0; /* reset IR value. */
-
- /***************************************************************************/
- /* Reset the 'modem status changed' bit because after we read this */
- /* hasn't changed */
- /***************************************************************************/
-
- WR_N_DELAY (pDX->ADAPTERBASE+AR_8255B,
- IO_IN (pDX->ADAPTERBASE+AR_8255B) & CAST(~8,UCHAR));
- /* 8 = modem status changed */
-
- /***************************************************************************/
- /* Read the 8255 Port C settings to get the current state of Test */
- /***************************************************************************/
-
- if (BITSOFF(IO_IN (pDX->ADAPTERBASE+AR_8255C), 0x40))
- {
- pDX->pIR->V24In |= IR_IV24Test; /* &40 = 0 => Test is Active */
- }
-
- /***************************************************************************/
- /* Read the 8255 Port A settings. */
- /***************************************************************************/
-
- o = (IO_IN (pDX->ADAPTERBASE+AR_8255A));
-
- if (!(o&1)) /* &1=0 implies RI on at interface */
- {
- pDX->pIR->V24In |= IR_IV24RI;
- }
- if (!(o&2)) /* &2=0 implies DCD on at interface */
- {
- pDX->pIR->V24In |= IR_IV24DCD;
- }
- if (!(o&8)) /* &8=0 implies CTS on at interface */
- {
- pDX->pIR->V24In |= IR_IV24CTS;
- }
-
- /***************************************************************************/
- /* Used to do the 8273 Port A Reading to get hold of DSR here. There are */
- /* slight problems with doing that */
- /* - the 8273 can get upset if given three commands at once (e.g Rx, Tx */
- /* AND CmdStringReadPortA) (this is surmountable) */
- /***************************************************************************/
-
- if (pDX->RxFSMCurState NE RxFSMStateReady || /* not receiving ... or */
- pDX->TxFSMCurState EQ TxFSMStateIdle) /* transmitter idle */
- {
- pDX->LastPortA = Write8273Cmd (pDX, pDX->CmdStringReadPortA);
- }
-
- if (pDX->LastPortA & 4) /* is the DSR bit set??? */
- {
- pDX->pIR->V24In |= IR_IV24DSR;
- }
- TRACE_EVENT (GV2>);
-
- }
-
- /*****************************************************************************/
- /* */
- /* Name InitialiseAdapter */
- /* */
- /* Purpose Initialises and checks the hardware for a link. */
- /* */
- /* Params IN pDX, plus Synchronised, plus interrupt routines set up */
- /* */
- /* Return Value False on failure, plus SynchInformation set */
- /* */
- /*****************************************************************************/
-
- BOOLean InitialiseAdapter (PDX pDX)
- {
- BOOLean rc;
-
- TRACE_EVENT (<InA);
-
- /***************************************************************************/
- /* Resetting the adapter and check that it accepts commands. Then call */
- /* the link options handler to set it up in the default mode. */
- /***************************************************************************/
-
- AdapterReset(pDX);
-
- /***************************************************************************/
- /* The adapter is now primed and ready to go. Set up a default link */
- /* characteristics configuration and call link set-up. The link set-up */
- /* routine SetLinkConfig returns carry set if problems occur. */
- /***************************************************************************/
-
- pDX->LinkMaxFrameSize = DEFAULT_FRAME_SIZE;
- pDX->LinkOptionsByte = 0;
-
- if (SetLinkConfig(pDX))
- {
- SetV24Output (pDX);
- GetV24Input (pDX);
- rc = TRUE; /* OK return code */
- }
- else
- {
- SynchTerminateAdapter(pDX);
- pDX->Information = IO_ERR_HARDWARE_INIT_FAILURE;
- rc = FALSE;
- TRACE_EVENT (HwIF);
- TRACE_RC(rc);
- }
-
- TRACE_EVENT (InA>);
- return (rc);
- }
-
- /*****************************************************************************/
- /* */
- /* Name IoctlAbortReceiver */
- /* */
- /* Purpose Abort Receiver IOCtl Processor */
- /* */
- /* Params IN pDX */
- /* */
- /* OUT Requested function is processed. No return code */
- /* */
- /*****************************************************************************/
-
- void IoctlAbortReceiver (PDX pDX)
- {
- TRACE_EVENT ([IAR);
- RxFSMEvent (pDX, RxFSMInputStop); /* terminate with extreme prejudice */
-
- /***************************************************************************/
- /* Then reset the buffer pointers, discarding all the data in the receive */
- /* buffer. */
- /***************************************************************************/
-
- RCVINFO_INIT(pDX);
- TRACE_EVENT (IAR]);
- }
-
- /*****************************************************************************/
- /* */
- /* Name IoctlAbortTransmitter */
- /* */
- /* Purpose Abort Transmitter IOCtl Processor */
- /* */
- /* Params IN pDX */
- /* */
- /* OUT None */
- /* */
- /*****************************************************************************/
-
- void IoctlAbortTransmitter (PDX pDX)
- {
- TRACE_EVENT ([IAT);
- /***************************************************************************/
- /* First stop the transmitter (if it is running). */
- /***************************************************************************/
-
- TxFSMEvent (pDX, TxFSMInputStop);
-
- /*0025****************************************************************/
- /*0025* Clear the underrun count. */
- /*0025****************************************************************/
-
- pDX->TxConsecutiveUnderrunCount = 0;
-
- /***************************************************************************/
- /* Then reset the transmit buffer pointers, discarding all the data in the */
- /* buffer. */
- /***************************************************************************/
-
- pDX->TxNextToTransmit = 0;
- pDX->TxNextToBuffer = 0;
-
- /*0025**********************************************************************/
- /*0025* Set up the maximum buffer size and the interface record */
- /*0025* 'initialisation' buffer size. */
- /*0025**********************************************************************/
-
- pDX->TxStartUnusedArea = SENDBUF_SIZE;
- pDX->pIR->TxMaxFrSizeNow = INIT_MAXFRSIZENOW;
- XTRACE_ACTION (Tz, pDX->pIR->TxMaxFrSizeNow);
- TRACE_EVENT (IAT]);
- }
-
- /*****************************************************************************/
- /* */
- /* Name IoctlSetInterfaceRecord */
- /* */
- /* Purpose / *IRMdl?* / Obsolete */
- /* Set Interface Record Address handler */
- /* */
- /* Params IN pDX */
- /* Implicit: the input buffer address (IrpSp->InputBufferLength */
- /* + Irp->AssociatedIrp->SystemBuffer) describes the */
- /* interface record */
- /* */
- /* OUT None */
- /* */
- /* Side Effect pDX->IoctlRetStatus & Information */
- /* */
- /* Return Value void */
- /* */
- /*****************************************************************************/
-
- //void IoctlSetInterfaceRecord (PDX pDX)
- //{
- // PIRP pIrp = pDX->IoctlCurrentIrp;
- // PIO_STACK_LOCATION
- // pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
- //
- // TRACE_EVENT ([IoI);
- //
- // /***************************************************************************/
- // /* The old story: allocate an MDL, probe and lock, map to system address */
- // /* space and save the resulting system address in pIR. */
- // /* */
- // /* Free up Mdl and unlock pages if this is a subsequent call. */
- // /***************************************************************************/
- //
- // if (pDX->pIRMdl != NULL)
- // {
- // /*************************************************************************/
- // /* Protect ourselves from bozo users calling IoctlSetInterfaceRecrd twice*/
- // /*************************************************************************/
- // ASSERT (pDX->pIR != NULL);
- // MmUnmapLockedPages (pDX->pIR, pDX->pIRMdl); /*IRMdl?*/
- // IoFreeMdl (pDX->pIRMdl);
- // }
- //
- // pDX->pIRMdl = IoAllocateMdl(pIrp->AssociatedIrp.SystemBuffer,
- // pIrpSp->IRS_INLEN,
- // sizeof (IRP),
- // FALSE, /* this is not a secondary buffer */
- // FALSE, /* no charge to quota */
- // (PIRP)NULL/* not attached to IRP */
- // );
- //
- // if (pDX->pIRMdl NE NULL) /* We could do the mapping */
- // {
- // MmProbeAndLockPages (pDX->pIRMdl, KernelMode, IoModifyAccess);
- //
- // pDX->pIR = MmMapLockedPages(pDX->pIRMdl, KernelMode);
- // pDX->pIR->RxFrameCount = 0;
- // pDX->pIR->TxMaxFrSizeNow = INIT_MAXFRSIZENOW;
- // pDX->pIR->StatusCount = 0;
- // pDX->pIR->V24In = 0;
- // pDX->pIR->V24Out = 0;
- // RtlZeroMemory (pDX->pIR->StatusArray, sizeof (pDX->pIR->StatusArray));
- // TRACE_EVENT (pIR_);
- // TRACE_DWORD (pDX->pIR);
- // XTRACE_ACTION (Tz, pDX->pIR->TxMaxFrSizeNow);
- // }
- // else
- // {
- // pDX->pIR = NULL;
- // pDX->Information = INFO_CANT_ALLOCATE_MDL;
- // pDX->IoctlRetStatus = STATUS_INSUFFICIENT_RESOURCES;
- // }
- // TRACE_EVENT (IoI]);
- //}
-
- /*****************************************************************************/
- /* */
- /* Name IoctlSetLinkConfig */
- /* */
- /* Purpose Set Link Characteristics IOCtl Processor */
- /* */
- /* Sets the link configuration on the basis of the supplied */
- /* parameters. This routine also aborts any outstanding */
- /* activity in case there is a conflict between old and new */
- /* parameters (switching to DMA for instance!). */
- /* */
- /* Params IN pDX */
- /* */
- /* OUT */
- /* */
- /* Side Effect pDX->IoctlRetStatus & Information */
- /* */
- /*****************************************************************************/
-
- BOOLean IoctlSetLinkConfig (PDX pDX)
- {
- PIRP pIrp = pDX->IoctlCurrentIrp;
- PIO_STACK_LOCATION
- pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
- SLPARMS *pParms = pIrp->AssociatedIrp.SystemBuffer;
- UCHAR NewOpt = pParms->SLLinkOptionsByte; /* easier to type */
- BOOLean rc = FALSE; /* assume the worst! */
-
- TRACE_EVENT ([IoC);
-
- /***************************************************************************/
- /* Issue the abort calls to get Tx and Rx synchronised with this. */
- /***************************************************************************/
-
- IoctlAbortReceiver (pDX);
- IoctlAbortTransmitter(pDX);
-
- /***************************************************************************/
- /* Read the parameter data. Check that frame will fit the buffer. */
- /***************************************************************************/
-
- if (pIrpSp->IRS_INLEN NE sizeof(SLPARMS))
- {
- pDX->IoctlRetStatus = STATUS_INVALID_PARAMETER;
- pDX->Information = IO_ERR_LINKCHAR_BUF_WRONG_SIZE;
- }
- else
- if (pParms->SLFrameSize < 267) /* don't really want < 2+6+3+256 bytes!? */
- {
- pDX->IoctlRetStatus = STATUS_INVALID_PARAMETER;
- pDX->Information = IO_ERR_FRAME_BUF_TOO_SMALL;
- }
- else
- if (pParms->SLFrameSize > 2048) /* really SDLC frame bigger than 2Kb? */
- {
- pDX->IoctlRetStatus = STATUS_INVALID_PARAMETER;
- pDX->Information = IO_ERR_FRAME_BUF_TOO_BIG;
- }
- else
- if (pParms->SLLinkOptionsByte & LinkOption_InternalClock)
- {
- /*************************************************************************/
- /* We have been asked to supply internal clocks (not supported by these */
- /* adapters). */
- /*************************************************************************/
-
- pDX->IoctlRetStatus = STATUS_INVALID_PARAMETER;
- pDX->Information = IO_ERR_NO_CLOCKS;
- }
- else
- {
- pDX->LinkMaxFrameSize = pParms->SLFrameSize;
-
- /*************************************************************************/
- /* Pick up the addresses and put them in the LCB. Then set General or */
- /* specific receive depending on whether the addresses are zero. */
- /*************************************************************************/
-
- pDX->OurAddress1 = pParms->SLOurAddress1;
- pDX->OurAddress2 = pParms->SLOurAddress2;
- pDX->CmdStringReceive[4] = pParms->SLOurAddress1;
- pDX->CmdStringReceive[5] = pParms->SLOurAddress2;
-
- if (pParms->SLOurAddress1 EQ 0 &&
- pParms->SLOurAddress2 EQ 0)
- {
- /***********************************************************************/
- /* if both addresses are zero, we are SDLC primary and can accept */
- /* frames targetted at any address */
- /***********************************************************************/
- pDX->CmdStringReceive[0] = 0xC0; /* set 3-byte General Rx command */
- pDX->CmdStringReceive[1] = 2;
- }
- else
- {
- pDX->CmdStringReceive[0] = 0xC1; /* set 5-byte Specific Rx command */
- pDX->CmdStringReceive[1] = 4;
- }
-
- /*************************************************************************/
- /* Next, pick up the Link Options and make any necessary changes. */
- /*************************************************************************/
-
- if (NewOpt & LinkOption_FullDuplex /* turn off DMA if the link will */
- && NewOpt & LinkOption_DMA) /* be full duplex. */
- {
- /***********************************************************************/
- /* Check whether the caller asked for DMA, but we couldn't support it */
- /* - return warning error if so. */
- /***********************************************************************/
-
- NewOpt &= ~LinkOption_DMA;
- pDX->Information = IO_ERR_NO_DMA_FDX; /* but r/c is OK. */
- }
-
- pDX->LinkOptionsByte = NewOpt; /* set the new options byte */
-
-
- /*************************************************************************/
- /* Clear the statistics data on the IF record if the appl wants to. */
- /*************************************************************************/
-
- if (NewOpt & LinkOption_ResetStatistics)
- { /* clear the statistics ?? */
- RtlZeroMemory (pDX->pIR->StatusArray, sizeof(pDX->pIR->StatusArray));
- pDX->pIR->StatusCount = 0;
- }
-
- /*************************************************************************/
- /* Now set the options and start the receiver. */
- /*************************************************************************/
-
- if (SetLinkConfig (pDX)) /* call hardware to set options */
- {
- RxFSMEvent (pDX, RxFSMInputStart);/* start receiver if possible */
- rc = TRUE; /* set good return code */
- }
- else
- {
- pDX->IoctlRetStatus = STATUS_DATA_ERROR;
- pDX->Information = IO_ERR_HARDWARE_CMD_TIMEOUT_4;
- }
- }
-
- TRACE_EVENT (IoC]);
- return(rc);
- }
-
- /**PROC+**********************************************************************/
- /* */
- /* Name IoctlRxFrame */
- /* */
- /* Purpose Receive Request processor */
- /* */
- /* Copies next available frame to the application buffer. */
- /* */
- /* Params IN IRP: buffer length in Stack->OutputBufferLength (IRS_OUTLEN)*/
- /* buffer pointer in UserBuffer */
- /* */
- /* OUT Available data, if any */
- /* */
- /* Side Effect pDX->IoctlRetStatus & Information */
- /* */
- /* Return Value TRUE - ignored */
- /* */
- /**PROC-**********************************************************************/
-
- BOOLean IoctlRxFrame (PDX pDX)
- {
- PIRP pIrp = pDX->IoctlCurrentIrp;
- PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
- RFD *pRFD;
- short RxLength;
- UCHAR * GiveMeACharPtr;
-
- TRACE_EVENT ([IoR);
-
- /***************************************************************************/
- /* Check to see if there are any frames waiting in the buffer. The ISR */
- /* fills the buffer by incrementing the 'head' pointer but stops before it */
- /* catches up with the 'tail'. */
- /***************************************************************************/
-
- if (RFD_CAN_GET(pDX)) /* then there is data present */
- {
- pRFD = &pDX->RcvInfo.RFDArray[pDX->RcvInfo.RFDNextToGet];
-
- /*************************************************************************/
- /* We need to copy the data from our buffer into the user's buffer. */
- /* The actual output length goes into the Information field */
- /*************************************************************************/
-
- RxLength = pRFD->RcvdDataLength;
- if (CAST(RxLength, ULONG) + 2 > pIrpSp->IRS_OUTLEN)
- {
- /***********************************************************************/
- /* Output buffer not as big as A + C + Data received */
- /***********************************************************************/
- pDX->IoctlRetStatus = STATUS_BUFFER_TOO_SMALL;
- }
- else
- {
- ASSERT (RxLength >= 0); /* n.b. but length = 0 is OK */
- /* (RR's will have length of 0 in */
- /* buffer, which we report to user */
- /* as length of 0 */
-
- if (RxLength >= 0) /* != -1 => really something there */
- {
- GiveMeACharPtr = MmMapLockedPages(pIrp->MdlAddress, KernelMode);
-
- GiveMeACharPtr[0] = pRFD->SDLCAddressByte;
- GiveMeACharPtr[1] = pRFD->SDLCControlByte;
- RtlMoveMemory (&GiveMeACharPtr[2], pRFD->StartAddr, RxLength);
- }
- }
-
- /*************************************************************************/
- /* We signal the actual received length back in the IoStatusBlock, via */
- /* pDX. */
- /*************************************************************************/
- pDX->Information = RxLength+2;
-
- RFD_GOT(pDX); /* release the buffer we got */
-
- /*************************************************************************/
- /* Lastly decrement the count of received frames available in the shared */
- /* data area. */
- /*************************************************************************/
-
- pDX->pIR->RxFrameCount--;
- }
- else
- {
- pDX->Information = 0;
- TRACE_EVENT (IoRN);
- }
-
- TRACE_EVENT (IoR]);
- return (TRUE);
- }
-
- /*****************************************************************************/
- /* */
- /* Name IoctlSetV24Output */
- /* */
- /* Purpose Handles the IoCtl to set the V24 Output */
- /* */
- /* Params IN pDX */
- /* Implicit input: V24Out byte in IR is what is to be pumped out*/
- /* */
- /* OUT TRUE */
- /* */
- /* Side Effect pDX->IoctlRetStatus & Information */
- /* */
- /*****************************************************************************/
-
- BOOLean IoctlSetV24Output (PDX pDX)
- {
- TRACE_EVENT ([IVO);
- // temporary hack !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- pDX->pIR->V24Out = *(CAST (pDX->IoctlCurrentIrp->UserBuffer, UCHAR *));
- // temporary hack !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- if (!SetV24Output(pDX)) /* call hardware processor */
- {
- return (FALSE);
- }
-
- TRACE_EVENT (IVO]);
- return (TRUE);
- }
-
- /*****************************************************************************/
- /* */
- /* Name IoctlTxFrame */
- /* */
- /* Purpose Transmit frame request handler. Puts frames into the Tx */
- /* buffer ready for the Tx FSM to use. */
- /* */
- /* Transmit Request Processor. */
- /* */
- /* Params IN pIrp parameters point to request packet data and length */
- /* */
- /* OUT Data transferred to Tx buffer ready to send. */
- /* Transmitter FSM kicked. */
- /* */
- /* Side Effect pDX->IoctlRetStatus & Information */
- /* */
- /*****************************************************************************/
-
- BOOLean IoctlTxFrame (PDX pDX)
- {
- ULONG BufferSpaceNeeded;
- ULONG BufferSpaceAvailable;
- PIRP pIrp = pDX->IoctlCurrentIrp;
- PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
- BOOLean rc = TRUE; /* normally OK */
-
- TRACE_EVENT ([IoT);
-
- BufferSpaceNeeded = pIrpSp->IRS_OUTLEN
- + 2; /* allow for frame length header */
-
- XTRACE_ACTION (Tn, BufferSpaceNeeded);
- XTRACE_ACTION (Tx, pDX->LinkMaxFrameSize);
- XTRACE_ACTION (Tb, pDX->TxNextToBuffer);
- XTRACE_ACTION (Tt, pDX->TxNextToTransmit);
-
- if (CAST(pIrpSp->IRS_OUTLEN, int) < 2)
- {
- /*************************************************************************/
- /* The minimum frame size is 2 */
- /*************************************************************************/
-
- pDX->IoctlRetStatus = STATUS_INVALID_PARAMETER;
- pDX->Information = IO_ERR_TX_FRAME_TOO_SMALL;
- rc = FALSE;
- TRACE_RC(rc);
- return(rc);
- }
-
- if (CAST(pIrpSp->IRS_OUTLEN, int) > pDX->LinkMaxFrameSize)
- {
- /*************************************************************************/
- /* The frame is bigger than the maximum specified */
- /*************************************************************************/
-
- pDX->IoctlRetStatus = STATUS_INVALID_PARAMETER;
- pDX->Information = IO_ERR_TX_FRAME_TOO_BIG;
- rc = FALSE;
- TRACE_RC(rc);
- return(rc);
- }
-
- /***************************************************************************/
- /* Check to see if there is room for the data in the transmit buffer. */
- /* This code fills the buffer by incrementing the 'ToTransmit' pointer but */
- /* stops before it catches up with the 'tail'. The ISR takes frames from */
- /* the tail pointer, incrementing it until it matches ToTransmit. */
- /***************************************************************************/
-
- /***************************************************************************/
- /* The ToBuffer and ToTransmit pointers could be anywhere. This code */
- /* checks for ToTransmit < ToBuffer and works out the difference -> AX. */
- /* If the ToTransmit is greater than the ToBuffer, there could be space at */
- /* either end if the buffer - the top end is checked and, if too small, */
- /* the ToTransmit is moved round to the start and then checked as */
- /* ToTransmit < ToBuffer. */
- /***************************************************************************/
-
- if (pDX->TxNextToBuffer >= pDX->TxNextToTransmit)
- { /* ToTransmit is in front of ToBuffer*/
- /*************************************************************************/
- /* The free space is at the end of the buffer. If this is too small, */
- /* set the 'end' for the ISR to the current ToTransmit and then move */
- /* ToTransmit round to the front. Note: we don't go up to SENDBUF_SIZE */
- /* because the TxStartUnusedArea must start on that */
- /*************************************************************************/
-
- BufferSpaceAvailable = SENDBUF_SIZE - 1 - pDX->TxNextToBuffer;
- if (BufferSpaceNeeded > BufferSpaceAvailable)
- /* not enough space at the end ? */
- {
- pDX->TxStartUnusedArea = pDX->TxNextToBuffer;
- /* ISR will wrap at this point */
- pDX->TxNextToBuffer = 0;
- BufferSpaceAvailable = pDX->TxNextToTransmit-1;/* free up to bfr area*/
-
- XTRACE_ACTION (Tu, pDX->TxStartUnusedArea);
- XTRACE_ACTION (Tb, pDX->TxNextToBuffer);
- XTRACE_ACTION (Ta, BufferSpaceAvailable);
- }
- }
- else
- {
- /*************************************************************************/
- /* the free space is from NextToTransmit up to NextToBuffer */
- /*************************************************************************/
-
- BufferSpaceAvailable = pDX->TxNextToBuffer - 1 - pDX->TxNextToTransmit;
- XTRACE_ACTION (Ta, BufferSpaceAvailable);
- }
-
- if (BufferSpaceAvailable >= BufferSpaceNeeded)
- {
- /*************************************************************************/
- /* The 'Max Tx Frame is initialised to be a little less than half the */
- /* total size of the transmit buffer and is decremented by half the size */
- /* of each frame put in (rounded UP). It is kept at half because the */
- /* bfr can get split into two pieces and we need a contiguous area. */
- /*************************************************************************/
-
- pDX->pIR->TxMaxFrSizeNow -= (BufferSpaceNeeded + 1) >> 1;
- XTRACE_ACTION (Tz, pDX->pIR->TxMaxFrSizeNow);
- pDX->pSendBuf [pDX->TxNextToBuffer] = LOBYTE(BufferSpaceNeeded-2);
- pDX->pSendBuf [pDX->TxNextToBuffer+1] = HIBYTE(BufferSpaceNeeded-2);
- /* set length to data length */
- /* (-2 => less length itself)*/
- RtlMoveMemory (&(pDX->pSendBuf[pDX->TxNextToBuffer+2]),
- pIrp->UserBuffer,
- BufferSpaceNeeded-2);
-
- /*************************************************************************/
- /* Now set up the new buffer ToTransmit position. */
- /*************************************************************************/
-
- pDX->TxNextToBuffer += BufferSpaceNeeded;
- XTRACE_ACTION (Tb, pDX->TxNextToBuffer);
- ASSERT (pDX->TxNextToBuffer < SENDBUF_SIZE);
-
- /*************************************************************************/
- /* Kick the Transmit FSM to start it off. */
- /*************************************************************************/
-
- TxFSMEvent (pDX, TxFSMInputStart);
-
- // and returned status is TRUE;
- }
- else
- {
- /*************************************************************************/
- /* There is no room for the frame - return an error. */
- /*************************************************************************/
-
- pDX->IoctlRetStatus = STATUS_BUFFER_TOO_SMALL;
- pDX->Information = IO_ERR_TX_BUFFER_FULL;
- rc = FALSE;
- TRACE_RC(rc);
- }
-
- TRACE_EVENT (IoT]);
-
- return (rc);
-
- }
-
- /*****************************************************************************/
- /* */
- /* Name RxFSMActionInvalid */
- /* */
- /* Purpose Error input to FSM */
- /* */
- /* This routine should never be called as it implies an */
- /* 'impossible state/input combination. This is taken to mean */
- /* that adapter status has been incorrectly reported and is */
- /* treated as a hardware error. */
- /* */
- /* Params IN pDX */
- /* */
- /* OUT Error processing started by RQ FSM input */
- /* */
- /*****************************************************************************/
-
- void RxFSMActionInvalid (PDX pDX)
- {
- TRACE_EVENT (RAI:);
-
- pDX->pIR->StatusArray[SA_HardwareError]++;
- pDX->pIR->StatusCount ++;
- pDX->DPCAction |= DPC_ACTION_PULSE;
-
- TRACE_EVENT (RAI;);
- }
-
- /*****************************************************************************/
- /* */
- /* Name RxFSMActionRestart */
- /* */
- /* Purpose Coming back after having held rx so transmitter can go */
- /* so - we can switch buffers so DMA can run for the whole buf */
- /* */
- /* Params IN pDX */
- /* */
- /* Implicit input: that when the receiver was stopped that the */
- /* 'NowBeingPut' RFD for this adapter was allocated and init- */
- /* ialised properly. So this is just a 'start reciver'. */
- /* */
- /* OUT Receiver started */
- /* */
- /* */
- /*****************************************************************************/
-
- void RxFSMActionRestart (PDX pDX)
- {
- RFD * pRFD = & pDX->RcvInfo.RFDArray[pDX->RcvInfo.RFDNowBeingPut];
-
- TRACE_EVENT (RRs:);
-
- pDX->LastPortA = Write8273Cmd (pDX, pDX->CmdStringReadPortA);
-
- if (pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA)
- {
- StopDMA (pDX);
- XASSERT (!pDX->DMAIsActive);
-
- /*************************************************************************/
- /* only worry about this if we using DMA and if other buffer not in use */
- /*************************************************************************/
- if (!(RCVBUF_INUSE(pRFD->BufPtr->OtherBuffer)))
- {
- /* use other buffer */
- pRFD->BufPtr = pRFD->BufPtr->OtherBuffer;
- pRFD->StartIndex= 0;
- pRFD->StartAddr = &pRFD->BufPtr->Data[0];
- }
- }
- RxFSMActionStart (pDX);
- TRACE_EVENT (RRs;);
- }
-
- /*****************************************************************************/
- /* */
- /* Name RxFSMActionStart */
- /* */
- /* Purpose Starts the Receiver and DMA (if configured). */
- /* */
- /* Params IN pDX */
- /* */
- /* Implicit input: that when the receiver was stopped that the */
- /* 'NowBeingPut' RFD for this adapter was allocated and init- */
- /* ialised properly. So this is just a 'start reciver'. */
- /* */
- /* OUT Receiver started */
- /* */
- /* */
- /*****************************************************************************/
-
- void RxFSMActionStart (PDX pDX)
- {
- RFD * pRFD = & pDX->RcvInfo.RFDArray[pDX->RcvInfo.RFDNowBeingPut];
- int AvailableByteCount = RCVDATABUF_SIZE - 1 - pRFD->StartIndex;
- /* allocate all the rest of the buffr*/
- /* This really is the available bytes*/
- USHORT CmdByteCount = CAST (AvailableByteCount - 2, USHORT);
- /* number of bytes to command 8273 */
- TRACE_EVENT (RSt:);
-
- XASSERT (AvailableByteCount >= CAST (pDX->LinkMaxFrameSize, int));
- /* frame must fit into rest of buffer*/
- /* or previous code screwed up */
- XTRACE_ACTION (Ra, AvailableByteCount);
-
- /***************************************************************************/
- /* Prime the DMA if necessary. */
- /***************************************************************************/
-
- if (pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA)
- {
- if (!pDX->DMAIsActive)
- {
- /***********************************************************************/
- /* If the DMA is already running we just leave it running. Otherwise */
- /* need to start it */
- /***********************************************************************/
- PHYSICAL_ADDRESS L;
-
- L = pRFD->BufPtr->DataPhysAddr;
- L.LowPart += (ULONG) pRFD->StartIndex;
- StartDMA (pDX,
- L,
- CmdByteCount, /* should be one less, but we've left*/
- /* two bytes slop above anyway */
- DMACmdWrite
- );
- }
- XASSERT (pDX->DMAIsActive);
- }
- else
- {
- pDX->pRxPIOData = pRFD->StartAddr;
- XTRACE_EVENT (RPIO);
- XTRACE_DWORD (pDX->pRxPIOData);
- }
-
- pDX->CmdStringReceive[2] = LOBYTE(CmdByteCount);
- pDX->CmdStringReceive[3] = HIBYTE(CmdByteCount);
-
- Write8273Cmd (pDX, pDX->CmdStringReceive);
-
- TRACE_EVENT (RSt;);
- }
-
- /****************************************************************************/
- /* */
- /* Name RxFSMActionStop */
- /* */
- /* Purpose Stops the Receiver and DMA (if configured). */
- /* */
- /* Params IN pDX */
- /* */
- /* OUT Receiver stopped */
- /* */
- /****************************************************************************/
-
- void RxFSMActionStop (PDX pDX)
- {
- TRACE_EVENT (RSo:);
-
- /*********************************************************************/
- /* Check whether DMA is supported and kill the DMA Channel if so. */
- /*********************************************************************/
-
- if (pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA)
- {
- StopDMA (pDX);
- XASSERT (!pDX->DMAIsActive);
- }
-
- /*********************************************************************/
- /* Issue a Disable command to the 8273. */
- /*********************************************************************/
-
- Write8273Cmd (pDX, pDX->CmdStringDisableReceiver);
-
- /***************************************************************************/
- /* Following IO_DELAY is an attempt to prevent a hang reading port A in */
- /* this situation */
- /***************************************************************************/
- IO_DELAY(5L);
- pDX->LastPortA = Write8273Cmd (pDX, pDX->CmdStringReadPortA);
-
- TRACE_EVENT (RSo;);
- }
-
- /****************************************************************************/
- /* */
- /* Name RxFSMActionRcvError */
- /* */
- /* Purpose Updates the received data statistics and restarts the Rcvr */
- /* */
- /* Carries out end-of-frame processing on error results. */
- /* */
- /* Params IN BX -> error result from the 8273 */
- /* */
- /* OUT Updated Rx stats - receiver restarted. */
- /* */
- /****************************************************************************/
-
- void RxFSMActionRcvError (PDX pDX)
- {
- /***************************************************************************/
- /* Clear the top nibble of result so we can detect non-octet boundary errs */
- /***************************************************************************/
-
- UCHAR ResultCode = CAST(pDX->RxResultBuffer[0] & 0x0F, UCHAR);
-
- static
- USHORT ErrorMapArray[] = /* f: 8273code -> index in StatusArry*/
- {
- /* 0General */ SA_Spare + 256, /* +256->stop receiver */
- /* 1Selective */ SA_Spare + 256,
- /* 2<unused> */ SA_HardwareError, /* shouldn't be generated */
- /* 3CRC */ SA_CRC_Error + 256,
- /* 4Abort */ SA_RxAbort + 256,
- /* 5Idle */ 0, /* don't use */
- /* 6EOP */ SA_Spare,
- /* 7Short */ SA_RxFrameTooShort + 256,
- /* 8DMAOverrun */ SA_RxOverrun,
- /* 9BufO */ SA_RxFrameTooBig,
- /* 10RLSD */ SA_DCDDrop,
- /* 11RxIntOverrun */ SA_HardwareError,
- /* 12 tx */ SA_HardwareError,
- /* 13 tx */ SA_HardwareError,
- /* 14 tx */ SA_HardwareError,
- /* 15 tx */ SA_HardwareError, /* 15 for 0x0F & value */
- };
-
- XASSERT (ResultCode < 12);
- XTRACE_ACTION (Rm, ErrorMapArray[ResultCode]);
-
- /***************************************************************************/
- /* Filter out 'idle' indications before going through checks */
- /***************************************************************************/
-
- if (ResultCode NE ARxR_ErrIdle) /* no StopRequired - idle stop Rcvr */
- {
- /*************************************************************************/
- /* Increment the statistics and set the flag to pulse event */
- /*************************************************************************/
-
- pDX->pIR->StatusArray[LOBYTE(ErrorMapArray[ResultCode])]++;
- pDX->pIR->StatusCount++;
- pDX->DPCAction |= DPC_ACTION_PULSE;
- }
-
- /*********************************************************************/
- /* Check whether DMA is supported and kill the DMA Channel if so. */
- /*********************************************************************/
-
- if (pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA)
- {
- StopDMA (pDX);
- XASSERT (!pDX->DMAIsActive);
- }
-
- /***************************************************************************/
- /* For those situations that need it (i.e. where the error has left the */
- /* receiver active), stop the receiver. As a result, the receiver will */
- /* always be stopped after an error. This is just being paranoid - */
- /* shouldn't really need to. */
- /***************************************************************************/
-
- if (HIBYTE(ErrorMapArray[ResultCode])) /* high byte->stop required */
- {
- RxFSMActionStop (pDX);
- }
-
- /***************************************************************************/
- /* Now call the action routine to restart the receiver. */
- /***************************************************************************/
-
- RxFSMActionStart (pDX);
-
- }
-
- /*****************************************************************************/
- /* */
- /* Name RxFSMActionRcvOK */
- /* */
- /* Purpose Updates the Receiver buffer data to reflect new data, does */
- /* some statistics adjustment and kicks the Rx sema4. */
- /* */
- /* Carries out end-of-received frame processing. */
- /* */
- /* Params IN pDX */
- /* Implicit:pDX->ResultBuffer has all results */
- /* [0] = OK result code */
- /* [1] = Length (lo) */
- /* [2] = Length (hi) */
- /* [3] = Address */
- /* [4] = Control */
- /* */
- /* OUT Updated Rx buffer and stats - receiver restarted. */
- /* */
- /*****************************************************************************/
-
- void RxFSMActionRcvOK (PDX pDX)
- {
- /* this is the 'Old' one */
- /* New NowBeingPut */
- BOOLean CanMoveOn = TRUE; /* won't be true if no more RFDs OR */
- /* no space in this buffer and other */
- /* buffer in use */
- BOOLean MustStopReceiver = TRUE;
- short NewNBP = CAST((pDX->RcvInfo.RFDNowBeingPut+1) % RFDARRAY_SIZE,
- short);
- RFD * pNewRFD= & pDX->RcvInfo.RFDArray[NewNBP];
- USHORT RcvdLength;
- RFD * pRFD = & pDX->RcvInfo.RFDArray[pDX->RcvInfo.RFDNowBeingPut];
-
- TRACE_EVENT (ROk:);
- XTRACE_OBJECT(Rp, (*pRFD));
- XTRACE_DWORD (pRFD);
- XTRACE_OBJECT(Rb, (*(pRFD->BufPtr)));
- XTRACE_ACTION(Rs, pRFD->StartIndex);
-
- /***************************************************************************/
- /* First, copy results into existing RFD */
- /***************************************************************************/
-
- XASSERT (pRFD->RcvdDataLength EQ -1); /* this buffer hasn't been 'filled' */
-
- pRFD->SDLCAddressByte = pDX->RxResultBuffer[3];
- pRFD->SDLCControlByte = pDX->RxResultBuffer[4];
- pRFD->RcvdDataLength = MAKEUSHORT (pDX->RxResultBuffer[1],
- pDX->RxResultBuffer[2]);
- RcvdLength = pRFD->RcvdDataLength;
- XTRACE_ACTION (Rl,RcvdLength);
-
- /***************************************************************************/
- /* Double-check the length the 8273 tells us compared to what we rcvd on */
- /* the interrupt side */
- /***************************************************************************/
-
- #ifdef XDEBUG
-
- if (BITSOFF(pDX->GrabbedResources,GRABBEDRESOURCE_GOTDMA))
- XASSERT (CAST(pRFD->RcvdDataLength, int) EQ
- (pDX->pRxPIOData - pRFD->StartAddr));
- #endif
-
- /***************************************************************************/
- /* Now figure out a) if we can fit next frame into this buffer, and b) */
- /* failing that if we can start using the other buffer */
- /***************************************************************************/
-
- if (NewNBP EQ pDX->RcvInfo.RFDNextToGet)
- {
- CanMoveOn = FALSE; /* can't wrap round onto next to get */
- }
- else
- {
-
- /*************************************************************************/
- /* Set up the new startindex - this is OK even if we don't move onto new */
- /* RFD because it's not being used. */
- /* */
- /* Then see if we can let the receiver run - if not, we'll have to stop */
- /* it and switch DMA etc. */
- /* */
- /* If we let the receiver run, we must calculate exactly where the data */
- /* for the next frame is going to go! */
- /* */
- /* Note that if we are receiving into a given buffer, we always have the */
- /* rest of that buffer to play with, because we only strt using a new */
- /* buffer if all received frames that were in it have been got out. */
- /*************************************************************************/
-
- pNewRFD->StartIndex = CAST(pRFD->StartIndex + RcvdLength, short);
-
- if (CAST(pNewRFD->StartIndex, int) +
- CAST(pDX->LinkMaxFrameSize, int) +
- 2 /* +2 for possible CRC dribble */
- < RCVDATABUF_SIZE) /* (and some more paranoia). */
- {
- /***********************************************************************/
- /* next packet fits into this buffer - can let receiver run */
- /***********************************************************************/
-
- pNewRFD->BufPtr = pRFD->BufPtr;
- pNewRFD->StartAddr = &pNewRFD->BufPtr->Data[pNewRFD->StartIndex];
- MustStopReceiver = FALSE;
- }
- else
- {
- /***********************************************************************/
- /* This buffer is hopeless, so how about the other one - have all it's */
- /* frams been pulled? If so, we can use it */
- /***********************************************************************/
-
- if (RCVBUF_INUSE(pRFD->BufPtr->OtherBuffer))
- {
- CanMoveOn = FALSE; /* cant use him either */
- }
- else
- {
- /* use other buffer */
- pNewRFD->BufPtr = pRFD->BufPtr->OtherBuffer;
- pNewRFD->StartIndex= 0;
- pNewRFD->StartAddr = &pNewRFD->BufPtr->Data[0];
- }
- }
- }
-
- /***************************************************************************/
- /* If necessary, stop the receiver */
- /***************************************************************************/
-
- if (MustStopReceiver)
- {
- RxFSMActionStop (pDX);
- }
-
- /***************************************************************************/
- /* If we will be moving on, do it & increment the count of waiting frames. */
- /* Whatever happens, we must signal that RFD is empty via RcvdDataLength */
- /***************************************************************************/
-
- if (CanMoveOn)
- {
- RFD_PUT(pDX);
-
- pDX->RcvInfo.RFDNowBeingPut = NewNBP;
- pRFD = pNewRFD;
- pDX->pIR->RxFrameCount++; /* show Rx frame available */
- }
- pRFD->RcvdDataLength = -1; /* empty ! */
-
- TRACE_OBJECT(Rp, (*pRFD));
- XTRACE_DWORD (pRFD);
- XTRACE_OBJECT(Rb, (*(pRFD->BufPtr)));
- XTRACE_ACTION(Rs, pRFD->StartIndex);
-
- /***************************************************************************/
- /* A frame is ready for the application (or the buffer is full and the */
- /* application should do some receiving) - set the flag so that its */
- /* semaphore will be cleared by the ISR when we return. */
- /***************************************************************************/
-
- pDX->DPCAction |= DPC_ACTION_PULSE;
-
- /***************************************************************************/
- /* Now call the action routine to restart the receiver. */
- /***************************************************************************/
-
- RxFSMActionStart (pDX);
-
- TRACE_EVENT (ROk;);
- }
-
- /*****************************************************************************/
- /* */
- /* Name RxFSMEvent */
- /* */
- /* Purpose Interprets inputs from the Request handlers and from the */
- /* ISR and calls the relevant action routines. */
- /* */
- /* There are two fundamental states: */
- /* */
- /* - idle */
- /* - ready (i.e. receiver is active) */
- /* */
- /* Each of these states, however, can also exist in two states */
- /* depending on the activity of the transmitter which has to */
- /* restrain the receiver when it is using the DMA. These sub- */
- /* states are idle(held) and ready(held). */
- /* */
- /* Purpose Routes processing to the relevant action routines. The FSM */
- /* action must be synchronized. The action routines are allowed*/
- /* to call back to the FSM. */
- /* */
- /* Params IN pDX */
- /* FSMInput - the input value */
- /* Implicit - pDX->RxResultBuffer result bytes pulled from */
- /* Rx status register on 8273 */
- /* */
- /* OUT Action routine called and new state set. */
- /* */
- /*****************************************************************************/
-
- void RxFSMEvent (PDX pDX, int Input)
- {
- RXFSMENTRY *e = &RxFSM [Input] [pDX->RxFSMCurState];
-
- /***************************************************************************/
- /* The FSM consists of a 'state' which is actually the address of the */
- /* current FSM 'column'. The 'input' is an offset down the column at */
- /* which is located an action routine address and a new state. */
- /***************************************************************************/
-
- TRACE_EVENT (<RFE);
-
- ASSERT (pDX->RxFSMCurState < RXFSMSTATECOUNT);
- ASSERT (Input < RXFSMINPUTCOUNT);
- TRACE_EVENTNAME(RxFSMStateNames[pDX->RxFSMCurState]);
- TRACE_EVENTNAME(RxFSMInputNames[Input]);
-
- /***************************************************************************/
- /* Reset the state to the new state specified in the FSM table */
- /* (Important to do this before the actions because some of them then do */
- /* recursive calls to FSMEvent */
- /***************************************************************************/
-
- pDX->RxFSMCurState = e->NewState;
- ASSERT (e->NewState < RXFSMSTATECOUNT);
- TRACE_EVENTNAME(RxFSMStateNames[pDX->RxFSMCurState]);
-
- /***************************************************************************/
- /* Do the action specified by the FSM table entry */
- /***************************************************************************/
- (*(e->pRxActionRoutine)) (pDX);
-
- TRACE_EVENT (RFE>);
- }
-
- /*****************************************************************************/
- /* */
- /* Name FSMNullAction */
- /* */
- /* Purpose Carries out a 'nul' action for both Tx and Rx FSM */
- /* */
- /*****************************************************************************/
-
- void FSMNullAction (PDX pDX)
- {
- UNREFERENCED_PARAMETER (pDX);
- return;
- }
-
- /**PROC+**********************************************************************/
- /* */
- /* Name SetLinkConfig (pDX) */
- /* */
- /* Purpose Link Configuration Characteristics set-up. */
- /* Primes the 8273 and V24 interface in the manner required */
- /* required by a particular set of link configuration options. */
- /* */
- /* Params IN Link Options byte (pDX->LinkOptions) set up */
- /* Implicit input: the adapter has been reset and is ready to go*/
- /* */
- /* OUT Hardware is set up as indicated or carry set. */
- /* */
- /* Return Value BOOLean: TRUE if options set up OK, otherwise FALSE */
- /* */
- /**PROC-**********************************************************************/
-
- BOOLean SetLinkConfig (PDX pDX)
- {
- UCHAR o;
- BOOLean rc;
-
- TRACE_EVENT (<SLC);
-
- ASSERT (pDX->HardwareError EQ FALSE); /* Reset function should turn off */
- /* hardware error flag */
-
- /***************************************************************************/
- /* Check the configuration bits and use the data to set up the mode set */
- /* and reset commands held on the LCB. Then run through the whole batch */
- /* in a tight loop at the end. */
- /***************************************************************************/
-
- /***************************************************************************/
- /* Operating mode */
- /***************************************************************************/
- o = AP_OMBFR; /* assume default (buffered) */
- if (pDX->LinkOptionsByte & LinkOption_HDLC)
- {
- o |= AP_OMX25; /* set HDLC Abort */
- }
-
- pDX->CmdStringSetOpMode[2] = CAST(o, UCHAR);
- pDX->CmdStringResetOpMode[2]= CAST(o | APR_OM, UCHAR);
-
- /***************************************************************************/
- /* Serial IO Mode */
- /***************************************************************************/
- o = 0; /* assume SIO mode is NRZ */
- if (pDX->LinkOptionsByte & LinkOption_NRZI) /* then check for NRZI selected */
- {
- o |= AP_IONZI; /* set NRZI bit in the mask */
- }
- pDX->CmdStringSetSerialIOMode[2]= CAST (o, UCHAR);
- pDX->CmdStringResetSerialIOMode[2]= CAST (o | APR_IO, UCHAR);
- /* set the unused bits for reset */
- /***************************************************************************/
- /* Sort out DMA. Assume for now we will be able to use an architectural */
- /* NT-defined way of avoiding conflicts on DMA channels, */
- /***************************************************************************/
-
- pDX->CmdStringDataTransferMode[0]= 0x97;/* assume Data Transfer is PIO */
- pDX->CmdStringDataTransferMode[2]= 1;
- pDX->GrabbedResources &= ~GRABBEDRESOURCE_GOTDMA; /*and clear DMA privelege*/
-
- if (pDX->LinkOptionsByte & LinkOption_DMA && /* DMA Requested ? */
- pDX->ConfigData.DMAChannel NE 0) /* and DMA possible for card */
- {
- /*************************************************************************/
- /* Read this link's configured DMA channel and check for non-0 */
- /*************************************************************************/
-
- ///////////////////////////////////////////////////////////////////////////////
- // guff to do with protecting ourselves from other guy using same DMA channel
- // reinstate later if necessary
- //
- // if <SI eq <offset SELCBL1>>
- //
- // mov DI,offset SELCBL2
- //
- // else
- //
- // mov DI,offset SELCBL1
- //
- // }
- //
- // /**********************************************************************/
- // /* Check whether the links use the same DMA and grab it if not. */
- // /* Otherwise look to see whether the other link does not currently */
- // /* have DMA. */
- // /**********************************************************************/
- //
- // if <AL ne pDX->DMAChan> OR
- // test pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA
- // if z
- ///////////////////////////////////////////////////////////////////////////////
-
- pDX->GrabbedResources |= GRABBEDRESOURCE_GOTDMA; /* register ownership! */
- pDX->DMAIsActive = FALSE;
- pDX->CmdStringDataTransferMode[0]= 0x57; /* and set DT mode to DMA */
- pDX->CmdStringDataTransferMode[2]= 0xFE; /* ..rather than interrupts */
-
- /*************************************************************************/
- /* If this is MCA Extended DMA then we have to set up an I/O transfer */
- /* address. */
- /*************************************************************************/
-
- if (pDX->ConfigData.DMAChannel NE StandardDMAChannel)
- {
- ///////////////////////////////////////////////////////////////////////////////
- //?ML?
- // from semdh.asm
- // and AL,0fh ;clear top four bits
- // out LDD_DMAEFR,AL ;write out the fncn cmnd
- //
- // mov AX,LCB.LCBPrtBase
- // add AX,LDD_73Data
- // out LDD_DMAEFE,AL ;write out the LOB
- // SEPDHDLY ;let it take effect
- // mov AL,AH
- // out LDD_DMAEFE,AL ;write out the HOB
- //////////////////////////////////////////////////////////////////////////////
-
- USHORT Addr = CAST(pDX->ADAPTERBASE+AR_8273D, USHORT);
-
- WR_N_DELAY (DMAExtdFnRegister, CAST(pDX->ConfigData.DMAChannel & 0x0F, \
- UCHAR));
- WR_N_DELAY (DMAExtdFnRegister, LOBYTE(Addr)); /* write out the LOB */
- WR_N_DELAY (DMAExtdFnRegister, HIBYTE(Addr)); /* and HOB */
- }
- }
-
- /***************************************************************************/
- /* Now actually issue the mode setting commands to the 8273. */
- /***************************************************************************/
-
- Write8273Cmd(pDX,pDX->CmdStringResetOpMode);
- Write8273Cmd(pDX,pDX->CmdStringResetSerialIOMode);
- Write8273Cmd(pDX,pDX->CmdStringSetOpMode);
- Write8273Cmd(pDX,pDX->CmdStringSetSerialIOMode);
- Write8273Cmd(pDX,pDX->CmdStringDataTransferMode);
- rc = !pDX->HardwareError;
-
- TRACE_RCFALSE(rc);
- TRACE_EVENT (SLC>);
- return (rc);
- }
-
- /**PROC+**********************************************************************/
- /* */
- /* Name SetV24Output ( */
- /* PDX pDX */
- /* ); */
- /* */
- /* Purpose Primes the 8273 and V24 interfaces as requested in IR->V24Out*/
- /* */
- /* Params IN pDX - the device extension */
- /* Implicit input: V24Out byte in IR is what is to be pumped out*/
- /* */
- /* Return Value BOOLean: TRUE if commands etc. correctly written */
- /* */
- /* Operation */
- /* */
- /**PROC-**********************************************************************/
-
- BOOLean SetV24Output (PDX pDX)
- {
- /**********************************************************************/
- /* Do the 8255 Port B settings first. Note that their sense is */
- /* logically inverted and 0 = ON. */
- /*********************************************************************/
-
- UCHAR o;
- UCHAR V24Out = pDX->pIR->V24Out;
-
- o = 8; /* NOT reset modem status logic */
- o |= (V24Out & IR_OV24DSRS) /* user wants DSRS on? */
- ? 0 /* 0 in port B turns on DSRS */
- : 1;
- o |= (V24Out & IR_OV24SlSt) /* user wants Select Standby on? */
- ? 0 /* 0 in port B turns on Select Stndby*/
- : 2;
- o |= (V24Out & IR_OV24Test) /* user wants Test on? */
- ? 0 /* 0 in port B turns on Test */
- : 4;
-
- WR_N_DELAY (pDX->ADAPTERBASE + AR_8255B, o);
-
- /*********************************************************************/
- /* Now do the 8273 Port B settings. */
- /*********************************************************************/
-
- o = 0;
- o |= (V24Out & IR_OV24RTS) /* user wants RTS up? */
- ? 1
- : 0;
- o |= (V24Out & IR_OV24DTR) /* user wants DTR up? */
- ? 4
- : 0;
-
- pDX->CmdStringSetPortB[2]= o; /* save value in 'set' cmd */
- pDX->CmdStringResetPortB[2]= CAST(0xC0 | o, UCHAR);
- /* and also in 'reset' cmd */
-
- Write8273Cmd (pDX,pDX->CmdStringSetPortB); /* turn on what should be on */
- Write8273Cmd (pDX,pDX->CmdStringResetPortB); /*and turn off what shouldn't*/
-
- return(!pDX->HardwareError);
- }
-
- /*****************************************************************************/
- /* */
- /* Name StartDMA ( */
- /* PDX pDX */
- /* PHYSICAL_ADDRESS PhysicalAddress */
- /* USHORT BufferLength */
- /* UCHAR OpCode */
- /* ); */
- /* */
- /* Purpose Issues a Receive/Transmit command to the DMA. The address */
- /* and length information are all in registers, other than the */
- /* segment physical base address which is in global data. */
- /* */
- /* Params IN PhysicalAddress (not System VAS address!) */
- /* BufferLength is maximum data length */
- /* (although the 8273 controls exactly how many transfers are */
- /* pulled). So this count really acts as a stopper and should */
- /* (due to stupid design of 8273) be one less than overflow val */
- /* OpCode is DMACmdRead/Write */
- /* */
- /* OUT Command issued to DMA. */
- /* */
- /* Modified: 31/03/88 Initial coding */
- /* */
- /*****************************************************************************/
-
- void StartDMA(PDX pDX,
- PHYSICAL_ADDRESS PhysicalAddress,
- USHORT BufferLength,
- UCHAR OpCode)
- {
- PHYSICAL_ADDRESS a;
- USHORT b;
-
- TRACE_EVENT (<SDM);
-
- ASSERT (!DMACrosses64K(PhysicalAddress.LowPart, BufferLength));
-
- /***************************************************************************/
- /* First, test whether the channel number is set to 1. If not, then this */
- /* is an MCA machine using a non-standard channel, so dothe MCA version of */
- /* this routine */
- /***************************************************************************/
-
- if (pDX->ConfigData.DMAChannel EQ StandardDMAChannel)/* good ole channel one */
- {
- /*************************************************************************/
- /* Mask off the channel we're about to play with. */
- /*************************************************************************/
-
- IO_OUT (DMAMaskRegister, DMAMaskChannel1);
-
- /*************************************************************************/
- /* The hard part is generating an address to give the DMA chip. We */
- /* already know, because initialisation ensures it, that the buffer will */
- /* not span a 64k boundary, but we have to generate the full physical */
- /* address from the offset supplied in DI and the physical address of */
- /* DGROUP read in during initialisation. */
- /*************************************************************************/
-
- IO_OUT (DMAFirstByteFlipFlop,0); /* data ignored, OUT resets FF */
-
- a = PhysicalAddress;
-
- WR_N_DELAY (DMAPhysAddress, a.LowPart & 0xFF); /* first, set physaddr low byte */
- a.LowPart = a.LowPart >> 8;
- WR_N_DELAY (DMAPhysAddress, a.LowPart & 0xFF); /* next, set physaddr high byte */
- a.LowPart = a.LowPart >> 8;
- WR_N_DELAY (DMAPageRegister,a.LowPart & 0xFF) /* finally 64k page register value*/
-
- /*************************************************************************/
- /* Next give the chip the maximum size count passed in BufferLength. */
- /*************************************************************************/
-
- WR_N_DELAY (DMAFirstByteFlipFlop,0); /* ML did this so I will too ? */
-
- b = BufferLength;
- WR_N_DELAY (DMACountRegister, a.LowPart & 0xFF);
- b = b >> 8;
- WR_N_DELAY (DMACountRegister, a.LowPart & 0xFF);
-
- /*************************************************************************/
- /* Set up the mode value as passed in. */
- /*************************************************************************/
-
- WR_N_DELAY (DMAModeRegister, OpCode);
-
- /*************************************************************************/
- /* Finally kick the chip off by clearing the channel mask bit. */
- /*************************************************************************/
-
- IO_OUT (DMAMaskRegister, DMAClearChannel1);
-
- }
- else
- {
- /*************************************************************************/
- /* This must be an MCA machine with programmable DMA channels. The only */
- /* actual option at present is '7' for the second MPA/A. */
- /*************************************************************************/
-
- ASSERT (pDX->ConfigData.DMAChannel EQ 7);
-
- /*************************************************************************/
- /* Set the mask for this channel. */
- /*************************************************************************/
-
- IO_OUT (DMAExtdFnRegister, pDX->ConfigData.DMAChannel | MCADMASetMask);
-
- /*************************************************************************/
- /* Give the DMA registers the data xfer start address. */
- /*************************************************************************/
-
- IO_OUT (DMAExtdFnRegister, pDX->ConfigData.DMAChannel | MCADMAAddress);
-
- a = PhysicalAddress;
-
- WR_N_DELAY (DMAExtdFnRegister, a.LowPart & 0xFF); /* and then set address bits 0-7 */
- a.LowPart = a.LowPart >> 8;
- WR_N_DELAY (DMAExtdFnRegister, a.LowPart & 0xFF); /* set address bits 8 - 15 */
- a.LowPart = a.LowPart >> 8;
- WR_N_DELAY (DMAExtdFnRegister, a.LowPart & 0xFF); /* set address bits 16 - 23 */
-
- /*************************************************************************/
- /* Now set up the maximum xfer count. */
- /*************************************************************************/
-
- IO_OUT (DMAExtdFnRegister, pDX->ConfigData.DMAChannel | MCADMACount);
-
- a.LowPart = BufferLength;
- WR_N_DELAY (DMAExtdFnRegister, a.LowPart & 0xFF); /* length low byte */
- a.LowPart = a.LowPart >> 8;
- WR_N_DELAY (DMAExtdFnRegister, a.LowPart & 0xFF); /* length high byte */
-
- /*************************************************************************/
- /* Now set the mode register for the channel (read/write). This is done */
- /* on the basis of the original old-style mode being for read or for */
- /* write. */
- /*************************************************************************/
-
- IO_OUT (DMAExtdFnRegister, pDX->ConfigData.DMAChannel | MCADMAMode);
-
- WR_N_DELAY (DMAExtdFnRegister, (OpCode EQ DMACmdWrite) ? 0x0D : 0x05);
-
- /*************************************************************************/
- /* Last job is to reset the mask register for the channel. */
- /*************************************************************************/
-
- IO_OUT (DMAExtdFnRegister, pDX->ConfigData.DMAChannel | MCADMAClearMask);
- }
- pDX->DMAIsActive = TRUE;
- TRACE_EVENT (SDM>);
- }
-
- /*****************************************************************************/
- /* */
- /* Name StopDMA */
- /* */
- /* Purpose Link Device Driver Stop DMA Routine. */
- /* */
- /* Kills the DMA by masking the appropriate channel. */
- /* */
- /* Params IN pDX */
- /* Implicit: DMA channel allocated */
- /* */
- /* OUT Command issued to DMA. */
- /* */
- /*****************************************************************************/
-
- void StopDMA (PDX pDX)
- {
- TRACE_EVENT (<ZDM);
-
- ASSERT (pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA);
-
- if (pDX->ConfigData.DMAChannel EQ StandardDMAChannel)
- {
- /*************************************************************************/
- /* Channel #1 - set the mask directly. */
- /*************************************************************************/
-
- IO_OUT (DMAMaskRegister, DMAMaskChannel1);
- }
- else
- {
- /*************************************************************************/
- /* Not channel 1 - set the mask using the Extended function addressing */
- /* register. */
- /*************************************************************************/
-
- IO_OUT (DMAExtdFnRegister, pDX->ConfigData.DMAChannel | MCADMASetMask);
- }
- pDX->DMAIsActive = FALSE;
- TRACE_EVENT (ZDM>);
- }
-
- /**PROC+**********************************************************************/
- /* */
- /* Name: SynchReset8273 ( */
- /* PDEVICE_OBJECT pDeviceObject */
- /* ) */
- /* */
- /* Purpose: Reset the 8273 and set the 'Closing' flag so that following */
- /* interrupts are ignored (until we disable) */
- /* with interrupt processing */
- /* */
- /* Params: IN Context is really pDX */
- /* */
- /* Return Value:None */
- /* */
- /* Operation: */
- /* */
- /* */
- /**PROC-**********************************************************************/
-
- BOOLEAN SynchReset8273 (PVOID Context)
- {
- PDX pDX = (PDX) Context;
- TRACE_EVENT (<XR8);
-
- pDX->AdapterIsClosing = TRUE;
- AdapterReset (pDX);
-
- TRACE_EVENT(XR8>);
-
- return (FALSE);
- }
-
- /**PROC+**********************************************************************/
- /* */
- /* Name: SynchTerminateAdapter( */
- /* PDEVICE_OBJECT pDeviceObject */
- /* ) */
- /* */
- /* Purpose: Close a particular device - stuff that needs to be interlockd*/
- /* with interrupt processing */
- /* */
- /* Params: IN Context is really pDX */
- /* */
- /* Return Value:None */
- /* */
- /* Operation: */
- /* */
- /* */
- /**PROC-**********************************************************************/
-
- BOOLEAN SynchTerminateAdapter (PVOID Context)
- {
- PDX pDX = (PDX) Context;
- TRACE_EVENT (<XTA);
-
- TerminateAdapter (pDX);
-
- TRACE_EVENT(XTA>);
-
- return (FALSE);
- }
-
- /**PROC+**********************************************************************/
- /* */
- /* Name: SynchEntryPointOpen ( */
- /* PDEVICE_OBJECT pDeviceObject */
- /* ) */
- /* */
- /* Purpose: Initialise the next device (from GetDriverSpec) */
- /* */
- /* Params: IN Context is really pDX */
- /* */
- /* Return Value:BOOLEAN: True if object opened OK */
- /* */
- /* Operation: */
- /* 1. Copy over pre-initialised data sequences */
- /* */
- /* */
- /**PROC-**********************************************************************/
-
- BOOLEAN SynchEntryPointOpen (PVOID Context)
- {
- PDX pDX = (PDX) Context;
- BOOLEAN rc;
- TRACE_EVENT (<XEO);
-
- rc = CAST (InitialiseAdapter (pDX), BOOLEAN);
- /* if OK, InitAdapter returns TRUE */
- TRACE_EVENT(XEO>);
- return (rc);
- }
-
- /*****************************************************************************/
- /* */
- /* Name TerminateAdapter */
- /* */
- /* Purpose Link Device Driver Hardware Termination. */
- /* */
- /* Does the physical termination, but leaves assigned resurces */
- /* still assigned */
- /* */
- /* Params IN pDX */
- /* */
- /* OUT Hardware is cleared down. */
- /* */
- /*****************************************************************************/
-
- void TerminateAdapter (PDX pDX)
- {
- /***************************************************************************/
- /* Reset the 8255 and 8273. */
- /***************************************************************************/
-
- IO_OUT (pDX->ADAPTERBASE + AR_8255B, A55_Reset8273On);
-
- /***************************************************************************/
- /* Documentation says use a long delay while resetting! */
- /* (but I'm blowed if I can find where it says it. Try 10 microsecs.) */
- /***************************************************************************/
-
- KeStallExecutionProcessor (10L);
-
- WR_N_DELAY (pDX->ADAPTERBASE + AR_8255B, A55_Reset8273Off);
- WR_N_DELAY (pDX->ADAPTERBASE + AR_8255B, A55_Reset8273Off);
-
- IO_OUT (pDX->ADAPTERBASE + AR_8255C, A55_ResetPortC);
-
- /***************************************************************************/
- /* Ensure that an MPCA is completely 'turned off'. */
- /***************************************************************************/
-
- if (pDX->ConfigData.MPCAModePort NE 0)
- {
- IO_OUT (pDX->ConfigData.MPCAModePort, AC_MPCAD); /* MPCAD = disable */
- TRACE_DATABYTE (Mpc, AC_MPCAD);
- }
-
- /***************************************************************************/
- /* Check whether this channel was using the DMA and clear it down. */
- /***************************************************************************/
-
- if (pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA)
- {
- StopDMA(pDX); /* stop the channel doing anything */
- pDX->GrabbedResources &= ~GRABBEDRESOURCE_GOTDMA;
- }
- }
-
- /****************************************************************************/
- /* */
- /* Name TxFSMActionAbort */
- /* */
- /* Purpose Aborts the current transmission. */
- /* */
- /* Params IN pDX. Transmitter going presumably. */
- /* */
- /* OUT Receiver started */
- /* */
- /****************************************************************************/
-
- void TxFSMActionAbort (PDX pDX)
- {
- TRACE_EVENT (TAb:);
-
- Write8273Cmd (pDX, pDX->CmdStringAbortTransmit);
-
- TRACE_EVENT (TAb;);
- }
-
- /****************************************************************************/
- /* */
- /* Name TxFSMActionEndError */
- /* */
- /* Purpose Handles Tx error conditions by recording and retrying */
- /* */
- /* Updates statistics, */
- /* Restarts the transmitter. */
- /* */
- /* Params IN pDX, 8273 result code in TxResult */
- /* */
- /* OUT Tx Stats updated, transmitter restarted */
- /* */
- /****************************************************************************/
-
- void TxFSMActionEndError (PDX pDX)
- {
- TRACE_EVENT (TEr:);
-
- /*********************************************************************/
- /* Check whether DMA is supported and kill the DMA Channel if so. */
- /*********************************************************************/
-
- if (pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA)
- {
- StopDMA (pDX);
- XASSERT (!pDX->DMAIsActive);
- }
-
- /***************************************************************************/
- /* Increment the stats count and set the flag to pulse the event */
- /***************************************************************************/
-
- pDX->pIR->StatusCount++;
- pDX->DPCAction |= DPC_ACTION_PULSE;
-
- /***************************************************************************/
- /* Basically we translate the error to an index into the stats array held */
- /* in the interface record and increment it. */
- /***************************************************************************/
-
- TRACE_DATABYTE (TEb, pDX->TxResult);
-
- if (pDX->TxResult EQ ATxR_ErrTxUnderrun)
- {
- /*************************************************************************/
- /* Check how many times we have tried to resend this frame. If this was */
- /* the third attempt then give up, otherwise try again. */
- /*************************************************************************/
-
- pDX->TxConsecutiveUnderrunCount++; /* increment count of underruns */
- if (pDX->TxConsecutiveUnderrunCount > 2)
- {
- TxFSMActionEndOK(pDX); /* forget this frame - pretend OK*/
- }
- else
- {
- TxFSMEvent (pDX, TxFSMInputStart); /* tell FSM to send again */
- }
-
- pDX->pIR->StatusArray[SA_TxUnderrun]++; /* transmitter underrun */
- }
- else if (pDX->TxResult EQ ATxR_ErrTxCTSDrop)
- {
- TxFSMActionEndOK (pDX); /* forget this frame - pretend OK*/
- pDX->pIR->StatusArray[SA_CTSDrop]++; /* clear to send dropped */
- }
- else
- {
- TxFSMActionEndOK (pDX); /* forget this frame - pretend OK*/
- pDX->pIR->StatusArray[SA_HardwareError]++;
- /* unknown result byte! */
- }
-
- TRACE_EVENT (TEr;);
- }
-
- /****************************************************************************/
- /* */
- /* Name TxFSMActionEndOK */
- /* */
- /* Purpose Frame transmission complete. */
- /* */
- /* Handles the frame transmission completion actions. */
- /* Updates the Tx buffer data. */
- /* Starts the next transmission if data is available. */
- /* */
- /* Params IN pDX */
- /* */
- /* OUT Tx Data Buffer updated */
- /* */
- /****************************************************************************/
-
- void TxFSMActionEndOK (PDX pDX)
- {
- USHORT FreedLength; /* how many bytes freed up from bufr */
-
- TRACE_EVENT (TOk:);
-
- /*********************************************************************/
- /* Check whether DMA is supported and kill the DMA Channel if so. */
- /*********************************************************************/
-
- if (pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA)
- {
- StopDMA (pDX);
- XASSERT (!pDX->DMAIsActive);
- }
-
- /*********************************************************************/
- /* Clear the count of consecutive transmitter underruns. */
- /*********************************************************************/
-
- pDX->TxConsecutiveUnderrunCount = 0;
-
- /***************************************************************************/
- /* Read the 'tail' and work out the length of the area freed up by the */
- /* completion of this transmission. Divide that by two and add it to the */
- /* 'maximum' Tx frame size on the interface. The 'max' is in fact half */
- /* the total size of the transmit buffer (with some allowance for length */
- /* words and rounding up) because the free area within the buffer can be */
- /* broken into at most two non-contiguous sections. */
- /***************************************************************************/
-
- FreedLength = CAST(MAKEUSHORT (pDX->pSendBuf[pDX->TxNextToTransmit ], \
- pDX->pSendBuf[pDX->TxNextToTransmit+1])
- + 2, /* +2 : freeing up length as well */
- USHORT);
-
- pDX->pIR->TxMaxFrSizeNow += (FreedLength + 1) / 2;
- /* making sure we round UP! */
- XTRACE_ACTION (Tz, pDX->pIR->TxMaxFrSizeNow);
-
- /***************************************************************************/
- /* Calculate the new next-to-transmit point, wrapping if necessary */
- /***************************************************************************/
-
- pDX->TxNextToTransmit += FreedLength;
- if (pDX->TxNextToTransmit >= pDX->TxStartUnusedArea)
- {
- /*************************************************************************/
- /* The last buffer we sent was the right-most in the buffer - so we must */
- /* reset the unused area and NextToTranmsit */
- /*************************************************************************/
-
- pDX->TxStartUnusedArea = SENDBUF_SIZE;
- pDX->TxNextToTransmit = 0;
- XTRACE_ACTION (Tu, pDX->TxStartUnusedArea);
- }
- XTRACE_ACTION (Tt, pDX->TxNextToTransmit);
-
-
- /***************************************************************************/
- /* Now check whether there is more data in the buffer and send it. If */
- /* there are no more frames, check whether the application has finished */
- /* the current transmission and stop the transmitter if so. */
- /***************************************************************************/
-
- if (pDX->TxNextToTransmit NE pDX->TxNextToBuffer)
- {
- TxFSMEvent (pDX, TxFSMInputStart);
- }
- else
- {
- /*************************************************************************/
- /* The buffer is empty so we need to stop the transmitter if we are half */
- /* duplex and we have indeed sent the poll/final bit (as defined in the */
- /* 'C' byte of the last transmit command (ooh, it's so tricky). */
- /*************************************************************************/
-
- if (BITSOFF(pDX->LinkOptionsByte, LinkOption_FullDuplex) &&
- pDX->CmdStringTransmit[5] & POLLFINL
- )
- {
- TxFSMEvent (pDX, TxFSMInputStop);
- }
-
- /*************************************************************************/
- /* We have to tell the DLC software when the buffer goes empty. */
- /*************************************************************************/
-
- pDX->DPCAction |= DPC_ACTION_PULSE; /* do a PULSE-EVENT from the DPC */
- }
- TRACE_EVENT (TOk;);
- }
-
- /*****************************************************************************/
- /* */
- /* Name TxFSMActionInvalid */
- /* */
- /* Purpose Error input to FSM */
- /* */
- /* This routine should never be called as it implies an */
- /* 'impossible state/input combination. This is taken to mean */
- /* that adapter status has been incorrectly reported and is */
- /* treated as a hardware error. */
- /* */
- /* Params IN pDX */
- /* */
- /* OUT Error processing started by RQ FSM input */
- /* */
- /*****************************************************************************/
-
- void TxFSMActionInvalid (PDX pDX)
- {
- TRACE_EVENT(T!!!);
- pDX->pIR->StatusArray[SA_HardwareError]++;
- pDX->pIR->StatusCount++;
- pDX->DPCAction |= DPC_ACTION_PULSE;
- }
-
- /****************************************************************************/
- /* */
- /* Name TxFSMActionStart */
- /* */
- /* Purpose Activates the Transmitter. */
- /* */
- /* Raise RTS (if not raised already). */
- /* Start flag streaming. */
- /* Stop the receiver (if not full duplex). */
- /* Initiate the first transmission. */
- /* */
- /* Params IN Data held in Device Object */
- /* */
- /* OUT Transmitter Active and Transmit command issued. */
- /* */
- /****************************************************************************/
-
- void TxFSMActionStart (PDX pDX)
- {
- TRACE_EVENT (TSt:);
- /***************************************************************************/
- /* Put the transmitter into Flag Stream mode while it is active. */
- /***************************************************************************/
-
- pDX->CmdStringSetOpMode[2] |= 1; /* turn on flag stream mode */
- Write8273Cmd (pDX, pDX->CmdStringSetOpMode);
-
- /***************************************************************************/
- /* Ensure that RTS is up. */
- /***************************************************************************/
-
- pDX->CmdStringSetPortB[2] |= 1; /* 1 = RTS line - turn it up */
- Write8273Cmd (pDX, pDX->CmdStringSetPortB);
- pDX->pIR->V24Out |= IR_OV24RTS; /* record fact that RTS is on! */
-
- /***************************************************************************/
- /* We are just starting the transmitter up. If the link is not full */
- /* duplex then stop the receiver while we are transmitting. */
- /***************************************************************************/
-
- if (BITSOFF(pDX->LinkOptionsByte, LinkOption_FullDuplex))
- {
- RxFSMEvent (pDX, RxFSMInputHold);
- }
-
- /***************************************************************************/
- /* Lastly, start the first transmission. */
- /***************************************************************************/
-
- TxFSMActionXmitNext (pDX);
- TRACE_EVENT (TSt;);
-
- }
-
- /*****************************************************************************/
- /* */
- /* Name TxFSMActionStop */
- /* */
- /* Purpose Closes down the transmitter */
- /* */
- /* Drops RTS (if 2-wire) */
- /* Stops flag stream and (if not HDLC) */
- /* Re-enables the receiver (if half duplex) */
- /* */
- /* Params IN pDX */
- /* */
- /* OUT Receiver started if HDX */
- /* */
- /*****************************************************************************/
-
- void TxFSMActionStop (PDX pDX)
- {
- TRACE_EVENT (TZap);
- /*********************************************************************/
- /* Check whether DMA is supported and kill the DMA Channel if so. */
- /*********************************************************************/
-
- if (pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA)
- {
- StopDMA (pDX);
- XASSERT (!pDX->DMAIsActive);
- }
-
- if (BITSOFF(pDX->LinkOptionsByte, LinkOption_4Wire))
- {
- /*************************************************************************/
- /* Modem 2-wire : Turn off RTS and drop it in the interface flags. */
- /*************************************************************************/
-
- pDX->CmdStringSetPortB[2] &= ~1;
- pDX->CmdStringResetPortB[2] &= ~1;
- Write8273Cmd (pDX, pDX->CmdStringResetPortB);
- pDX->pIR->V24Out &= ~IR_OV24RTS; /* tell appl that RTS is off! */
- }
-
- /*********************************************************************/
- /* Turn off Flag Stream Mode. */
- /*********************************************************************/
-
- pDX->CmdStringSetOpMode[2] &= ~1;
- pDX->CmdStringResetOpMode[2]&= ~1;
- Write8273Cmd (pDX, pDX->CmdStringResetOpMode);
-
- pDX->LastPortA = Write8273Cmd (pDX, pDX->CmdStringReadPortA);
-
- /*********************************************************************/
- /* Release the receiver if this is a half duplex link. */
- /*********************************************************************/
-
- if (BITSOFF(pDX->LinkOptionsByte, LinkOption_FullDuplex))
- {
- RxFSMEvent (pDX, RxFSMInputRelease);
- }
- }
-
- /*****************************************************************************/
- /* */
- /* Name TxFSMActionXmitNext */
- /* */
- /* Purpose Transmits the Next Frame in the Buffer */
- /* */
- /* Set up the transmit command */
- /* Set up the DMA (if used) */
- /* Issue the transmit command. */
- /* */
- /* Params IN pDX, plus xmitter already active */
- /* */
- /* NextToTransmit: +0) length of buffered frame (A+C+data) */
- /* +1) */
- /* +2 A(ddress) */
- /* +3 C(ontrol) */
- /* */
- /* Total buffer taken up is Length + 2. */
- /* */
- /* OUT Transmission under way. */
- /* */
- /*****************************************************************************/
-
- void TxFSMActionXmitNext (PDX pDX)
- {
- USHORT LengthFor8273;
- UCHAR *p;
- UCHAR TempLo;
- UCHAR TempHi;
-
- TRACE_EVENT (TSn:);
-
- /***************************************************************************/
- /* Before issuing the transmit command, read in the current Port A value */
- /* as we won't be able to if both the transmitter and receiver become */
- /* active concurrently. */
- /***************************************************************************/
-
- pDX->LastPortA = Write8273Cmd (pDX, pDX->CmdStringReadPortA);
-
- /***************************************************************************/
- /* Read the current tail position and check for a buffer wrap (tail = */
- /* current length of buffer). */
- /***************************************************************************/
-
- if (pDX->TxNextToTransmit >= pDX->TxStartUnusedArea)
- {
- /*************************************************************************/
- /* The last buffer we sent was the right-most in the buffer - so we must */
- /* reset the unused area and NextToTranmsit */
- /*************************************************************************/
-
- pDX->TxStartUnusedArea = SENDBUF_SIZE;
- pDX->TxNextToTransmit = 0;
- XTRACE_ACTION (Tu, pDX->TxStartUnusedArea);
- XTRACE_ACTION (Tt, pDX->TxNextToTransmit);
- }
-
- /***************************************************************************/
- /* Found the next frame - read its length and set up Tx Command. */
- /***************************************************************************/
-
- p = &pDX->pSendBuf[pDX->TxNextToTransmit];
- TempLo = *(p++); /* first two bytes are length*/
- TempHi = *(p++);
- LengthFor8273 = CAST (TempLo + (TempHi <<8)-2,/* allow for the buffered A+C*/
- USHORT);
-
- ASSERT (CAST(LengthFor8273, int ) < pDX->LinkMaxFrameSize);
- ASSERT (CAST(LengthFor8273, short) >= 0);
-
- pDX->CmdStringTransmit[2] = LOBYTE(LengthFor8273);
- /* and put it into the cmd */
- pDX->CmdStringTransmit[3] = HIBYTE(LengthFor8273);
-
- /***************************************************************************/
- /* and set up the (buffered) A & C in the command */
- /***************************************************************************/
-
- TRC_IN_DW (*p);
- pDX->CmdStringTransmit[4] = *(p++); /* next two bytes are A&C */
- pDX->CmdStringTransmit[5] = *(p++);
-
- pDX->pTxPIOData = p; /* next is PIO data start pos*/
- TRACE_EVENT (TPIO);
- TRACE_DWORD (pDX->pTxPIOData);
-
- /***************************************************************************/
- /* Now prime the DMA if necessary */
- /***************************************************************************/
-
- if (pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA)
- {
- PHYSICAL_ADDRESS L;
- if (pDX->DMAIsActive)
- {
- StopDMA (pDX);
- XASSERT (!pDX->DMAIsActive);
- }
-
-
- L = pDX->SendBufPhysAddr;
- L.LowPart += pDX->TxNextToTransmit + 4;
-
- StartDMA(pDX,
- L,
- LengthFor8273, /* but 8273 will control how many snt*/
- DMACmdRead /* set the mode */
- );
- XASSERT (pDX->DMAIsActive);
- }
-
- /******************************************************************/
- /* Lastly, issue the transmit command to the 8273. */
- /******************************************************************/
-
- Write8273Cmd (pDX, pDX->CmdStringTransmit);
-
- TRACE_EVENT (TSn;);
- }
-
- /****************************************************************************/
- /* */
- /* Name TxFSMEvent */
- /* */
- /* Purpose Interprets inputs from the Request handlers and from the */
- /* ISR and calls the relevant action routines. */
- /* */
- /* Params IN pDX, and FSM input */
- /* */
- /* OUT Action routine called and new state set. */
- /* */
- /****************************************************************************/
-
- void TxFSMEvent (PDX pDX, int Input)
- {
- TXFSMENTRY *e = &TxFSM [Input] [pDX->TxFSMCurState];
-
- /***************************************************************************/
- /* The FSM consists of a 'state' which is actually the address of the */
- /* current FSM 'column'. The 'input' is an offset down the column at */
- /* which is located an action routine address and a new state. */
- /***************************************************************************/
-
- TRACE_EVENT (<TFE);
-
- ASSERT (pDX->TxFSMCurState < TXFSMSTATECOUNT);
- ASSERT (Input < TXFSMINPUTCOUNT);
- TRACE_EVENTNAME(TxFSMStateNames[pDX->TxFSMCurState]);
- TRACE_EVENTNAME(TxFSMInputNames[Input]);
-
- /***************************************************************************/
- /* Reset the state to the new state specified in the FSM table */
- /* (Important to do this before the actions because some of them then do */
- /* recursive calls to FSMEvent */
- /***************************************************************************/
-
- pDX->TxFSMCurState = e->NewState;
- ASSERT (e->NewState < TXFSMSTATECOUNT);
- TRACE_EVENTNAME(TxFSMStateNames[pDX->TxFSMCurState]);
-
- (*(e->pTxActionRoutine)) (pDX);
-
- TRACE_EVENT (TFE>);
-
- }
-
- /**PROC+**********************************************************************/
- /* */
- /* Name Write8273Cmd ( */
- /* PDX pDX */
- /* UCHAR *Cmd; */
- /* ); */
- /* */
- /* Purpose Send out a command array (in <cmd>, <length>, <params> format*/
- /* */
- /* Params IN pDX - the device extension */
- /* IN Cmd - ptr to first char of command */
- /* */
- /* Return Value If command is READ 8273 PORT A/B return value read, otherwise*/
- /* return value is meaningless. */
- /* */
- /* Operation None */
- /* */
- /* Notes 1. <length> may be 0 */
- /* 2. Write8273Cmd (OS/2 DD precursor of this routine used to */
- /* return carry on error. We don't bother as this was only */
- /* check in one place. */
- /* */
- /**PROC-**********************************************************************/
-
- UCHAR Write8273Cmd (PDX pDX, UCHAR *Cmd)
- {
- int ParameterCount;
- UCHAR Result = 0;
-
- TRACE_EVENT (<Cmd);
- TRACE_CHAR (*Cmd); /* trace command and first 3 params */
- TRACE_CHAR (*(Cmd+2));
- TRACE_CHAR (*(Cmd+3));
- TRACE_CHAR (*(Cmd+4));
-
- WAITUNTIL(pDX,AS_CMBSY|AS_CMBFF,EQ,0);/* wait for busy and full to go off */
- if (pDX->HardwareError) /* stop if previous error or error */
- return(0); /* this time */
-
- IO_OUT (pDX->ADAPTERBASE+AR_8273S, /* status reg also command register */
- *Cmd++); /* command is first byte */
-
- if (*(Cmd-1) EQ 0x22 || *(Cmd-1) EQ 0x23)
- { /* what we sent out was Read Port A/B*/
- WAITUNTIL(pDX,AS_CRBFF,EQ,AS_CRBFF);/* wait for result buff full to go on*/
- Result = IO_IN (pDX->ADAPTERBASE+AR_8273P);
- }
- ParameterCount = *(Cmd++); /* parameter count is next */
- while (ParameterCount--)
- {
- WAITUNTIL (pDX, /* wait for busy to go on, but */
- (AS_CMBSY|AS_CMBFF|AS_CPBFF), /* command and param buffs are clear */
- EQ, AS_CMBSY);
-
- IO_OUT (pDX->ADAPTERBASE+AR_8273P, /* write params to parameter port */
- (UCHAR)*(Cmd++));
- }
-
- TRACE_EVENT (Cmd>);
- return(Result);
- }
-
- /*****************************************************************************/
- /* */
- /* Name LogDriverError */
- /* */
- /* Purpose Allocates an error log entry, copies over the given info */
- /* and writes it to the error log file. */
- /* */
- /* Params IN pDeviceObject */
- /* IN FinalStatus : NT Status returned to calling service */
- /* IN UniqueErrorValue : bottom word is the resource message id */
- /* IN MajorFunctionCode : for the current Irp */
- /* IN IoControlCode : Ioctl code */
- /* */
- /*****************************************************************************/
-
- VOID LogDriverError (
- PDEVICE_OBJECT pDeviceObject,
- NTSTATUS FinalStatus,
- ULONG UniqueErrorValue,
- UCHAR MajorFunctionCode,
- ULONG IoControlCode
- )
- {
- PIO_ERROR_LOG_PACKET ErrorLogEntry;
-
- TRACE_EVENT (<LDE);
-
- ErrorLogEntry = IoAllocateErrorLogEntry(
- pDeviceObject,
- (UCHAR)sizeof(IO_ERROR_LOG_PACKET)
- );
-
- if (ErrorLogEntry NE NULL)
- {
- ErrorLogEntry->ErrorCode = UniqueErrorValue;
-
- ErrorLogEntry->FinalStatus = FinalStatus;
- ErrorLogEntry->UniqueErrorValue = UniqueErrorValue;
- ErrorLogEntry->MajorFunctionCode = MajorFunctionCode;
- ErrorLogEntry->IoControlCode = IoControlCode;
-
- ErrorLogEntry->SequenceNumber = pDeviceObject->ReferenceCount;
-
- IoWriteErrorLogEntry(ErrorLogEntry);
- }
-
- TRACE_EVENT (LDE>);
- }
-
-
- /*****************************************************************************/
- /* Notes. */
- /* */
- /* 1. The OS/2 device driver registers the MPA interrupt 3 as exclusive but */
- /* then shares it internally. We can't do this unfortunately on NT because */
- /* IoConnectInterrupt requires the device object as a parameter. We will */
- /* therefore have to register MPAA interrupts as shared. The problem with */
- /* the shared interrupts on OS/2 was that phantom interrupts could be */
- /* generated (and, because we didn't have to service any cards, the */
- /* interrupt request stayed asserted). As NT is well-designed and tested, */
- /* this won't occur so we can use shared interrupts. */
- /* */
- /* 2. Should we action receive results immediately? As background, we do */
- /* action all events immediately except for Transmitter results which are */
- /* passed to the DPC routine. NT religious dogma says we should not action */
- /* the rx result immediately either, but pass them to the DPC routine. The */
- /* danger in doing this is that we will miss the start of the next frame. */
- /* This isn't a problem in DMA, because we're just letting it rip. But in */
- /* PIO mode, we can be some while getting to restart the receiver if we drop */
- /* down to DPC level. So... action al rx interrupts immediately. */
- /* */
- /* */
- /*****************************************************************************/
-
-
- //on termination, unlock any locked memory and free the MDLs (e.g.
- //InterfaceRecordMdl)
- //
- //need to initialise InterfaceRecordMdl = NULL