Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

762 lines
24 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. ioctl.c
  5. Abstract:
  6. This is the main file for handling DevIOCtl calls for AsyncMAC.
  7. This driver conforms to the NDIS 3.0 interface.
  8. Author:
  9. Thomas J. Dimitri (TommyD) 08-May-1992
  10. Environment:
  11. Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
  12. Revision History:
  13. --*/
  14. #include "asyncall.h"
  15. #ifdef NDIS_NT
  16. #include <ntiologc.h>
  17. #endif
  18. // asyncmac.c will define the global parameters.
  19. VOID
  20. AsyncSendLineUp(
  21. PASYNC_INFO pInfo
  22. )
  23. {
  24. PASYNC_ADAPTER pAdapter = pInfo->Adapter;
  25. NDIS_MAC_LINE_UP MacLineUp;
  26. //
  27. // divide the baud by 100 because NDIS wants it in 100s of bits per sec
  28. //
  29. MacLineUp.LinkSpeed = pInfo->LinkSpeed / 100;
  30. MacLineUp.Quality = pInfo->QualOfConnect;
  31. MacLineUp.SendWindow = ASYNC_WINDOW_SIZE;
  32. MacLineUp.ConnectionWrapperID = pInfo;
  33. MacLineUp.NdisLinkHandle = pInfo;
  34. MacLineUp.NdisLinkContext = pInfo->NdisLinkContext;
  35. //
  36. // Tell the transport above (or really RasHub) that the connection
  37. // is now up. We have a new link speed, frame size, quality of service
  38. //
  39. NdisMIndicateStatus(pAdapter->MiniportHandle,
  40. NDIS_STATUS_WAN_LINE_UP, // General Status.
  41. &MacLineUp, // (baud rate in 100 bps).
  42. sizeof(NDIS_MAC_LINE_UP));
  43. //
  44. // Get the next binding (in case of multiple bindings like BloodHound)
  45. //
  46. pInfo->NdisLinkContext = MacLineUp.NdisLinkContext;
  47. }
  48. NTSTATUS
  49. AsyncIOCtlRequest(
  50. IN PIRP pIrp,
  51. IN PIO_STACK_LOCATION pIrpSp
  52. )
  53. /*++
  54. Routine Description:
  55. This routine takes an irp and checks to see if the IOCtl
  56. is a valid one. If so, it performs the IOCtl and returns
  57. any errors in the process.
  58. Return Value:
  59. The function value is the final status of the IOCtl.
  60. --*/
  61. {
  62. NTSTATUS status;
  63. ULONG funcCode;
  64. PVOID pBufOut;
  65. ULONG InBufLength, OutBufLength;
  66. NDIS_HANDLE hNdisEndPoint;
  67. PASYMAC_CLOSE pCloseStruct;
  68. PASYMAC_OPEN pOpenStruct;
  69. PASYMAC_DCDCHANGE pDCDStruct;
  70. PASYNC_ADAPTER Adapter;
  71. LARGE_INTEGER li ;
  72. //
  73. // Initialize locals.
  74. //
  75. status = STATUS_SUCCESS;
  76. //
  77. // Initialize the I/O Status block
  78. //
  79. InBufLength = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
  80. OutBufLength = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  81. funcCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode;
  82. //
  83. // Validate the function code
  84. //
  85. #ifdef MY_DEVICE_OBJECT
  86. if ( (funcCode >> 16) != FILE_DEVICE_ASYMAC ) {
  87. return STATUS_INVALID_PARAMETER;
  88. }
  89. #else
  90. if ( (funcCode >> 16) != FILE_DEVICE_NETWORK ) {
  91. return STATUS_INVALID_PARAMETER;
  92. }
  93. #endif
  94. //
  95. // Get a quick ptr to the IN/OUT SystemBuffer
  96. //
  97. pBufOut = pIrp->AssociatedIrp.SystemBuffer;
  98. switch ( funcCode ) {
  99. case IOCTL_ASYMAC_OPEN:
  100. DbgTracef(0,("AsyncIOCtlRequest: IOCTL_ASYMAC_OPEN.\n"));
  101. pIrp->IoStatus.Information = sizeof(ASYMAC_OPEN);
  102. if (InBufLength >= sizeof(ASYMAC_OPEN) &&
  103. OutBufLength >= sizeof(ASYMAC_OPEN)) {
  104. pOpenStruct = pBufOut;
  105. } else {
  106. status = STATUS_INFO_LENGTH_MISMATCH;
  107. }
  108. break;
  109. case IOCTL_ASYMAC_CLOSE:
  110. DbgTracef(0,("AsyncIOCtlRequest: IOCTL_ASYMAC_CLOSE\n"));
  111. if ( InBufLength >= sizeof(ASYMAC_CLOSE) ) {
  112. pCloseStruct = pBufOut;
  113. } else {
  114. status = STATUS_INFO_LENGTH_MISMATCH;
  115. }
  116. break;
  117. case IOCTL_ASYMAC_TRACE:
  118. #if DBG
  119. DbgPrint("AsyncIOCtlRequest: IOCTL_ASYMAC_TRACE.\n");
  120. if ( InBufLength >= sizeof(TraceLevel) ) {
  121. CHAR *pTraceLevel=pBufOut;
  122. TraceLevel=*pTraceLevel;
  123. } else {
  124. status = STATUS_INFO_LENGTH_MISMATCH;
  125. }
  126. #endif
  127. return status;
  128. break;
  129. case IOCTL_ASYMAC_DCDCHANGE:
  130. DbgTracef(0,("AsyncIOCtlRequest: IOCTL_ASYMAC_DCDCHANGE.\n"));
  131. if ( InBufLength >= sizeof(ASYMAC_DCDCHANGE) ) {
  132. pDCDStruct = pBufOut;
  133. } else {
  134. status = STATUS_INFO_LENGTH_MISMATCH;
  135. }
  136. break;
  137. default:
  138. status = STATUS_INVALID_DEVICE_REQUEST;
  139. }
  140. //
  141. // Check if we already have an error (like STATUS_INFO_LENGTH_MISMATCH).
  142. //
  143. if ( status != STATUS_SUCCESS ) {
  144. return status;
  145. }
  146. //
  147. // Since most of IOCTL structs are similar
  148. // we get the Adapter and hNdisEndPoint here using
  149. // the StatsStruct (we could several of them)
  150. //
  151. pOpenStruct = pBufOut;
  152. hNdisEndPoint = pOpenStruct->hNdisEndpoint;
  153. //
  154. // No error yet, let's go ahead and grab the global lock...
  155. //
  156. if ((Adapter = GlobalAdapter) == NULL ) {
  157. return ASYNC_ERROR_NO_ADAPTER;
  158. }
  159. // there's a race condition right here that I am
  160. // not bothering to get rid of because it would
  161. // require the removal of this adapter in between
  162. // here (which is, for all intensive purposes, impossible).
  163. // Hmm... now that we have the lock we can do stuff
  164. NdisAcquireSpinLock(&Adapter->Lock);
  165. // Here we do the real work for the function call
  166. switch ( funcCode ) {
  167. case IOCTL_ASYMAC_OPEN:
  168. {
  169. PASYNC_INFO pNewInfo = NULL;
  170. USHORT i;
  171. PDEVICE_OBJECT deviceObject;
  172. PFILE_OBJECT fileObject;
  173. OBJECT_HANDLE_INFORMATION handleInformation;
  174. //
  175. // Get a new AsyncInfo
  176. //
  177. pNewInfo = (PASYNC_INFO)
  178. ExAllocateFromNPagedLookasideList(&AsyncInfoList);
  179. //
  180. // Check if we could not find an open port
  181. //
  182. if ( pNewInfo == NULL ) {
  183. NdisReleaseSpinLock(&Adapter->Lock);
  184. return ASYNC_ERROR_NO_PORT_AVAILABLE;
  185. }
  186. RtlZeroMemory(pNewInfo, sizeof(ASYNC_INFO));
  187. pNewInfo->Adapter = Adapter;
  188. status =
  189. AsyncGetFrameFromPool(pNewInfo, &pNewInfo->AsyncFrame);
  190. if (status != NDIS_STATUS_SUCCESS) {
  191. ExFreeToNPagedLookasideList(&AsyncInfoList, pNewInfo);
  192. NdisReleaseSpinLock(&Adapter->Lock);
  193. return ASYNC_ERROR_NO_PORT_AVAILABLE;
  194. }
  195. KeInitializeEvent(&pNewInfo->DetectEvent,
  196. SynchronizationEvent,
  197. TRUE);
  198. // increment the reference count (don't kill this adapter)
  199. InterlockedIncrement(&Adapter->RefCount);
  200. // release spin lock so we can do some real work.
  201. NdisReleaseSpinLock(&Adapter->Lock);
  202. //
  203. // Reference the file object so the target device can be found and
  204. // the access rights mask can be used in the following checks for
  205. // callers in user mode. Note that if the handle does not refer to
  206. // a file object, then it will fail.
  207. //
  208. status = ObReferenceObjectByHandle(pOpenStruct->FileHandle,
  209. FILE_READ_DATA | FILE_WRITE_DATA,
  210. *IoFileObjectType,
  211. UserMode,
  212. (PVOID) &fileObject,
  213. &handleInformation);
  214. if (!NT_SUCCESS(status)) {
  215. pNewInfo->PortState = PORT_CLOSED;
  216. NdisAcquireSpinLock(&Adapter->Lock);
  217. // RemoveEntryList(&pNewInfo->Linkage);
  218. ExFreeToNPagedLookasideList(&Adapter->AsyncFrameList,
  219. pNewInfo->AsyncFrame);
  220. NdisReleaseSpinLock(&Adapter->Lock);
  221. ExFreeToNPagedLookasideList(&AsyncInfoList,
  222. pNewInfo);
  223. return ASYNC_ERROR_NO_PORT_AVAILABLE;
  224. }
  225. //
  226. // Init the portinfo block
  227. //
  228. InitializeListHead(&pNewInfo->DDCDQueue);
  229. // Ok, we've gotten this far. We have a port.
  230. // Own port, and check params...
  231. // Nothing can be done to the port until it comes
  232. // out of the PORT_OPENING state.
  233. pNewInfo->PortState = PORT_OPENING;
  234. NdisAllocateSpinLock(&pNewInfo->Lock);
  235. //
  236. // Get the address of the target device object. Note that this was already
  237. // done for the no intermediate buffering case, but is done here again to
  238. // speed up the turbo write path.
  239. //
  240. deviceObject = IoGetRelatedDeviceObject(fileObject);
  241. ObReferenceObject(deviceObject);
  242. // ok, we have a VALID handle of *something*
  243. // we do NOT assume that the handle is anything
  244. // in particular except a device which accepts
  245. // non-buffered IO (no MDLs) Reads and Writes
  246. // set new info...
  247. pNewInfo->Handle = pOpenStruct->FileHandle;
  248. //
  249. // Tuck away link speed for line up
  250. // and timeouts
  251. //
  252. pNewInfo->LinkSpeed = pOpenStruct->LinkSpeed;
  253. //
  254. // Return endpoint to RASMAN
  255. //
  256. pOpenStruct->hNdisEndpoint =
  257. pNewInfo->hNdisEndPoint = pNewInfo;
  258. // Get parameters set from Registry and return our capabilities
  259. pNewInfo->QualOfConnect = pOpenStruct->QualOfConnect;
  260. pNewInfo->PortState = PORT_FRAMING;
  261. pNewInfo->FileObject = fileObject;
  262. pNewInfo->DeviceObject = deviceObject;
  263. pNewInfo->NdisLinkContext = NULL;
  264. //
  265. // Initialize the NDIS_WAN_GET_LINK_INFO structure.
  266. //
  267. pNewInfo->GetLinkInfo.MaxSendFrameSize = DEFAULT_PPP_MAX_FRAME_SIZE;
  268. pNewInfo->GetLinkInfo.MaxRecvFrameSize = DEFAULT_PPP_MAX_FRAME_SIZE;
  269. pNewInfo->GetLinkInfo.HeaderPadding = DEFAULT_PPP_MAX_FRAME_SIZE;
  270. pNewInfo->GetLinkInfo.TailPadding = 4;
  271. pNewInfo->GetLinkInfo.SendFramingBits = PPP_FRAMING;
  272. pNewInfo->GetLinkInfo.RecvFramingBits = PPP_FRAMING;
  273. pNewInfo->GetLinkInfo.SendCompressionBits = 0;
  274. pNewInfo->GetLinkInfo.RecvCompressionBits = 0;
  275. pNewInfo->GetLinkInfo.SendACCM = (ULONG) -1;
  276. pNewInfo->GetLinkInfo.RecvACCM = (ULONG) -1;
  277. ASYNC_ZERO_MEMORY(&(pNewInfo->SerialStats), sizeof(SERIAL_STATS));
  278. NdisAcquireSpinLock(&Adapter->Lock);
  279. InsertHeadList(&Adapter->ActivePorts, &pNewInfo->Linkage);
  280. NdisReleaseSpinLock(&Adapter->Lock);
  281. //
  282. // Send a line up to the WAN wrapper.
  283. //
  284. AsyncSendLineUp(pNewInfo);
  285. //
  286. // We send a special IRP to the serial driver to set it in RAS friendly mode
  287. // where it will not complete write requests until the packet has been transmitted
  288. // on the wire. This is mostly important in case of intelligent controllers.
  289. //
  290. pNewInfo->WaitMaskToUse =
  291. (SERIAL_EV_RXFLAG | SERIAL_EV_RLSD | SERIAL_EV_DSR |
  292. SERIAL_EV_RX80FULL | SERIAL_EV_ERR) ;
  293. {
  294. NTSTATUS status;
  295. PASYNC_IO_CTX AsyncIoCtx;
  296. PIRP irp;
  297. irp =
  298. IoAllocateIrp(pNewInfo->DeviceObject->StackSize, (BOOLEAN)FALSE);
  299. if (irp != NULL) {
  300. AsyncIoCtx = AsyncAllocateIoCtx(TRUE, pNewInfo);
  301. if (AsyncIoCtx == NULL) {
  302. IoFreeIrp(irp);
  303. irp = NULL;
  304. }
  305. }
  306. if (irp != NULL) {
  307. #define IOCTL_SERIAL_PRIVATE_RAS CTL_CODE(FILE_DEVICE_SERIAL_PORT,4000,METHOD_BUFFERED,FILE_ANY_ACCESS)
  308. InitSerialIrp(irp,
  309. pNewInfo,
  310. IOCTL_SERIAL_PRIVATE_RAS,
  311. sizeof(ULONG));
  312. AsyncIoCtx->WriteBufferingEnabled =
  313. Adapter->WriteBufferingEnabled;
  314. irp->AssociatedIrp.SystemBuffer=
  315. &AsyncIoCtx->WriteBufferingEnabled;
  316. IoSetCompletionRoutine(irp, // irp to use
  317. SerialIoSyncCompletionRoutine, // routine to call when irp is done
  318. AsyncIoCtx, // context to pass routine
  319. TRUE, // call on success
  320. TRUE, // call on error
  321. TRUE); // call on cancel
  322. // Now simply invoke the driver at its dispatch entry with the IRP.
  323. //
  324. KeClearEvent(&AsyncIoCtx->Event);
  325. status = IoCallDriver(pNewInfo->DeviceObject, irp);
  326. if (status == STATUS_PENDING) {
  327. KeWaitForSingleObject(&AsyncIoCtx->Event,
  328. Executive,
  329. KernelMode,
  330. FALSE,
  331. NULL);
  332. status = AsyncIoCtx->IoStatus.Status;
  333. }
  334. IoFreeIrp(irp);
  335. AsyncFreeIoCtx(AsyncIoCtx);
  336. if (status == STATUS_SUCCESS) {
  337. //
  338. // this means that the driver below is DIGI. we should disable setting of the EV_ERR
  339. // flags in this case.
  340. //
  341. pNewInfo->WaitMaskToUse &= ~SERIAL_EV_ERR;
  342. }
  343. }
  344. }
  345. //
  346. // Start the detect framing out with a 6 byte read to get the header
  347. //
  348. pNewInfo->BytesWanted=6;
  349. pNewInfo->BytesRead=0;
  350. //
  351. // Start reading.
  352. //
  353. AsyncStartReads(pNewInfo);
  354. if (NdisInterlockedIncrement(&glConnectionCount) == 1) {
  355. ObReferenceObject(AsyncDeviceObject);
  356. }
  357. break;
  358. }
  359. case IOCTL_ASYMAC_TRACE:
  360. NdisReleaseSpinLock(&Adapter->Lock);
  361. status = STATUS_SUCCESS;
  362. break;
  363. case IOCTL_ASYMAC_CLOSE:
  364. case IOCTL_ASYMAC_DCDCHANGE:
  365. {
  366. PASYNC_INFO pNewInfo; // ptr to open port if found
  367. USHORT i;
  368. PLIST_ENTRY pListEntry;
  369. BOOLEAN Valid = FALSE;
  370. switch (funcCode) {
  371. case IOCTL_ASYMAC_CLOSE:
  372. {
  373. NDIS_MAC_LINE_DOWN AsyncLineDown;
  374. pNewInfo = (PASYNC_INFO)pCloseStruct->hNdisEndpoint;
  375. // Verify that the pointer is a valid ASYNC_INFO
  376. for (pListEntry=Adapter->ActivePorts.Flink;
  377. pListEntry!=&Adapter->ActivePorts;
  378. pListEntry=pListEntry->Flink)
  379. {
  380. if (&pNewInfo->Linkage==pListEntry)
  381. {
  382. Valid = TRUE;
  383. break;
  384. }
  385. }
  386. if (!Valid) {
  387. status=ASYNC_ERROR_PORT_NOT_FOUND;
  388. break;
  389. }
  390. // release spin lock so we can do some real work.
  391. NdisReleaseSpinLock(&Adapter->Lock);
  392. NdisAcquireSpinLock(&pNewInfo->Lock);
  393. // ASSERT(pNewInfo->PortState == PORT_FRAMING);
  394. if(pNewInfo->PortState != PORT_FRAMING)
  395. {
  396. KdPrint(("AsyncIOCtlRequest: IOCTL_ASYMAC_CLOSE."));
  397. KdPrint(("PortState = %d != PORT_FRAMING\n", pNewInfo->PortState));
  398. NdisReleaseSpinLock(&pNewInfo->Lock);
  399. return ASYNC_ERROR_PORT_BAD_STATE;
  400. // break;
  401. }
  402. AsyncLineDown.NdisLinkContext = pNewInfo->NdisLinkContext;
  403. // Signal that port is closing.
  404. pNewInfo->PortState = PORT_CLOSING;
  405. //Set MUTEX to wait on
  406. KeInitializeEvent(&pNewInfo->ClosingEvent, // Event
  407. SynchronizationEvent, // Event type
  408. (BOOLEAN)FALSE); // Not signalled state
  409. NdisReleaseSpinLock(&pNewInfo->Lock);
  410. //
  411. // If we have an outstanding Detect worker
  412. // wait for it to complete!
  413. //
  414. KeWaitForSingleObject(&pNewInfo->DetectEvent,
  415. UserRequest,
  416. KernelMode,
  417. FALSE,
  418. NULL);
  419. //
  420. // now we must send down an IRP do cancel
  421. // any request pending in the serial driver
  422. //
  423. CancelSerialRequests(pNewInfo);
  424. //
  425. // Also, cancel any outstanding DDCD irps
  426. //
  427. AsyncCancelAllQueued(&pNewInfo->DDCDQueue);
  428. // Synchronize closing with the read irp
  429. li.LowPart = 5000 ;
  430. li.HighPart = 0 ;
  431. if (KeWaitForSingleObject (&pNewInfo->ClosingEvent,// PVOID Object,
  432. UserRequest, // KWAIT_REASON WaitReason,
  433. KernelMode, // KPROCESSOR_MODE WaitMode,
  434. (BOOLEAN)FALSE, // BOOLEAN Alertable,
  435. &li) == STATUS_TIMEOUT) {
  436. // If the wait fails cause another flush
  437. //
  438. NTSTATUS status;
  439. PIRP irp;
  440. PASYNC_IO_CTX AsyncIoCtx;
  441. irp=
  442. IoAllocateIrp(pNewInfo->DeviceObject->StackSize, (BOOLEAN)FALSE);
  443. if (irp == NULL)
  444. goto DEREF ;
  445. AsyncIoCtx = AsyncAllocateIoCtx(TRUE, pNewInfo);
  446. if (AsyncIoCtx == NULL) {
  447. IoFreeIrp(irp);
  448. goto DEREF;
  449. }
  450. InitSerialIrp(irp,
  451. pNewInfo,
  452. IOCTL_SERIAL_PURGE,
  453. sizeof(ULONG));
  454. // kill all read and write threads.
  455. AsyncIoCtx->SerialPurge =
  456. SERIAL_PURGE_TXABORT | SERIAL_PURGE_RXABORT;
  457. irp->AssociatedIrp.SystemBuffer=
  458. &AsyncIoCtx->SerialPurge;
  459. IoSetCompletionRoutine(irp, // irp to use
  460. SerialIoSyncCompletionRoutine, // routine to call when irp is done
  461. AsyncIoCtx, // context to pass routine
  462. TRUE, // call on success
  463. TRUE, // call on error
  464. TRUE); // call on cancel
  465. // Now simply invoke the driver at its dispatch entry with the IRP.
  466. //
  467. KeClearEvent(&AsyncIoCtx->Event);
  468. status = IoCallDriver(pNewInfo->DeviceObject, irp);
  469. if (status == STATUS_PENDING) {
  470. KeWaitForSingleObject(&AsyncIoCtx->Event,
  471. Executive,
  472. KernelMode,
  473. FALSE,
  474. NULL);
  475. status = AsyncIoCtx->IoStatus.Status;
  476. }
  477. IoFreeIrp(irp);
  478. AsyncFreeIoCtx(AsyncIoCtx);
  479. // if we do hit this code - wait for some time to let
  480. // the read complete
  481. //
  482. KeDelayExecutionThread (KernelMode, FALSE, &li) ;
  483. }
  484. //
  485. // Get rid of our reference to the serial port
  486. //
  487. DEREF:
  488. ObDereferenceObject(pNewInfo->DeviceObject);
  489. ObDereferenceObject(pNewInfo->FileObject);
  490. NdisMIndicateStatus(Adapter->MiniportHandle,
  491. NDIS_STATUS_WAN_LINE_DOWN, // General Status
  492. &AsyncLineDown, // Specific Status
  493. sizeof(NDIS_MAC_LINE_DOWN));
  494. // reacquire spin lock
  495. NdisAcquireSpinLock(&Adapter->Lock);
  496. RemoveEntryList(&pNewInfo->Linkage);
  497. // decrement the reference count because we're done.
  498. InterlockedDecrement(&Adapter->RefCount);
  499. pNewInfo->PortState = PORT_CLOSED;
  500. NdisFreeSpinLock(&pNewInfo->Lock);
  501. ExFreeToNPagedLookasideList(&Adapter->AsyncFrameList,
  502. pNewInfo->AsyncFrame);
  503. ExFreeToNPagedLookasideList(&AsyncInfoList,
  504. pNewInfo);
  505. if (NdisInterlockedDecrement(&glConnectionCount) == 0) {
  506. ObDereferenceObject(AsyncDeviceObject);
  507. }
  508. break; // get out of case statement
  509. }
  510. case IOCTL_ASYMAC_DCDCHANGE:
  511. pNewInfo = (PASYNC_INFO)pDCDStruct->hNdisEndpoint;
  512. // Verify that the pointer is a valid ASYNC_INFO
  513. for (pListEntry=Adapter->ActivePorts.Flink;
  514. pListEntry!=&Adapter->ActivePorts;
  515. pListEntry=pListEntry->Flink)
  516. {
  517. if (&pNewInfo->Linkage==pListEntry)
  518. {
  519. Valid = TRUE;
  520. break;
  521. }
  522. }
  523. //
  524. // If the port is already closed, we WILL complain
  525. //
  526. if (!Valid || pNewInfo->PortState == PORT_CLOSED) {
  527. status=ASYNC_ERROR_PORT_NOT_FOUND;
  528. break;
  529. }
  530. //
  531. // If any irps are pending, cancel all of them
  532. // Only one irp can be outstanding at a time.
  533. //
  534. AsyncCancelAllQueued(&pNewInfo->DDCDQueue);
  535. DbgTracef(0, ("ASYNC: Queueing up DDCD IRP\n"));
  536. AsyncQueueIrp(&pNewInfo->DDCDQueue, pIrp);
  537. //
  538. // we'll have to wait for the SERIAL driver
  539. // to flip DCD or DSR
  540. //
  541. status=STATUS_PENDING;
  542. break;
  543. } // end switch
  544. NdisReleaseSpinLock(&Adapter->Lock);
  545. return(status);
  546. }
  547. break;
  548. } // end switch
  549. return status;
  550. }