Leaked source code of windows server 2003
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.

1152 lines
30 KiB

  1. /* ++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. wceusbsh.c
  5. Abstract:
  6. Main entrypoint for Windows CE USB Serial Host driver, for
  7. ... Windows CE USB sync devices:
  8. SL11, Socket CF cards, HP Jornada, COMPAQ iPAQ, Casio Cassiopeia, etc.
  9. ... cables using the Anchor AN27x0 chipset (i.e. EZ-Link)
  10. ... ad-hoc USB NULL Modem Class
  11. Environment:
  12. kernel mode only
  13. Author:
  14. Jeff Midkiff (jeffmi)
  15. Revision History:
  16. 07-15-99 : rev 1.00 ActiveSync 3.1 initial release
  17. 04-20-00 : rev 1.01 Cedar 3.0 Platform Builder
  18. 09-20-00 : rev 1.02 finally have some hardware
  19. Notes:
  20. o) WCE Devices currently do not handle remote wake, nor can we put the device in power-off state when not used, etc.
  21. o) Pageable Code sections are marked as follows:
  22. PAGEWCE0 - useable only during init/deinit
  23. PAGEWCE1 - useable during normal runtime
  24. -- */
  25. #include "wceusbsh.h"
  26. //
  27. // This is currently missing from wdm.h,
  28. // but IoUnregisterShutdownNotification is there
  29. //
  30. #if !defined( IoRegisterShutdownNotification )
  31. NTKERNELAPI
  32. NTSTATUS
  33. IoRegisterShutdownNotification(
  34. IN PDEVICE_OBJECT DeviceObject
  35. );
  36. #endif
  37. NTSTATUS
  38. Create(
  39. IN PDEVICE_OBJECT PDevObj,
  40. IN PIRP PIrp
  41. );
  42. NTSTATUS
  43. Close(
  44. IN PDEVICE_OBJECT PDevObj,
  45. IN PIRP PIrp
  46. );
  47. NTSTATUS
  48. Cleanup(
  49. IN PDEVICE_OBJECT DeviceObject,
  50. IN PIRP Irp
  51. );
  52. VOID
  53. Unload(
  54. IN PDRIVER_OBJECT DriverObject
  55. );
  56. NTSTATUS
  57. SetInformationFile(
  58. IN PDEVICE_OBJECT DeviceObject,
  59. IN PIRP Irp
  60. );
  61. NTSTATUS
  62. QueryInformationFile(
  63. IN PDEVICE_OBJECT DeviceObject,
  64. IN PIRP Irp
  65. );
  66. NTSTATUS
  67. Flush(
  68. IN PDEVICE_OBJECT DeviceObject,
  69. IN PIRP Irp
  70. );
  71. NTSTATUS
  72. Shutdown(
  73. IN PDEVICE_OBJECT DeviceObject,
  74. IN PIRP Irp
  75. );
  76. VOID
  77. KillAllPendingUserIrps(
  78. PDEVICE_OBJECT PDevObj
  79. );
  80. NTSTATUS
  81. SystemControl(
  82. IN PDEVICE_OBJECT DeviceObject,
  83. IN PIRP Irp
  84. );
  85. //
  86. // GLOBALS
  87. //
  88. BOOLEAN g_isWin9x = FALSE;
  89. BOOLEAN g_ExposeComPort = FALSE;
  90. LONG g_NumDevices;
  91. LONG g_lIntTimout = DEFAULT_INT_PIPE_TIMEOUT;
  92. ULONG g_ulAlternateSetting = 0;
  93. ULONG g_ulMaxPipeErrors = DEFAULT_MAX_PIPE_DEVICE_ERRORS;
  94. ULONG DebugLevel;
  95. #ifdef ALLOC_PRAGMA
  96. #pragma alloc_text(INIT, DriverEntry)
  97. #pragma alloc_text(PAGEWCE0, AddDevice)
  98. #pragma alloc_text(PAGEWCE1, Unload)
  99. #pragma alloc_text(PAGEWCE1, Flush)
  100. #pragma alloc_text(PAGEWCE1, QueryInformationFile)
  101. #pragma alloc_text(PAGEWCE1, SetInformationFile)
  102. #pragma alloc_text(PAGEWCE1, Shutdown)
  103. #pragma alloc_text(PAGEWCE1, UsbFreeReadBuffer)
  104. #endif
  105. NTSTATUS
  106. DriverEntry(
  107. IN PDRIVER_OBJECT PDrvObj,
  108. IN PUNICODE_STRING PRegistryPath
  109. )
  110. {
  111. #ifdef DBG
  112. CHAR VersionHerald[] = "Windows CE USB Serial Host, Version %s built on %s\n";
  113. CHAR VersionNumber[] = "1.02";
  114. CHAR VersionTimestamp[] = __DATE__ " " __TIME__;
  115. #endif
  116. PAGED_CODE();
  117. KdPrint((VersionHerald, VersionNumber, VersionTimestamp));
  118. //
  119. // determine OS
  120. //
  121. g_isWin9x = IsWin9x();
  122. KdPrint(("This is Win %s\n", g_isWin9x ? "9x" : "NT" ));
  123. PDrvObj->MajorFunction[IRP_MJ_CREATE] = Create;
  124. PDrvObj->MajorFunction[IRP_MJ_CLOSE] = Close;
  125. PDrvObj->MajorFunction[IRP_MJ_CLEANUP] = Cleanup;
  126. PDrvObj->MajorFunction[IRP_MJ_READ] = Read;
  127. PDrvObj->MajorFunction[IRP_MJ_WRITE] = Write;
  128. PDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SerialIoctl;
  129. PDrvObj->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = Flush;
  130. PDrvObj->MajorFunction[IRP_MJ_QUERY_INFORMATION] = QueryInformationFile;
  131. PDrvObj->MajorFunction[IRP_MJ_SET_INFORMATION] = SetInformationFile;
  132. PDrvObj->DriverExtension->AddDevice = AddDevice;
  133. PDrvObj->MajorFunction[IRP_MJ_PNP] = Pnp;
  134. PDrvObj->MajorFunction[IRP_MJ_POWER] = Power;
  135. PDrvObj->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = SystemControl;
  136. PDrvObj->MajorFunction[IRP_MJ_SHUTDOWN] = Shutdown;
  137. PDrvObj->DriverUnload = Unload;
  138. //
  139. // initialize Globals
  140. //
  141. g_NumDevices = 0;
  142. QueryRegistryParameters( PRegistryPath );
  143. DbgDump(DBG_INIT, ("Create @ %p\n", Create));
  144. DbgDump(DBG_INIT, ("Close @ %p\n", Close));
  145. DbgDump(DBG_INIT, ("Cleanup @ %p\n", Cleanup));
  146. DbgDump(DBG_INIT, ("Read @ %p\n", Read));
  147. DbgDump(DBG_INIT, ("Write @ %p\n", Write));
  148. DbgDump(DBG_INIT, ("SerialIoctl @ %p\n", SerialIoctl));
  149. DbgDump(DBG_INIT, ("Flush @ %p\n", Flush));
  150. DbgDump(DBG_INIT, ("QueryInformationFile @ %p\n", QueryInformationFile));
  151. DbgDump(DBG_INIT, ("SetInformationFile @ %p\n", SetInformationFile));
  152. DbgDump(DBG_INIT, ("AddDevice @ %p\n", AddDevice));
  153. DbgDump(DBG_INIT, ("Pnp @ %p\n", Pnp));
  154. DbgDump(DBG_INIT, ("Power @ %p\n", Power));
  155. DbgDump(DBG_INIT, ("Shutdown @ %p\n", Shutdown));
  156. DbgDump(DBG_INIT, ("Unload @ %p\n", Unload));
  157. return STATUS_SUCCESS;
  158. }
  159. NTSTATUS
  160. AddDevice(
  161. IN PDRIVER_OBJECT PDrvObj,
  162. IN PDEVICE_OBJECT PPDO
  163. )
  164. /*++
  165. Routine Description:
  166. Add our driver to the USB device stack.
  167. This also creates our base device name and symbolic link.
  168. Arguments:
  169. PDrvObj - Pointer to our driver object
  170. PPDO - Pointer to the PDO for the stack to which we should add ourselves
  171. Return Value:
  172. NTSTATUS
  173. --*/
  174. {
  175. NTSTATUS status;
  176. PDEVICE_OBJECT pDevObj = NULL;
  177. PDEVICE_EXTENSION pDevExt = NULL;
  178. LONG comPortNumber=0;
  179. BOOLEAN bListsInitilized = FALSE;
  180. ULONG UniqueErrorValue = 0;
  181. DbgDump(DBG_INIT, (">AddDevice\n"));
  182. PAGED_CODE();
  183. //
  184. // Create the FDO
  185. //
  186. if (PPDO == NULL) {
  187. DbgDump(DBG_ERR, ("No PDO\n"));
  188. return STATUS_NO_MORE_ENTRIES;
  189. }
  190. //
  191. // create a named device object
  192. // and unprotected symbolic link.
  193. //
  194. status = CreateDevObjAndSymLink(
  195. PDrvObj,
  196. PPDO,
  197. &pDevObj,
  198. DRV_NAME );
  199. if ( (status != STATUS_SUCCESS) || !pDevObj ) {
  200. DbgDump(DBG_ERR, ("CreateDevObjAndSymLink error: 0x%x\n", status));
  201. UniqueErrorValue = ERR_NO_DEVICE_OBJ;
  202. goto AddDeviceFailed;
  203. }
  204. DbgDump( DBG_INIT, ("DevObj: %p\n", pDevObj));
  205. // init our device extension
  206. //
  207. pDevExt = pDevObj->DeviceExtension;
  208. pDevExt->DeviceObject = pDevObj;
  209. pDevExt->PDO = PPDO;
  210. // init our states
  211. //
  212. InterlockedExchange((PULONG)&pDevExt->PnPState, PnPStateInitialized);
  213. #ifdef POWER
  214. pDevExt->DevicePowerState= PowerDeviceD0;
  215. #endif
  216. // set FDO flags
  217. //
  218. ASSERT( !(pDevObj->Flags & DO_POWER_PAGABLE) );
  219. pDevObj->Flags |= (PPDO->Flags & DO_POWER_PAGABLE);
  220. pDevObj->Flags |= DO_BUFFERED_IO;
  221. pDevObj->Flags &= ~ DO_DEVICE_INITIALIZING;
  222. //
  223. // Create or initialize any other non-hardware resources here.
  224. // These items get cleaned up in IRP_MN_REMOVE_DEVICE....
  225. //
  226. // Initialize locks
  227. //
  228. KeInitializeSpinLock(&pDevExt->ControlLock);
  229. InitializeRemoveLock( &pDevExt->RemoveLock );
  230. //
  231. // Initialize USB Read Buffer, This value has an effect on performance.
  232. // In addition to testing the endpoint's MaximumPacketSize (64 byte max),
  233. // I tested 512, 1024, 2048, & 4096 across the EZ-Link, SL11, & CF.
  234. // 1024, 2048, and 4096 all gave similiar results which were much faster than 64 bytes
  235. // or even 512.
  236. //
  237. // EZ-Link Note: the pserial perf tests can sometimes go into timeout/retry/abort
  238. // situatiuon in the 2nd phase of a test. This is because it closes and then re-opens (so therefore purges) the driver's read buffer.
  239. // The driver's USB read buffer is purged of a full 960 byte device FIFO, already consumed by the driver.
  240. // This is viewable in the debugger using DBG_READ_LENGTH. This does not happen with ActiveSync.
  241. //
  242. pDevExt->UsbReadBuffSize = USB_READBUFF_SIZE;
  243. pDevExt->UsbReadBuff = ExAllocatePool( NonPagedPool, pDevExt->UsbReadBuffSize );
  244. if ( !pDevExt->UsbReadBuff ) {
  245. status = STATUS_INSUFFICIENT_RESOURCES;
  246. UniqueErrorValue = ERR_NO_USBREAD_BUFF;
  247. goto AddDeviceFailed;
  248. }
  249. pDevExt->MaximumTransferSize = DEFAULT_PIPE_MAX_TRANSFER_SIZE;
  250. #if defined (USE_RING_BUFF)
  251. // setup Ring Buffer
  252. pDevExt->RingBuff.Size = RINGBUFF_SIZE;
  253. pDevExt->RingBuff.pHead =
  254. pDevExt->RingBuff.pTail =
  255. pDevExt->RingBuff.pBase = ExAllocatePool( NonPagedPool, pDevExt->RingBuff.Size );
  256. if ( !pDevExt->RingBuff.pBase ) {
  257. status = STATUS_INSUFFICIENT_RESOURCES;
  258. UniqueErrorValue = ERR_NO_RING_BUFF;
  259. goto AddDeviceFailed;
  260. }
  261. #endif
  262. // Initialize events
  263. //
  264. KeInitializeEvent( &pDevExt->PendingDataInEvent, NotificationEvent /*SynchronizationEvent*/, FALSE);
  265. KeInitializeEvent( &pDevExt->PendingDataOutEvent, NotificationEvent /*SynchronizationEvent*/, FALSE);
  266. KeInitializeEvent( &pDevExt->PendingIntEvent, NotificationEvent /*SynchronizationEvent*/, FALSE);
  267. KeInitializeEvent( &pDevExt->PendingWorkItemsEvent, NotificationEvent /*SynchronizationEvent*/, FALSE);
  268. //
  269. // initialize nonpaged pools...
  270. //
  271. ExInitializeNPagedLookasideList(
  272. &pDevExt->PacketPool, // Lookaside,
  273. NULL, // Allocate OPTIONAL,
  274. NULL, // Free OPTIONAL,
  275. 0, // Flags,
  276. sizeof(USB_PACKET), // Size,
  277. WCEUSB_POOL_TAG, // Tag,
  278. 0 ); // Depth
  279. DbgDump(DBG_INIT, ("PacketPool: %p\n", &pDevExt->PacketPool));
  280. ExInitializeNPagedLookasideList(
  281. &pDevExt->BulkTransferUrbPool,
  282. NULL, NULL, 0,
  283. sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
  284. WCEUSB_POOL_TAG,
  285. 0 );
  286. DbgDump(DBG_INIT, ("BulkTransferUrbPool: %p\n", &pDevExt->BulkTransferUrbPool));
  287. ExInitializeNPagedLookasideList(
  288. &pDevExt->PipeRequestUrbPool,
  289. NULL, NULL, 0,
  290. sizeof(struct _URB_PIPE_REQUEST),
  291. WCEUSB_POOL_TAG,
  292. 0 );
  293. DbgDump(DBG_INIT, ("PipeRequestUrbPool: %p\n", &pDevExt->PipeRequestUrbPool));
  294. ExInitializeNPagedLookasideList(
  295. &pDevExt->VendorRequestUrbPool,
  296. NULL, NULL, 0,
  297. sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
  298. WCEUSB_POOL_TAG,
  299. 0 );
  300. DbgDump(DBG_INIT, ("VendorRequestUrbPool: %p\n", &pDevExt->VendorRequestUrbPool));
  301. ExInitializeNPagedLookasideList(
  302. &pDevExt->WorkItemPool,
  303. NULL, NULL, 0,
  304. sizeof(WCE_WORK_ITEM),
  305. WCEUSB_POOL_TAG,
  306. 0 );
  307. DbgDump(DBG_INIT, ("WorkItemPool: %p\n", &pDevExt->WorkItemPool));
  308. bListsInitilized = TRUE;
  309. //
  310. // initialize pending I/O lists
  311. //
  312. InitializeListHead( &pDevExt->PendingReadPackets );
  313. pDevExt->PendingReadCount = 0;
  314. InitializeListHead( &pDevExt->PendingWritePackets );
  315. pDevExt->PendingWriteCount = 0;
  316. InitializeListHead(&pDevExt->UserReadQueue);
  317. InitializeListHead( &pDevExt->PendingWorkItems );
  318. pDevExt->PendingWorkItemsCount = 0;
  319. //
  320. // Win 2000 ONLY : setup external SerialPort (COMx) interface
  321. // iff the user setup the magic reg key under
  322. // HKLM\SYSTEM\ControlSet\Services\wceusbsh\Parameters\ExposeComPort:REG_DWORD:1
  323. // This is NOT required for ActiveSync, only testing and is disabled by default.
  324. //
  325. // The Win9x CommXxx API *requires* going through VCOMM. Thus, we must
  326. // be installed as a virtual modem, and use ccport.sys and wdmmdmld.vxd ... NFW.
  327. //
  328. if ( !g_isWin9x && g_ExposeComPort ) {
  329. //
  330. // N.B. we don't want to use the static port name from the registry because the device
  331. // can come & go quickly (power up/down, etc.) and run into name collisions.
  332. //comPortNumber = GetComPort(pDevObj, pDevExt->SerialPort.Com.Instance-1);
  333. comPortNumber = GetFreeComPortNumber( );
  334. if (-1 == comPortNumber) {
  335. status = STATUS_DEVICE_DATA_ERROR;
  336. UniqueErrorValue = ERR_COMM_SYMLINK;
  337. goto AddDeviceFailed;
  338. }
  339. status = DoSerialPortNaming( pDevExt, comPortNumber );
  340. if (status != STATUS_SUCCESS) {
  341. UniqueErrorValue = ERR_COMM_SYMLINK;
  342. DbgDump(DBG_ERR, ("DoSerialPortNaming error: 0x%x\n", status));
  343. goto AddDeviceFailed;
  344. }
  345. status = IoRegisterShutdownNotification( pDevExt->DeviceObject );
  346. if (status != STATUS_SUCCESS) {
  347. UniqueErrorValue = ERR_COMM_SYMLINK;
  348. DbgDump(DBG_ERR, ("IoRegisterShutdownNotification error: 0x%x\n", status));
  349. TEST_TRAP();
  350. goto AddDeviceFailed;
  351. }
  352. } else {
  353. DbgDump(DBG_INIT, ("!GetFreeComPortNumber(%d, %d)\n", g_isWin9x, g_ExposeComPort));
  354. }
  355. //
  356. // attach to device stack
  357. //
  358. pDevExt->NextDevice = IoAttachDeviceToDeviceStack(pDevObj, PPDO);
  359. if ( !pDevExt->NextDevice ) {
  360. status = STATUS_NO_SUCH_DEVICE;
  361. DbgDump(DBG_ERR, ("IoAttachDeviceToDeviceStack error: 0x%x\n", status));
  362. } else {
  363. // set state after we attach to the stack
  364. InterlockedExchange((PULONG)&pDevExt->PnPState, PnPStateAttached);
  365. }
  366. #if PERFORMANCE
  367. InitPerfCounters();
  368. #endif
  369. AddDeviceFailed:
  370. if (status != STATUS_SUCCESS) {
  371. if (pDevObj != NULL) {
  372. UsbFreeReadBuffer( pDevObj );
  373. if (pDevExt) {
  374. if (pDevExt->NextDevice) {
  375. DbgDump(DBG_INIT, ("Detach from PDO\n"));
  376. IoDetachDevice(pDevExt->NextDevice);
  377. }
  378. if ( bListsInitilized) {
  379. //
  380. // delete LookasideLists
  381. //
  382. DbgDump(DBG_INIT, ("Deleting LookasideLists\n"));
  383. ExDeleteNPagedLookasideList( &pDevExt->PacketPool );
  384. ExDeleteNPagedLookasideList( &pDevExt->BulkTransferUrbPool );
  385. ExDeleteNPagedLookasideList( &pDevExt->PipeRequestUrbPool );
  386. ExDeleteNPagedLookasideList( &pDevExt->VendorRequestUrbPool );
  387. ExDeleteNPagedLookasideList( &pDevExt->WorkItemPool );
  388. }
  389. UndoSerialPortNaming(pDevExt);
  390. }
  391. ReleaseSlot( PtrToLong(NULL) );
  392. DeleteDevObjAndSymLink(pDevObj);
  393. }
  394. }
  395. if (STATUS_INSUFFICIENT_RESOURCES == status) {
  396. DbgDump(DBG_ERR, ("AddDevice ERROR: 0x%x, %d\n", status, UniqueErrorValue));
  397. LogError( PDrvObj,
  398. NULL,
  399. 0, 0, 0,
  400. UniqueErrorValue,
  401. status,
  402. SERIAL_INSUFFICIENT_RESOURCES,
  403. (pDevExt && pDevExt->DeviceName.Buffer) ? pDevExt->DeviceName.Length + sizeof(WCHAR) : 0,
  404. (pDevExt && pDevExt->DeviceName.Buffer) ? pDevExt->DeviceName.Buffer : NULL,
  405. 0, NULL );
  406. } else if (STATUS_SUCCESS != status ) {
  407. // handles all other failures
  408. LogError( PDrvObj,
  409. NULL,
  410. 0, 0, 0,
  411. UniqueErrorValue,
  412. status,
  413. SERIAL_INIT_FAILED,
  414. (pDevExt && pDevExt->DeviceName.Buffer) ? pDevExt->DeviceName.Length + sizeof(WCHAR) : 0,
  415. (pDevExt && pDevExt->DeviceName.Buffer) ? pDevExt->DeviceName.Buffer : NULL,
  416. 0, NULL );
  417. }
  418. DbgDump(DBG_INIT, ("<AddDevice 0x%x\n", status));
  419. return status;
  420. }
  421. NTSTATUS
  422. Create(
  423. IN PDEVICE_OBJECT PDevObj,
  424. IN PIRP PIrp
  425. )
  426. {
  427. PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  428. NTSTATUS status;
  429. DbgDump(DBG_INIT|DBG_TRACE, (">Create (%p)\n", PDevObj));
  430. if (!CanAcceptIoRequests(PDevObj, TRUE, FALSE) ||
  431. !NT_SUCCESS(AcquireRemoveLock(&pDevExt->RemoveLock, IRP_MJ_CREATE)))
  432. {
  433. status = STATUS_DELETE_PENDING;
  434. DbgDump(DBG_ERR, ("Create: 0x%x\n", status));
  435. PIrp->IoStatus.Status = status;
  436. IoCompleteRequest(PIrp, IO_NO_INCREMENT);
  437. return status;
  438. }
  439. ASSERT_SERIAL_PORT(pDevExt->SerialPort);
  440. //
  441. // Serial devices do not allow multiple concurrent opens
  442. //
  443. if ( InterlockedIncrement( &pDevExt->SerialPort.Com.OpenCnt ) != 1 ) {
  444. InterlockedDecrement( &pDevExt->SerialPort.Com.OpenCnt );
  445. status = STATUS_ACCESS_DENIED;
  446. DbgDump(DBG_ERR, ("OpenComPort ERROR: 0x%x\n", status));
  447. goto CreateDone;
  448. }
  449. InterlockedExchange(&pDevExt->DeviceOpened, TRUE);
  450. // Take out an additional reference on ourself.
  451. // We are seeing a possible premature unload with open handles in ActiveSync.
  452. // We dereference it in IRP_MJ_CLEANUP instead or IRP_MJ_CLOSE in case the app crashes
  453. // where we wouldn't otherwise get it.
  454. ObReferenceObject( PDevObj );
  455. //
  456. // reset the virtual serial port interface,
  457. // but don't send anything on the bus yet
  458. //
  459. status = SerialResetDevice(pDevExt, PIrp, FALSE);
  460. if (STATUS_SUCCESS == status) {
  461. //
  462. // CederRapier BUGBUG 13310: clean the read buffer when the app does CreateFile.
  463. //
  464. status = SerialPurgeRxClear(PDevObj, TRUE );
  465. if ( NT_SUCCESS(status) ) {
  466. #if !defined(DELAY_RXBUFF)
  467. // this will subit the read a bit earlier, making the connection faster
  468. if ( !pDevExt->IntPipe.hPipe ) {
  469. DbgDump(DBG_INIT, ("Create: kick starting another USB Read\n" ));
  470. status = UsbRead( pDevExt, FALSE );
  471. } else {
  472. DbgDump(DBG_INIT, ("Create: kick starting another USB INT Read\n" ));
  473. status = UsbInterruptRead( pDevExt );
  474. }
  475. if ( NT_SUCCESS(status) ) {
  476. // should be STATUS_PENDING
  477. status = STATUS_SUCCESS;
  478. }
  479. #else
  480. // signal to start the RX buffer in SerIoctl
  481. InterlockedExchange(&pDevExt->StartUsbRead, 1);
  482. #endif
  483. } else {
  484. DbgDump(DBG_ERR, ("SerialPurgeRxClear ERROR: %x\n", status));
  485. TEST_TRAP();
  486. }
  487. }
  488. if (STATUS_SUCCESS != status) {
  489. //
  490. // Let the user know that the device can not be opened.
  491. //
  492. DbgDump(DBG_ERR, ("*** UNRECOVERABLE CreateFile ERROR:0x%x, No longer Accepting Requests ***\n", status));
  493. InterlockedExchange(&pDevExt->AcceptingRequests, FALSE);
  494. InterlockedExchange(&pDevExt->DeviceOpened, FALSE);
  495. IoInvalidateDeviceState( pDevExt->PDO );
  496. LogError( NULL, PDevObj,
  497. 0, IRP_MJ_CREATE,
  498. 1, // retries
  499. ERR_NO_CREATE_FILE,
  500. status,
  501. SERIAL_HARDWARE_FAILURE,
  502. pDevExt->DeviceName.Length + sizeof(WCHAR),
  503. pDevExt->DeviceName.Buffer,
  504. 0,
  505. NULL );
  506. }
  507. CreateDone:
  508. // we release this reference on Close.
  509. if (STATUS_SUCCESS != status) {
  510. ReleaseRemoveLock(&pDevExt->RemoveLock, IRP_MJ_CREATE);
  511. }
  512. PIrp->IoStatus.Status = status;
  513. PIrp->IoStatus.Information = 0;
  514. IoCompleteRequest(PIrp, IO_SERIAL_INCREMENT);
  515. DbgDump(DBG_INIT|DBG_TRACE, ("<Create 0x%x\n", status));
  516. return status;
  517. }
  518. NTSTATUS
  519. Close(
  520. IN PDEVICE_OBJECT PDevObj,
  521. IN PIRP PIrp
  522. )
  523. {
  524. PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  525. NTSTATUS status = STATUS_SUCCESS;
  526. ULONG openCount;
  527. DbgDump(DBG_INIT|DBG_TRACE, (">Close (%p)\n", PDevObj));
  528. PAGED_CODE();
  529. ASSERT_SERIAL_PORT(pDevExt->SerialPort);
  530. //
  531. // stop any pending I/O
  532. //
  533. InterlockedExchange(&pDevExt->DeviceOpened, FALSE);
  534. status = StopIo(PDevObj);
  535. if (STATUS_SUCCESS == status) {
  536. if ( pDevExt->SerialPort.Com.OpenCnt ) {
  537. openCount = InterlockedDecrement( &pDevExt->SerialPort.Com.OpenCnt );
  538. if ( openCount != 0) {
  539. status = STATUS_UNSUCCESSFUL;
  540. DbgDump(DBG_WRN, ("Close ERROR: 0x%x RE: %d\n", status, openCount));
  541. TEST_TRAP();
  542. }
  543. #ifdef DELAY_RXBUFF
  544. // signal our RX buffer
  545. InterlockedExchange(&pDevExt->StartUsbRead, 0);
  546. #endif
  547. }
  548. } else {
  549. DbgDump(DBG_ERR, ("StopIo ERROR: 0x%x\n", status));
  550. TEST_TRAP();
  551. }
  552. PIrp->IoStatus.Status = status;
  553. PIrp->IoStatus.Information = 0;
  554. IoCompleteRequest(PIrp, IO_SERIAL_INCREMENT);
  555. if (STATUS_SUCCESS == status) {
  556. // Release the lock acquired in IRP_MJ_CREATE.
  557. // Warning: if the app misses our PnP signal then could we hang on this reference?
  558. ReleaseRemoveLock(&pDevExt->RemoveLock, IRP_MJ_CREATE);
  559. }
  560. DbgDump(DBG_INIT|DBG_TRACE, ("<Close 0x%x\n", status));
  561. return status;
  562. }
  563. NTSTATUS
  564. Cleanup(
  565. IN PDEVICE_OBJECT PDevObj,
  566. IN PIRP Irp
  567. )
  568. {
  569. PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  570. NTSTATUS status = STATUS_SUCCESS;
  571. DbgDump(DBG_INIT, (">Cleanup\n"));
  572. //
  573. // stop any pending I/O
  574. //
  575. InterlockedExchange(&pDevExt->DeviceOpened, FALSE);
  576. status = StopIo(PDevObj);
  577. if (STATUS_SUCCESS != status) {
  578. DbgDump(DBG_ERR, ("StopIo ERROR: 0x%x\n", status));
  579. TEST_TRAP();
  580. }
  581. #ifdef DELAY_RXBUFF
  582. // signal our RX buffer
  583. InterlockedExchange(&pDevExt->StartUsbRead, 0);
  584. #endif
  585. // Dereference the additional reference taken on IRP_MJ_CREATE.
  586. ObDereferenceObject( PDevObj );
  587. Irp->IoStatus.Status = STATUS_SUCCESS;
  588. Irp->IoStatus.Information = 0;
  589. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  590. DbgDump(DBG_INIT, ("<Cleanup 0x%x\n", status));
  591. return status;
  592. }
  593. VOID
  594. KillAllPendingUserReads(
  595. IN PDEVICE_OBJECT PDevObj,
  596. IN PLIST_ENTRY PQueueToClean,
  597. IN PIRP *PpCurrentOpIrp
  598. )
  599. /*++
  600. Routine Description:
  601. cancel all queued user reads.
  602. Arguments:
  603. PDevObj - A pointer to the serial device object.
  604. PQueueToClean - A pointer to the queue which we're going to clean out.
  605. PpCurrentOpIrp - Pointer to a pointer to the current irp.
  606. Return Value:
  607. None.
  608. --*/
  609. {
  610. PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  611. KIRQL irql;
  612. NTSTATUS status;
  613. DbgDump( DBG_IRP, (">KillAllPendingUserReads\n"));
  614. KeAcquireSpinLock( &pDevExt->ControlLock, &irql );
  615. //
  616. // Clean the list from back to front.
  617. //
  618. while (!IsListEmpty(PQueueToClean)) {
  619. PIRP pCurrentLastIrp = CONTAINING_RECORD( PQueueToClean->Blink,
  620. IRP,
  621. Tail.Overlay.ListEntry);
  622. RemoveEntryList(PQueueToClean->Blink);
  623. KeReleaseSpinLock( &pDevExt->ControlLock, irql );
  624. status = ManuallyCancelIrp( PDevObj, pCurrentLastIrp);
  625. ASSERT(STATUS_SUCCESS == status );
  626. KeAcquireSpinLock( &pDevExt->ControlLock, &irql );
  627. }
  628. //
  629. // The queue is clean. Now go after the current if
  630. // it's there.
  631. //
  632. if (*PpCurrentOpIrp) {
  633. KeReleaseSpinLock( &pDevExt->ControlLock, irql );
  634. status = ManuallyCancelIrp( PDevObj, *PpCurrentOpIrp );
  635. ASSERT(STATUS_SUCCESS == status );
  636. } else {
  637. DbgDump(DBG_IRP, ("No current Irp\n"));
  638. KeReleaseSpinLock( &pDevExt->ControlLock, irql );
  639. }
  640. DbgDump( DBG_IRP, ("<KillAllPendingUserReads\n"));
  641. return;
  642. }
  643. VOID
  644. Unload(
  645. IN PDRIVER_OBJECT DriverObject
  646. )
  647. /*++
  648. Routine Description:
  649. Undo everything setup in DriverEntry
  650. Arguments:
  651. DriverObject
  652. Return Value:
  653. VOID
  654. --*/
  655. {
  656. UNREFERENCED_PARAMETER( DriverObject );
  657. DbgDump(DBG_INIT, (">Unload\n"));
  658. PAGED_CODE();
  659. // release global resources here
  660. DbgDump(DBG_INIT, ("<Unload\n"));
  661. }
  662. NTSTATUS
  663. Flush(
  664. IN PDEVICE_OBJECT DeviceObject,
  665. IN PIRP Irp
  666. )
  667. /*++
  668. Routine Description:
  669. This is the dispatch routine for flush. Flushing works by placing
  670. this request in the write queue. When this request reaches the
  671. front of the write queue we simply complete it since this implies
  672. that all previous writes have completed.
  673. Arguments:
  674. DeviceObject - Pointer to the device object for this device
  675. Irp - Pointer to the IRP for the current request
  676. Return Value:
  677. Could return status success, cancelled, or pending.
  678. --*/
  679. {
  680. NTSTATUS status = STATUS_SUCCESS;
  681. UNREFERENCED_PARAMETER( DeviceObject );
  682. DbgDump( DBG_INIT|DBG_READ_LENGTH|DBG_WRITE_LENGTH, ("Flush\n"));
  683. PAGED_CODE();
  684. Irp->IoStatus.Status = status;
  685. Irp->IoStatus.Information = 0L;
  686. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  687. return status;
  688. }
  689. NTSTATUS
  690. QueryInformationFile(
  691. IN PDEVICE_OBJECT DeviceObject,
  692. IN PIRP Irp
  693. )
  694. /*++
  695. Routine Description:
  696. This routine is used to query the end of file information on
  697. the opened serial port. Any other file information request
  698. is retured with an invalid parameter.
  699. This routine always returns an end of file of 0.
  700. Arguments:
  701. DeviceObject - Pointer to the device object for this device
  702. Irp - Pointer to the IRP for the current request
  703. Return Value:
  704. The function value is the final status of the call
  705. --*/
  706. {
  707. //
  708. // The status that gets returned to the caller and
  709. // set in the Irp.
  710. //
  711. NTSTATUS Status;
  712. //
  713. // The current stack location. This contains all of the
  714. // information we need to process this particular request.
  715. //
  716. PIO_STACK_LOCATION IrpSp;
  717. UNREFERENCED_PARAMETER(DeviceObject);
  718. DbgDump( DBG_INIT|DBG_READ_LENGTH, (">QueryInformationFile\n"));
  719. PAGED_CODE();
  720. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  721. Irp->IoStatus.Information = 0L;
  722. Status = STATUS_SUCCESS;
  723. if (IrpSp->Parameters.QueryFile.FileInformationClass == FileStandardInformation) {
  724. PFILE_STANDARD_INFORMATION Buf = Irp->AssociatedIrp.SystemBuffer;
  725. Buf->AllocationSize.QuadPart = 0;
  726. Buf->EndOfFile = Buf->AllocationSize;
  727. Buf->NumberOfLinks = 0;
  728. Buf->DeletePending = FALSE;
  729. Buf->Directory = FALSE;
  730. Irp->IoStatus.Information = sizeof(FILE_STANDARD_INFORMATION);
  731. } else if (IrpSp->Parameters.QueryFile.FileInformationClass == FilePositionInformation) {
  732. ((PFILE_POSITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer)->CurrentByteOffset.QuadPart = 0;
  733. Irp->IoStatus.Information = sizeof(FILE_POSITION_INFORMATION);
  734. } else {
  735. Status = STATUS_INVALID_PARAMETER;
  736. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  737. }
  738. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  739. DbgDump( DBG_INIT|DBG_READ_LENGTH, ("<QueryInformationFile\n"));
  740. return Status;
  741. }
  742. NTSTATUS
  743. SetInformationFile(
  744. IN PDEVICE_OBJECT DeviceObject,
  745. IN PIRP Irp
  746. )
  747. /*++
  748. Routine Description:
  749. This routine is used to set the end of file information on
  750. the opened parallel port. Any other file information request
  751. is retured with an invalid parameter.
  752. This routine always ignores the actual end of file since
  753. the query information code always returns an end of file of 0.
  754. Arguments:
  755. DeviceObject - Pointer to the device object for this device
  756. Irp - Pointer to the IRP for the current request
  757. Return Value:
  758. The function value is the final status of the call
  759. --*/
  760. {
  761. //
  762. // The status that gets returned to the caller and
  763. // set in the Irp.
  764. //
  765. NTSTATUS Status;
  766. UNREFERENCED_PARAMETER(DeviceObject);
  767. PAGED_CODE();
  768. DbgDump( DBG_INIT|DBG_READ_LENGTH, (">SetInformationFile\n"));
  769. Irp->IoStatus.Information = 0L;
  770. if (IoGetCurrentIrpStackLocation(Irp)->Parameters.SetFile.FileInformationClass == FileEndOfFileInformation) {
  771. // || (IoGetCurrentIrpStackLocation(Irp)->Parameters.SetFile.FileInformationClass == FileAllocationInformation)) { // FileAllocationInformationnot defined in wdm.h
  772. Status = STATUS_SUCCESS;
  773. } else {
  774. Status = STATUS_INVALID_PARAMETER;
  775. }
  776. Irp->IoStatus.Status = Status;
  777. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  778. DbgDump( DBG_INIT|DBG_READ_LENGTH, ("<SetInformationFile\n"));
  779. return Status;
  780. }
  781. NTSTATUS
  782. Shutdown(
  783. IN PDEVICE_OBJECT DeviceObject,
  784. IN PIRP Irp
  785. )
  786. {
  787. PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  788. PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(Irp);
  789. NTSTATUS status = STATUS_SUCCESS;
  790. DbgDump(DBG_INIT, (">Shutdown\n"));
  791. PAGED_CODE();
  792. //
  793. // Special Case - If an app has an open handle to the device,
  794. // and the system is being shut down in a controlled manner,
  795. // and we have not been removed via PnP, then remove the COMx name
  796. // from the Registry's COM Name Arbitrator DataBase for the next boot cycle.
  797. // Win NT only; Win9x does not export COMx names.
  798. //
  799. // N.B: we have to do this in a Shutdown handler, and NOT in the PNP_POWER handler
  800. // because the Registry entry is NOT saved in the Power down code path.
  801. //
  802. if ( !g_isWin9x && g_ExposeComPort &&
  803. pDevExt->SerialPort.Com.PortNumber &&
  804. (PnPStateStarted == pDevExt->PnPState) ) {
  805. //
  806. // remove our entry from ComDB
  807. //
  808. ReleaseCOMPort( pDevExt->SerialPort.Com.PortNumber );
  809. }
  810. Irp->IoStatus.Status = status;
  811. Irp->IoStatus.Information = 0L;
  812. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  813. DbgDump(DBG_INIT, ("<Shutdown\n"));
  814. return status;
  815. }
  816. VOID
  817. UsbFreeReadBuffer(
  818. IN PDEVICE_OBJECT PDevObj
  819. )
  820. {
  821. PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  822. DbgDump(DBG_USB, (">UsbFreeReadBuffer %p\n", PDevObj));
  823. PAGED_CODE();
  824. if ( pDevExt->UsbReadBuff != NULL ) {
  825. ExFreePool(pDevExt->UsbReadBuff);
  826. pDevExt->UsbReadBuff = NULL;
  827. }
  828. #if defined (USE_RING_BUFF)
  829. if ( pDevExt->RingBuff.pBase != NULL ) {
  830. ExFreePool(pDevExt->RingBuff.pBase);
  831. pDevExt->RingBuff.pBase =
  832. pDevExt->RingBuff.pHead =
  833. pDevExt->RingBuff.pTail = NULL;
  834. }
  835. #endif // USE_RING_BUFF
  836. DbgDump(DBG_USB, ("<UsbFreeReadBuffer\n"));
  837. return;
  838. }
  839. NTSTATUS
  840. SystemControl(
  841. IN PDEVICE_OBJECT DeviceObject,
  842. IN PIRP Irp
  843. )
  844. {
  845. PDEVICE_EXTENSION pDevExt;
  846. PAGED_CODE();
  847. DbgDump(DBG_INIT, ("SystemControl\n"));
  848. pDevExt = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  849. IoSkipCurrentIrpStackLocation(Irp);
  850. return IoCallDriver(pDevExt->NextDevice, Irp);
  851. }
  852. // EOF