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.

951 lines
28 KiB

  1. //-------------------------------------------------------------------
  2. // This is implementation of WDM device
  3. // Author: Sergey Ivanov
  4. // Log:
  5. // 10/01/99 - implemented
  6. //-------------------------------------------------------------------
  7. #ifndef __WDM_ADAPTER__
  8. #define __WDM_ADAPTER__
  9. #include "kernel.h"
  10. #pragma LOCKEDCODE
  11. class CPendingIRP;
  12. class CLinkedList;
  13. #pragma PAGEDCODE
  14. // This is adapter class
  15. // It defines default device methods specific for any WDM.
  16. class CWDMDevice : public CDevice
  17. {
  18. public:
  19. NTSTATUS m_Status;
  20. SAFE_DESTRUCTORS();
  21. protected:
  22. NTSTATUS device_Default(PIRP Irp)
  23. {
  24. // Default functions to handle requests...
  25. // By default we do not handle any requests if
  26. // they are not reimplimented.
  27. Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
  28. Irp->IoStatus.Information = 0;
  29. irp->completeRequest(Irp,IO_NO_INCREMENT);
  30. return STATUS_IO_DEVICE_ERROR;
  31. };
  32. NTSTATUS PnP_Default(IN PIRP Irp)
  33. {
  34. // Default device does not do anything.
  35. // So let's just transfer request to low level driver...
  36. irp->skipCurrentStackLocation(Irp);
  37. return system->callDriver(m_pLowerDeviceObject, Irp);
  38. };
  39. NTSTATUS power_Default(IN PIRP Irp)
  40. {
  41. // Default device does not do anything.
  42. // So let's just transfer request to low level driver...
  43. power->startNextPowerIrp(Irp); // must be done while we own the IRP
  44. irp->skipCurrentStackLocation(Irp);
  45. return power->callPowerDriver(m_pLowerDeviceObject, Irp);
  46. }
  47. NTSTATUS completeDeviceRequest(PIRP Irp, NTSTATUS status, ULONG_PTR info)
  48. {
  49. // Complete current request with given information
  50. if (Irp->PendingReturned)
  51. {
  52. irp->getCurrentStackLocation(Irp)->Control &= ~SL_PENDING_RETURNED;
  53. }
  54. Irp->IoStatus.Status = status;
  55. Irp->IoStatus.Information = info;
  56. irp->completeRequest(Irp,IO_NO_INCREMENT);
  57. return status;
  58. }
  59. public:
  60. // Redefine base class methods..
  61. CWDMDevice()
  62. {
  63. m_Status = STATUS_INSUFFICIENT_RESOURCES;
  64. Signature[0]=L'I';
  65. Signature[1]=L'S';
  66. Signature[2]=L'V';
  67. initialized = FALSE;
  68. if(createDeviceObjects())
  69. {
  70. //Default our interface
  71. memory->copy(&InterfaceClassGuid,&GUID_CLASS_GRCLASS,sizeof(GUID));
  72. // It is reqired to initialize our object directly
  73. // through createDeviceObjects() function.
  74. event->initialize(&IdleState,SynchronizationEvent, TRUE);
  75. // This event will signal if device is ready to process requests...
  76. event->initialize(&m_evEnabled,NotificationEvent,TRUE);
  77. initializeRemoveLock();
  78. m_Status = STATUS_SUCCESS;
  79. }
  80. Idle_conservation = 0;
  81. Idle_performance = 0;
  82. m_VendorNameLength = 0;
  83. m_DeviceTypeLength = 0;
  84. TRACE("WDM device created...\n");
  85. };
  86. ~CWDMDevice()
  87. {
  88. TRACE(" Destroing WDM device %8.8lX ...\n", this);
  89. if(!m_RemoveLock.removing)
  90. {
  91. TRACE("######## ERROR: surprize destroing...\n");
  92. remove();
  93. }
  94. unregisterDeviceInterface(getDeviceInterfaceName());
  95. Signature[0]++;
  96. Signature[1]++;
  97. removeDeviceObjects();
  98. };
  99. BOOL checkValid(VOID)
  100. {
  101. if(!initialized) return FALSE;
  102. return (Signature[0]==L'I' && Signature[1]==L'S'
  103. && Signature[2]==L'V');
  104. };
  105. // It is alright to create device directly or
  106. // to call the function
  107. virtual CDevice* create(VOID)
  108. {
  109. CDevice* obj = new (NonPagedPool) CWDMDevice;
  110. RETURN_VERIFIED_OBJECT(obj);
  111. };
  112. virtual VOID dispose()
  113. {
  114. TRACE("Destroing WDM device...\n");
  115. if(!m_RemoveLock.removing)
  116. {
  117. TRACE("######## ERROR: surprize destroing...\n");
  118. remove();
  119. }
  120. Signature[0]++;
  121. Signature[1]++;
  122. removeDeviceObjects();
  123. // The device is link to the system.
  124. // So let system to remove device first and
  125. // after this we will remove device object...
  126. //self_delete();
  127. };
  128. BOOL createDeviceObjects()
  129. {
  130. debug = kernel->createDebug();
  131. system = kernel->createSystem();
  132. lock = kernel->createLock();
  133. irp = kernel->createIrp();
  134. event = kernel->createEvent();
  135. power = kernel->createPower();
  136. memory = kernel->createMemory();
  137. m_IoRequests = new (NonPagedPool) CLinkedList<CPendingIRP>;
  138. if(!system || !irp || !event || !power || !lock
  139. || !memory || !m_IoRequests)
  140. {
  141. removeDeviceObjects();
  142. return FALSE;
  143. }
  144. TRACE("WDM device objects created...\n");
  145. initialized = TRUE;
  146. return TRUE;
  147. };
  148. VOID removeDeviceObjects()
  149. {
  150. TRACE("Destroing WDM device objects...\n");
  151. if(m_IoRequests) delete m_IoRequests;
  152. if(lock) lock->dispose();
  153. if(irp) irp->dispose();
  154. if(event) event->dispose();
  155. if(power) power->dispose();
  156. if(memory) memory->dispose();
  157. if(system) system->dispose();
  158. if(debug) debug->dispose();
  159. initialized = FALSE;
  160. };
  161. // This part contains device synchronization functions.
  162. // They should be used to synchronize device removal.
  163. // So basically any access to device should be started with acquireRemoveLock()
  164. // and finished with releaseRemoveLock()...
  165. #pragma PAGEDCODE
  166. VOID initializeRemoveLock()
  167. { // InitializeRemoveLock
  168. PAGED_CODE();
  169. event->initialize(&m_RemoveLock.evRemove, NotificationEvent, FALSE);
  170. m_RemoveLock.usage = 1;
  171. m_RemoveLock.removing = FALSE;
  172. } // InitializeRemoveLock
  173. #pragma LOCKEDCODE
  174. NTSTATUS acquireRemoveLock()
  175. {
  176. LONG usage = lock->interlockedIncrement(&m_RemoveLock.usage);
  177. if (m_RemoveLock.removing)
  178. { // removal in progress
  179. if (lock->interlockedDecrement(&m_RemoveLock.usage) == 0)
  180. event->set(&m_RemoveLock.evRemove,IO_NO_INCREMENT,FALSE);
  181. TRACE("LOCK: m_RemoveLock.usage %d\n",m_RemoveLock.usage);
  182. TRACE("****** FAILED TO LOCK WDM DEVICE! REMOVE REQUEST IS ACTIVE! *******\n");
  183. return STATUS_DELETE_PENDING;
  184. }
  185. //TRACE("LOCK: m_RemoveLock.usage %d\n",m_RemoveLock.usage);
  186. return STATUS_SUCCESS;
  187. };
  188. #pragma PAGEDCODE
  189. VOID releaseRemoveLock()
  190. {
  191. ULONG usage;
  192. if(m_Type==BUS_DEVICE)
  193. { //???????????????????????- BIG BIG BUG!!!
  194. // It is connected only to BUS device!
  195. // At some conditions not all remove locks was released properly.
  196. // For other devices it is not appeared at all.
  197. if(m_RemoveLock.usage<0) m_RemoveLock.usage = 0;
  198. if (!m_RemoveLock.removing)
  199. {
  200. if(m_RemoveLock.usage<2) m_RemoveLock.usage = 2;
  201. }
  202. }
  203. if (usage = lock->interlockedDecrement(&m_RemoveLock.usage) == 0)
  204. event->set(&m_RemoveLock.evRemove,IO_NO_INCREMENT,FALSE);
  205. //TRACE("UNLOCK: m_RemoveLock.usage %d\n",m_RemoveLock.usage);
  206. };
  207. #pragma PAGEDCODE
  208. VOID releaseRemoveLockAndWait()
  209. {
  210. PAGED_CODE();
  211. TRACE("REMOVING DEVICE...\n");
  212. m_RemoveLock.removing = TRUE;
  213. // We are going to remove device.
  214. // So if somebody is waiting for the active device,
  215. // first allow them to fail request and complete Irp
  216. event->set(&m_evEnabled,IO_NO_INCREMENT,FALSE);
  217. releaseRemoveLock();
  218. releaseRemoveLock();
  219. // Child device at bus could be removed by the Bus itself
  220. // In this case it will not have second AquireRemoveLock from PnP system!
  221. if(m_Type == CHILD_DEVICE)
  222. if(m_RemoveLock.usage<0) m_RemoveLock.usage = 0;
  223. TRACE("LOCK COUNT ON REMOVING %x\n",m_RemoveLock.usage);
  224. //ASSERT(m_RemoveLock.usage==0);
  225. event->waitForSingleObject(&m_RemoveLock.evRemove, Executive, KernelMode, FALSE, NULL);
  226. }
  227. BOOL isDeviceLocked()
  228. {
  229. lock->interlockedIncrement(&m_RemoveLock.usage);
  230. // Add device will increment Usage!
  231. // Current request will add more...
  232. if(lock->interlockedDecrement(&m_RemoveLock.usage)<=2)
  233. {
  234. return FALSE;
  235. }
  236. TRACE("Current lock count %d\n",m_RemoveLock.usage);
  237. return TRUE;
  238. };
  239. // Contrary to RemoveLock disableDevice() stops and blocks any active request
  240. // INSIDE driver. It will not fail the request but will synchronize its
  241. // execution.
  242. VOID disableDevice()
  243. {
  244. TRACE("********** DISABLING DEVICE...***********\n");
  245. event->clear(&m_evEnabled);
  246. }
  247. VOID enableDevice()
  248. {
  249. TRACE("********** ENABLING DEVICE...***********\n");
  250. event->set(&m_evEnabled,IO_NO_INCREMENT,FALSE);
  251. }
  252. BOOL synchronizeDeviceExecution()
  253. { // If device is not ready to process requests, block waiting for the device
  254. ASSERT(system->getCurrentIrql()<=DISPATCH_LEVEL);
  255. NTSTATUS status = event->waitForSingleObject(&m_evEnabled, Executive,KernelMode, FALSE, NULL);
  256. if(!NT_SUCCESS(status) || m_RemoveLock.removing) return FALSE;
  257. return TRUE;
  258. }
  259. // Functions to synchronize device execution
  260. VOID setBusy()
  261. {
  262. event->clear(&IdleState);
  263. //TRACE("\n DEVICE BUSY\n");
  264. };
  265. VOID setIdle()
  266. {
  267. event->set(&IdleState,IO_NO_INCREMENT,FALSE);
  268. //TRACE("\n DEVICE IDLE\n");
  269. };
  270. NTSTATUS waitForIdle()
  271. {
  272. ASSERT(system->getCurrentIrql()<=DISPATCH_LEVEL);
  273. NTSTATUS status = event->waitForSingleObject(&IdleState, Executive,KernelMode, FALSE, NULL);
  274. if(!NT_SUCCESS(status)) return STATUS_IO_TIMEOUT;
  275. return STATUS_SUCCESS;
  276. };
  277. NTSTATUS waitForIdleAndBlock()
  278. {
  279. if(NT_SUCCESS(waitForIdle()))
  280. {
  281. setBusy();
  282. return STATUS_SUCCESS;
  283. }
  284. else return STATUS_IO_TIMEOUT;
  285. };
  286. BOOL registerDeviceInterface(const GUID* Guid)
  287. {
  288. if(isDeviceInterfaceRegistered())
  289. {
  290. TRACE("Device interface already active...\n");
  291. return TRUE;
  292. }
  293. if(memory) memory->copy(&InterfaceClassGuid, Guid,sizeof(GUID));
  294. TRACE("Registering device interface at system...\n");
  295. NTSTATUS Status = system->registerDeviceInterface(getPhysicalObject(),
  296. &InterfaceClassGuid, NULL, getDeviceInterfaceName());
  297. if(!NT_SUCCESS(Status))
  298. {
  299. TRACE("#### Failed to register device interface...\n");
  300. return FALSE;
  301. }
  302. system->setDeviceInterfaceState(getDeviceInterfaceName(),TRUE);
  303. m_DeviceInterfaceRegistered = TRUE;
  304. return TRUE;
  305. };
  306. VOID unregisterDeviceInterface(UNICODE_STRING* InterfaceName)
  307. {
  308. if(isDeviceInterfaceRegistered())
  309. {
  310. TRACE("Unregistering device interface...\n");
  311. system->setDeviceInterfaceState(InterfaceName,FALSE);
  312. }
  313. m_DeviceInterfaceRegistered = FALSE;
  314. };
  315. virtual NTSTATUS setVendorName(const PCHAR Name,USHORT Length)
  316. {
  317. m_VendorNameLength = Length<MAXIMUM_ATTR_STRING_LENGTH? Length:MAXIMUM_ATTR_STRING_LENGTH;
  318. if(!m_VendorNameLength) return STATUS_INVALID_PARAMETER;
  319. memory->copy(m_VendorName, Name, m_VendorNameLength);
  320. return STATUS_SUCCESS;
  321. };
  322. virtual NTSTATUS getVendorName(PUCHAR Name,PUSHORT pLength)
  323. {
  324. USHORT Len = m_VendorNameLength<*pLength? m_VendorNameLength:*pLength;
  325. *pLength = Len;
  326. if(!Len) return STATUS_INVALID_PARAMETER;
  327. memory->copy(Name, m_VendorName, Len);
  328. return STATUS_SUCCESS;
  329. };
  330. virtual NTSTATUS setDeviceType(const PCHAR Type,USHORT Length)
  331. {
  332. m_DeviceTypeLength = Length<MAXIMUM_ATTR_STRING_LENGTH? Length:MAXIMUM_ATTR_STRING_LENGTH;
  333. if(!m_DeviceTypeLength) return STATUS_INVALID_PARAMETER;
  334. memory->copy(m_DeviceType, Type, m_DeviceTypeLength);
  335. return STATUS_SUCCESS;
  336. };
  337. virtual NTSTATUS getDeviceType(PUCHAR Type,PUSHORT pLength)
  338. {
  339. USHORT Len = m_DeviceTypeLength<*pLength? m_DeviceTypeLength:*pLength;
  340. *pLength = Len;
  341. if(!Len) return STATUS_INVALID_PARAMETER;
  342. memory->copy(Type, m_DeviceType, Len);
  343. return STATUS_SUCCESS;
  344. };
  345. // This is basic PnP part of driver.
  346. // It allows to add and remove device.
  347. // Specific PnP request should be reimplemented by clients...
  348. virtual NTSTATUS createDeviceObjectByName(PDEVICE_OBJECT* ppFdo)
  349. {
  350. if(!ALLOCATED_OK(system)) return STATUS_INSUFFICIENT_RESOURCES;
  351. // By default we will create autogenerated name...
  352. // Specific implementations can overwrite the function to
  353. // change the functionality.
  354. return system->createDevice(m_DriverObject,sizeof(CWDMDevice*),NULL,
  355. FILE_DEVICE_UNKNOWN,FILE_AUTOGENERATED_DEVICE_NAME,FALSE,ppFdo);
  356. };
  357. virtual NTSTATUS registerDevicePowerPolicy()
  358. { // By default all devices at startup are ON
  359. if(!ALLOCATED_OK(power)) return STATUS_INSUFFICIENT_RESOURCES;
  360. POWER_STATE state;
  361. state.DeviceState = PowerDeviceD0;
  362. power->declarePowerState(m_DeviceObject, DevicePowerState, state);
  363. if(m_PhysicalDeviceObject)
  364. {
  365. m_CurrentDevicePowerState = PowerDeviceD0;
  366. m_Idle = power->registerDeviceForIdleDetection(m_PhysicalDeviceObject,Idle_conservation,Idle_performance, PowerDeviceD3);
  367. }
  368. return STATUS_SUCCESS;
  369. };
  370. virtual NTSTATUS initializeInterruptSupport()
  371. {
  372. // Here is where we can initialize our DPC (Deferred Procedure Call) object
  373. // that allows our interrupt service routine to request a DPC to finish handling
  374. // a device interrupt.
  375. // At default WDM device we do not do this.
  376. //interrupt->initializeDpcRequest(m_DeviceObject,&CALLBACK_FUNCTION(DpcForIsr));
  377. return STATUS_SUCCESS;
  378. };
  379. NTSTATUS add(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pPdo)
  380. {
  381. NTSTATUS status;
  382. PDEVICE_OBJECT pFdo;
  383. if(!ALLOCATED_OK(system)) return STATUS_INSUFFICIENT_RESOURCES;
  384. TRACE("Add with Driver %8.8lX, pPDO %8.8lX\n",DriverObject, pPdo);
  385. // Init first our objects...
  386. m_DriverObject = DriverObject;
  387. m_PhysicalDeviceObject = pPdo;
  388. // create Fdo for the registered objects.
  389. // Clients can overwrite device object name and it's visibility.
  390. status = createDeviceObjectByName(&pFdo);
  391. if(!NT_SUCCESS(status))
  392. {
  393. TRACE("#### Failed to create physical device! Status %x\n",status);
  394. DISPOSE_OBJECT(m_DeviceObjectName);
  395. return status;
  396. }
  397. TRACE(" Device object was created %8.8lX\n",pFdo);
  398. m_DeviceObject = pFdo;
  399. m_Added = TRUE;
  400. CLogger* logger = kernel->getLogger();
  401. if(pPdo)
  402. {
  403. m_pLowerDeviceObject = system->attachDevice(pFdo, pPdo);
  404. if(!m_pLowerDeviceObject)
  405. {
  406. TRACE("#### Failed to get lower device object...\n");
  407. if(ALLOCATED_OK(logger))
  408. logger->logEvent(GRCLASS_FAILED_TO_ADD_DEVICE,getSystemObject());
  409. system->deleteDevice(pFdo);
  410. return STATUS_NO_SUCH_DEVICE;
  411. }
  412. }
  413. else m_pLowerDeviceObject = NULL;
  414. initializeInterruptSupport();
  415. pFdo->Flags |= DO_BUFFERED_IO;
  416. pFdo->Flags |= DO_POWER_PAGABLE;
  417. pFdo->Flags &= ~DO_DEVICE_INITIALIZING;
  418. registerDevicePowerPolicy();
  419. TRACE("WDM device added...\n");
  420. return STATUS_SUCCESS;
  421. };
  422. VOID remove()
  423. {
  424. if(!m_Added) return;
  425. TRACE("Removing WDM device...\n");
  426. // Wait untill we finished all activity at device
  427. releaseRemoveLockAndWait();
  428. // Remove device from our system
  429. TRACE("Unregistering device from kernel...\n");
  430. kernel->unregisterObject(getSystemObject());
  431. TRACE("Removing device object name...\n");
  432. if(m_DeviceObjectName) delete m_DeviceObjectName;
  433. m_DeviceObjectName = NULL;
  434. if(m_pLowerDeviceObject)
  435. {
  436. TRACE("Detaching device from system...\n");
  437. system->detachDevice(m_pLowerDeviceObject);
  438. }
  439. TRACE("WDM device removed...\n");
  440. // Tell our system - device removed...
  441. m_Added = FALSE;
  442. // Removing device from system could result in
  443. // requesting Unload() from system if the device was last registered device.
  444. // So, this call should be last call AFTER disposing the device.
  445. };
  446. virtual VOID onDeviceStop()
  447. {
  448. return;
  449. };
  450. NTSTATUS forward(PIRP Irp, PIO_COMPLETION_ROUTINE Routine)
  451. {
  452. CIoPacket* IoPacket;
  453. // This function sends the current request
  454. // If completion routine is not set it will complete
  455. // the request by default(it means without doing anything special).
  456. TRACE("WDM forward()...\n");
  457. IoPacket = new (NonPagedPool) CIoPacket(Irp);
  458. if(!ALLOCATED_OK(IoPacket))
  459. {
  460. DISPOSE_OBJECT(IoPacket);
  461. return STATUS_INSUFFICIENT_RESOURCES;
  462. }
  463. IoPacket->copyCurrentStackToNext();
  464. if(Routine) IoPacket->setCompletion(Routine);
  465. else IoPacket->setDefaultCompletionFunction();
  466. NTSTATUS status = system->callDriver(getLowerDriver(),IoPacket->getIrpHandle());
  467. DISPOSE_OBJECT(IoPacket);
  468. return status;
  469. };
  470. // Send the current request to low level driver and wait for reply
  471. // Current IRP will not be completed, so we can process it and
  472. // complete later.
  473. // See also description of send() function.
  474. NTSTATUS forwardAndWait(PIRP Irp)
  475. { // Send request to low level and wait for a reply
  476. CIoPacket* IoPacket;
  477. TRACE("WDM forwardAndWait()...\n");
  478. IoPacket = new (NonPagedPool) CIoPacket(Irp);
  479. if(!ALLOCATED_OK(IoPacket))
  480. {
  481. DISPOSE_OBJECT(IoPacket);
  482. return STATUS_INSUFFICIENT_RESOURCES;
  483. }
  484. IoPacket->setCurrentStack();
  485. IoPacket->setStackDefaults();
  486. NTSTATUS status = system->callDriver(getLowerDriver(),IoPacket->getIrpHandle());
  487. if(status == STATUS_PENDING)
  488. {
  489. TRACE("Waiting for the bus driver to complete...\n");
  490. ASSERT(system->getCurrentIrql()<=DISPATCH_LEVEL);
  491. status = IoPacket->waitForCompletion();
  492. TRACE("Request completed with status %x\n",status);
  493. }
  494. DISPOSE_OBJECT(IoPacket);
  495. return status;
  496. };
  497. // WDM by default just forwards requests...
  498. virtual NTSTATUS send(CIoPacket* Irp)
  499. {
  500. TRACE("WDM sendRequestToDevice()\n");
  501. if(Irp) return forward(Irp->getIrpHandle(),NULL);
  502. else return STATUS_INVALID_PARAMETER;
  503. };
  504. virtual NTSTATUS sendAndWait(CIoPacket* Irp)
  505. {
  506. TRACE("WDM sendRequestToDeviceAndWait()\n");
  507. if(Irp) return forwardAndWait(Irp->getIrpHandle());
  508. else return STATUS_INVALID_PARAMETER;
  509. };
  510. // Define device interface functions
  511. virtual NTSTATUS write(PUCHAR pRequest,ULONG RequestLength)
  512. {
  513. CIoPacket* IoPacket;
  514. if(!pRequest || !RequestLength) return STATUS_INVALID_PARAMETER;
  515. IoPacket = new (NonPagedPool) CIoPacket(getLowerDriver()->StackSize);
  516. if(!ALLOCATED_OK(IoPacket))
  517. {
  518. DISPOSE_OBJECT(IoPacket);
  519. return STATUS_INSUFFICIENT_RESOURCES;
  520. }
  521. TRACE("IoPacket with device %x\n",getSystemObject());
  522. IoPacket->setTimeout(getCommandTimeout());
  523. IoPacket->buildStack(getSystemObject(),IRP_MJ_WRITE);
  524. IoPacket->setWriteLength(RequestLength);
  525. IoPacket->copyBuffer(pRequest,RequestLength);
  526. TRACE("WDM write()...\n");
  527. NTSTATUS status = send(IoPacket);
  528. TRACE("WDM write finished: %x\n", status);
  529. DISPOSE_OBJECT(IoPacket);
  530. return status;
  531. };
  532. virtual NTSTATUS writeAndWait(PUCHAR pRequest,ULONG RequestLength,PUCHAR pReply,ULONG* pReplyLength)
  533. {
  534. CIoPacket* IoPacket;
  535. if(!pRequest || !RequestLength || !pReply || !pReplyLength) return STATUS_INVALID_PARAMETER;
  536. IoPacket = new (NonPagedPool) CIoPacket(getLowerDriver()->StackSize);
  537. if(!ALLOCATED_OK(IoPacket))
  538. {
  539. DISPOSE_OBJECT(IoPacket);
  540. return STATUS_INSUFFICIENT_RESOURCES;
  541. }
  542. TRACE("IoPacket with device %x\n",getSystemObject());
  543. IoPacket->setTimeout(getCommandTimeout());
  544. IoPacket->buildStack(getSystemObject(),IRP_MJ_WRITE);
  545. IoPacket->setWriteLength(RequestLength);
  546. IoPacket->copyBuffer(pRequest,RequestLength);
  547. TRACE("WDM sendAndWait()...\n");
  548. NTSTATUS status = sendAndWait(IoPacket);
  549. TRACE("WDM writeAndWait finished: %x\n",status);
  550. if(!NT_SUCCESS(status))
  551. {
  552. *pReplyLength = 0;
  553. DISPOSE_OBJECT(IoPacket);
  554. return status;
  555. }
  556. *pReplyLength = (ULONG)IoPacket->getInformation();
  557. IoPacket->getSystemReply(pReply,*pReplyLength);
  558. //TRACE_BUFFER(pReply,*pReplyLength);
  559. DISPOSE_OBJECT(IoPacket);
  560. return status;
  561. };
  562. virtual NTSTATUS readAndWait(PUCHAR pRequest,ULONG RequestLength,PUCHAR pReply,ULONG* pReplyLength)
  563. {
  564. CIoPacket* IoPacket;
  565. if(!pRequest || !RequestLength || !pReply || !pReplyLength) return STATUS_INVALID_PARAMETER;
  566. IoPacket = new (NonPagedPool) CIoPacket(getLowerDriver()->StackSize);
  567. if(!ALLOCATED_OK(IoPacket))
  568. {
  569. DISPOSE_OBJECT(IoPacket);
  570. return STATUS_INSUFFICIENT_RESOURCES;
  571. }
  572. IoPacket->setTimeout(getCommandTimeout());
  573. IoPacket->buildStack(getSystemObject(),IRP_MJ_READ);
  574. IoPacket->setReadLength(RequestLength);
  575. IoPacket->copyBuffer(pRequest,RequestLength);
  576. TRACE("WDM sendAndWait()...\n");
  577. NTSTATUS status = sendAndWait(IoPacket);
  578. TRACE("WDM sendAndWait finished: %x\n",status);
  579. if(!NT_SUCCESS(status))
  580. {
  581. *pReplyLength = 0;
  582. DISPOSE_OBJECT(IoPacket);
  583. return status;
  584. }
  585. *pReplyLength = (ULONG)IoPacket->getInformation();
  586. IoPacket->getSystemReply(pReply,*pReplyLength);
  587. TRACE_BUFFER(pReply,*pReplyLength);
  588. DISPOSE_OBJECT(IoPacket);
  589. return status;
  590. };
  591. NTSTATUS synchronizeDevicePowerState()
  592. {
  593. if (m_CurrentDevicePowerState!=PowerDeviceD0)
  594. {
  595. NTSTATUS status;
  596. TRACE("RESTORING DEVICE POWER ON from state %d!\n",m_CurrentDevicePowerState);
  597. status = sendDeviceSetPower(PowerDeviceD0,TRUE);
  598. if(!NT_SUCCESS(status))
  599. {
  600. TRACE("FAILED TO SET POWER ON DEVICE STATE!\n");
  601. return status;
  602. }
  603. }
  604. return STATUS_SUCCESS;
  605. }
  606. NTSTATUS sendDeviceSetPower(DEVICE_POWER_STATE devicePower, BOOLEAN wait)
  607. {// SendDeviceSetPower
  608. POWER_STATE state;
  609. NTSTATUS status;
  610. state.DeviceState = devicePower;
  611. if (wait)
  612. {// synchronous operation
  613. KEVENT Event;
  614. event->initialize(&Event, NotificationEvent, FALSE);
  615. POWER_CONTEXT context = {&Event};
  616. status = power->requestPowerIrp(getPhysicalObject(), IRP_MN_SET_POWER, state,
  617. (PREQUEST_POWER_COMPLETE) onSendDeviceSetPowerComplete, &context, NULL);
  618. if (status == STATUS_PENDING)
  619. {
  620. event->waitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  621. status = context.status;
  622. }
  623. }// synchronous operation
  624. else
  625. status = power->requestPowerIrp(getPhysicalObject(), IRP_MN_SET_POWER,
  626. state, NULL, NULL, NULL);
  627. return status;
  628. }// SendDeviceSetPower
  629. // These functions define default interface with system.
  630. // Clients should redefine them if they would like to have
  631. // specific functionality.
  632. virtual NTSTATUS pnpRequest(IN PIRP irp){return PnP_Default(irp);};
  633. virtual NTSTATUS powerRequest(PIRP irp) {return power_Default(irp);};
  634. // By default we allow user to get connection with device
  635. virtual NTSTATUS open(PIRP irp) {return completeDeviceRequest(irp, STATUS_SUCCESS, 0); };//Create
  636. virtual NTSTATUS close(PIRP irp){return completeDeviceRequest(irp, STATUS_SUCCESS, 0); };
  637. virtual NTSTATUS read(PIRP irp) { return device_Default(irp); };
  638. virtual NTSTATUS write(PIRP irp) { return device_Default(irp); };
  639. virtual NTSTATUS deviceControl(PIRP irp) { return device_Default(irp);};
  640. virtual NTSTATUS cleanup(PIRP irp) { return device_Default(irp); };
  641. virtual NTSTATUS flush(PIRP irp) { return device_Default(irp); };
  642. // Standard system startIo
  643. // Actually we do not use it for now.
  644. // Instead we have our own synchronization facilities.
  645. virtual VOID startIo(PIRP irp){};
  646. //---------------------------------------------------------------------------//
  647. // SYNCHRONIZATION FACILITIES //
  648. //---------------------------------------------------------------------------//
  649. // To make synchronization at the driver we have to store and make pending
  650. // all our requests.
  651. // Specific devices should set specific thread which will start all pending Irp.
  652. //---------------------------------------------------------------------------//
  653. // CALLBACK FUNCTION:
  654. // This function will not only complete current Irp but also will dispose
  655. // corresponding IoRequest if any was pending at driver.
  656. #pragma LOCKEDCODE
  657. virtual VOID cancelPendingIrp(PIRP Irp)
  658. {
  659. KIRQL ioIrql;
  660. // 1.
  661. // We keep pending Irp inside list of IoRequests.
  662. // So we do not need to warry about removing Irp from a queue...
  663. // 2.
  664. // As soon as IoRequest started, we do not allow to cancel it.
  665. // So, in this case this function will not be called and it is responsibility
  666. // of the driver to finish (or cancel) active IoRequest.
  667. // It means this function should not warry about active (and removed from our queue)
  668. // IoRequests. But it has to warry about not yet started requests...
  669. TRACE(" CANCELLING IRP %8.8lX...\n", Irp);
  670. // Release cancel spin lock if somebody own it...
  671. lock->releaseCancelSpinLock(Irp->CancelIrql);
  672. // Get our own spin lock in case somebody desided to cancel this Irp
  673. lock->acquireCancelSpinLock(&ioIrql);
  674. // Reset our cancel routine to prevent it being called...
  675. irp->setCancelRoutine(Irp, NULL);
  676. // If Irp was on the queue - remove IoRequest from queue...
  677. if(m_IoRequests)
  678. {
  679. CPendingIRP* IrpReq = m_IoRequests->getFirst();
  680. while (IrpReq)
  681. {
  682. if(IrpReq->Irp == Irp)
  683. { // We found our Irp.
  684. m_IoRequests->remove(IrpReq);
  685. TRACE(" IO REQUEST WAS DISPOSED...\n");
  686. IrpReq->dispose();
  687. break;
  688. }
  689. IrpReq = m_IoRequests->getNext(IrpReq);
  690. }
  691. }
  692. if(m_OpenSessionIrp == Irp)
  693. {
  694. TRACE(" OPEN SESSION IRP WAS CANCELLED...\n");
  695. m_OpenSessionIrp = NULL;
  696. }
  697. // Complete Irp as canceled...
  698. Irp->IoStatus.Status = STATUS_CANCELLED;
  699. Irp->IoStatus.Information = 0;
  700. // Release our spin lock...
  701. lock->releaseCancelSpinLock(ioIrql);
  702. TRACE(" IRP %8.8lX WAS CANCELLED...\n", Irp);
  703. irp->completeRequest(Irp, IO_NO_INCREMENT);
  704. };
  705. #pragma PAGEDCODE
  706. virtual CLinkedList<CPendingIRP>* getIoRequestsQueue()
  707. {
  708. return m_IoRequests;
  709. };
  710. virtual NTSTATUS makeRequestPending(PIRP Irp_request,PDEVICE_OBJECT toDeviceObject,PENDING_REQUEST_TYPE Type)
  711. {
  712. KIRQL OldIrql;
  713. lock->acquireCancelSpinLock(&OldIrql);
  714. if (Irp_request->Cancel)
  715. {
  716. TRACE(" <<<<<< IO REQUEST CANCELLED... %8.8lX>>>>>>\n",Irp_request);
  717. lock->releaseCancelSpinLock(OldIrql);
  718. return STATUS_CANCELLED;
  719. }
  720. else
  721. {
  722. TRACE(" <<<<<< IO REQUEST PENDING %8.8lX>>>>>>\n",Irp_request);
  723. CPendingIRP* IrpReq = new (NonPagedPool) CPendingIRP(Irp_request,Type,toDeviceObject);
  724. if(!IrpReq)
  725. {
  726. lock->releaseCancelSpinLock(OldIrql);
  727. TRACE("ERROR! FAILED TO ALLOCATE IoRequest. LOW ON MEMORY!\n");
  728. return completeDeviceRequest(Irp_request,STATUS_INSUFFICIENT_RESOURCES,0);
  729. }
  730. Irp_request->IoStatus.Information=0;
  731. Irp_request->IoStatus.Status=STATUS_PENDING;
  732. irp->setCancelRoutine(Irp_request, CALLBACK_FUNCTION(cancelPendingIrp));
  733. lock->releaseCancelSpinLock(OldIrql);
  734. irp->markPending(Irp_request);
  735. m_IoRequests->New(IrpReq);
  736. return STATUS_PENDING;
  737. }
  738. };
  739. // Cancel current pending IO request
  740. virtual NTSTATUS cancelPendingRequest(CPendingIRP* IrpReq)
  741. {
  742. // Next function will remove and dispose our request...
  743. cancelPendingIrp(IrpReq->Irp);
  744. return STATUS_CANCELLED;
  745. };
  746. // Cancel all pending IO requests
  747. virtual NTSTATUS cancelAllPendingRequests()
  748. {
  749. // Next function will remove and dispose our request...
  750. if(m_IoRequests)
  751. {
  752. CPendingIRP* IrpReqNext;
  753. CPendingIRP* IrpReq = m_IoRequests->getFirst();
  754. while (IrpReq)
  755. {
  756. IrpReqNext = m_IoRequests->getNext(IrpReq);
  757. cancelPendingRequest(IrpReq);// This call will dispose request...
  758. IrpReq = IrpReqNext;
  759. }
  760. }
  761. if(m_OpenSessionIrp) cancelPendingIrp(m_OpenSessionIrp);
  762. return STATUS_CANCELLED;
  763. };
  764. // Checks if request queue is empty and if it is NOT - starts next request...
  765. // This function will be called by the Irp processing thread.
  766. virtual NTSTATUS startNextPendingRequest()
  767. {
  768. TRACE(" startNextPendingRequest() was called...\n");
  769. if (!m_IoRequests->IsEmpty())
  770. {
  771. KIRQL OldIrql;
  772. CDevice* device;
  773. NTSTATUS status;
  774. CPendingIRP* IrpReq = m_IoRequests->removeHead();
  775. if(!IrpReq) return STATUS_INVALID_PARAMETER;
  776. lock->acquireCancelSpinLock(&OldIrql);
  777. // Now Irp can not be canceled!
  778. irp->setCancelRoutine(IrpReq->Irp, NULL);
  779. if (IrpReq->Irp->Cancel)
  780. {
  781. lock->releaseCancelSpinLock(OldIrql);
  782. // Current Irp was already canceled,
  783. // Cancel function will be called shortly.
  784. // So just forget about current Irp.
  785. return STATUS_SUCCESS;;
  786. }
  787. lock->releaseCancelSpinLock(OldIrql);
  788. device = (CDevice*)IrpReq->DeviceObject->DeviceExtension;
  789. // Call device specific startIo function...
  790. TRACE(" Device startIoRequest() was called...\n");
  791. if(device) status = device->startIoRequest(IrpReq);
  792. else status = STATUS_INVALID_DEVICE_STATE;
  793. return status;
  794. }
  795. return STATUS_SUCCESS;
  796. };
  797. virtual NTSTATUS ThreadRoutine()
  798. {
  799. //NTSTATUS status;
  800. //if(!NT_SUCCESS(status = waitForIdleAndBlock())) return status;
  801. // If somebody inserted pending request - dispatch it...
  802. // It will call specific child device startIoRequest().
  803. // It is up to that device how to handle it.
  804. // If child device is busy - it can insert this request into
  805. // child device request queue again and process it later...
  806. startNextPendingRequest();
  807. //setIdle();
  808. return STATUS_SUCCESS;
  809. };
  810. // Device specific function which processes pending requests...
  811. // It will be redefined by specific devices.
  812. // This function always should be virtual because
  813. // we expect specific device behaviour...
  814. virtual NTSTATUS startIoRequest(CPendingIRP* IoReq)
  815. {
  816. // Default startIo just cancel current request.
  817. // IoReq will be disposed...
  818. if(IoReq)
  819. {
  820. cancelPendingRequest(IoReq);
  821. }
  822. return STATUS_SUCCESS;
  823. };
  824. };
  825. #endif //If not defined