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.

952 lines
29 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. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  483. return STATUS_INSUFFICIENT_RESOURCES;
  484. }
  485. IoPacket->setCurrentStack();
  486. IoPacket->setStackDefaults();
  487. NTSTATUS status = system->callDriver(getLowerDriver(),IoPacket->getIrpHandle());
  488. if(status == STATUS_PENDING)
  489. {
  490. TRACE("Waiting for the bus driver to complete...\n");
  491. ASSERT(system->getCurrentIrql()<=DISPATCH_LEVEL);
  492. status = IoPacket->waitForCompletion();
  493. TRACE("Request completed with status %x\n",status);
  494. }
  495. DISPOSE_OBJECT(IoPacket);
  496. return status;
  497. };
  498. // WDM by default just forwards requests...
  499. virtual NTSTATUS send(CIoPacket* Irp)
  500. {
  501. TRACE("WDM sendRequestToDevice()\n");
  502. if(Irp) return forward(Irp->getIrpHandle(),NULL);
  503. else return STATUS_INVALID_PARAMETER;
  504. };
  505. virtual NTSTATUS sendAndWait(CIoPacket* Irp)
  506. {
  507. TRACE("WDM sendRequestToDeviceAndWait()\n");
  508. if(Irp) return forwardAndWait(Irp->getIrpHandle());
  509. else return STATUS_INVALID_PARAMETER;
  510. };
  511. // Define device interface functions
  512. virtual NTSTATUS write(PUCHAR pRequest,ULONG RequestLength)
  513. {
  514. CIoPacket* IoPacket;
  515. if(!pRequest || !RequestLength) return STATUS_INVALID_PARAMETER;
  516. IoPacket = new (NonPagedPool) CIoPacket(getLowerDriver()->StackSize);
  517. if(!ALLOCATED_OK(IoPacket))
  518. {
  519. DISPOSE_OBJECT(IoPacket);
  520. return STATUS_INSUFFICIENT_RESOURCES;
  521. }
  522. TRACE("IoPacket with device %x\n",getSystemObject());
  523. IoPacket->setTimeout(getCommandTimeout());
  524. IoPacket->buildStack(getSystemObject(),IRP_MJ_WRITE);
  525. IoPacket->setWriteLength(RequestLength);
  526. IoPacket->copyBuffer(pRequest,RequestLength);
  527. TRACE("WDM write()...\n");
  528. NTSTATUS status = send(IoPacket);
  529. TRACE("WDM write finished: %x\n", status);
  530. DISPOSE_OBJECT(IoPacket);
  531. return status;
  532. };
  533. virtual NTSTATUS writeAndWait(PUCHAR pRequest,ULONG RequestLength,PUCHAR pReply,ULONG* pReplyLength)
  534. {
  535. CIoPacket* IoPacket;
  536. if(!pRequest || !RequestLength || !pReply || !pReplyLength) return STATUS_INVALID_PARAMETER;
  537. IoPacket = new (NonPagedPool) CIoPacket(getLowerDriver()->StackSize);
  538. if(!ALLOCATED_OK(IoPacket))
  539. {
  540. DISPOSE_OBJECT(IoPacket);
  541. return STATUS_INSUFFICIENT_RESOURCES;
  542. }
  543. TRACE("IoPacket with device %x\n",getSystemObject());
  544. IoPacket->setTimeout(getCommandTimeout());
  545. IoPacket->buildStack(getSystemObject(),IRP_MJ_WRITE);
  546. IoPacket->setWriteLength(RequestLength);
  547. IoPacket->copyBuffer(pRequest,RequestLength);
  548. TRACE("WDM sendAndWait()...\n");
  549. NTSTATUS status = sendAndWait(IoPacket);
  550. TRACE("WDM writeAndWait finished: %x\n",status);
  551. if(!NT_SUCCESS(status))
  552. {
  553. *pReplyLength = 0;
  554. DISPOSE_OBJECT(IoPacket);
  555. return status;
  556. }
  557. *pReplyLength = (ULONG)IoPacket->getInformation();
  558. IoPacket->getSystemReply(pReply,*pReplyLength);
  559. //TRACE_BUFFER(pReply,*pReplyLength);
  560. DISPOSE_OBJECT(IoPacket);
  561. return status;
  562. };
  563. virtual NTSTATUS readAndWait(PUCHAR pRequest,ULONG RequestLength,PUCHAR pReply,ULONG* pReplyLength)
  564. {
  565. CIoPacket* IoPacket;
  566. if(!pRequest || !RequestLength || !pReply || !pReplyLength) return STATUS_INVALID_PARAMETER;
  567. IoPacket = new (NonPagedPool) CIoPacket(getLowerDriver()->StackSize);
  568. if(!ALLOCATED_OK(IoPacket))
  569. {
  570. DISPOSE_OBJECT(IoPacket);
  571. return STATUS_INSUFFICIENT_RESOURCES;
  572. }
  573. IoPacket->setTimeout(getCommandTimeout());
  574. IoPacket->buildStack(getSystemObject(),IRP_MJ_READ);
  575. IoPacket->setReadLength(RequestLength);
  576. IoPacket->copyBuffer(pRequest,RequestLength);
  577. TRACE("WDM sendAndWait()...\n");
  578. NTSTATUS status = sendAndWait(IoPacket);
  579. TRACE("WDM sendAndWait finished: %x\n",status);
  580. if(!NT_SUCCESS(status))
  581. {
  582. *pReplyLength = 0;
  583. DISPOSE_OBJECT(IoPacket);
  584. return status;
  585. }
  586. *pReplyLength = (ULONG)IoPacket->getInformation();
  587. IoPacket->getSystemReply(pReply,*pReplyLength);
  588. TRACE_BUFFER(pReply,*pReplyLength);
  589. DISPOSE_OBJECT(IoPacket);
  590. return status;
  591. };
  592. NTSTATUS synchronizeDevicePowerState()
  593. {
  594. if (m_CurrentDevicePowerState!=PowerDeviceD0)
  595. {
  596. NTSTATUS status;
  597. TRACE("RESTORING DEVICE POWER ON from state %d!\n",m_CurrentDevicePowerState);
  598. status = sendDeviceSetPower(PowerDeviceD0,TRUE);
  599. if(!NT_SUCCESS(status))
  600. {
  601. TRACE("FAILED TO SET POWER ON DEVICE STATE!\n");
  602. return status;
  603. }
  604. }
  605. return STATUS_SUCCESS;
  606. }
  607. NTSTATUS sendDeviceSetPower(DEVICE_POWER_STATE devicePower, BOOLEAN wait)
  608. {// SendDeviceSetPower
  609. POWER_STATE state;
  610. NTSTATUS status;
  611. state.DeviceState = devicePower;
  612. if (wait)
  613. {// synchronous operation
  614. KEVENT Event;
  615. event->initialize(&Event, NotificationEvent, FALSE);
  616. POWER_CONTEXT context = {&Event};
  617. status = power->requestPowerIrp(getPhysicalObject(), IRP_MN_SET_POWER, state,
  618. (PREQUEST_POWER_COMPLETE) onSendDeviceSetPowerComplete, &context, NULL);
  619. if (status == STATUS_PENDING)
  620. {
  621. event->waitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  622. status = context.status;
  623. }
  624. }// synchronous operation
  625. else
  626. status = power->requestPowerIrp(getPhysicalObject(), IRP_MN_SET_POWER,
  627. state, NULL, NULL, NULL);
  628. return status;
  629. }// SendDeviceSetPower
  630. // These functions define default interface with system.
  631. // Clients should redefine them if they would like to have
  632. // specific functionality.
  633. virtual NTSTATUS pnpRequest(IN PIRP irp){return PnP_Default(irp);};
  634. virtual NTSTATUS powerRequest(PIRP irp) {return power_Default(irp);};
  635. // By default we allow user to get connection with device
  636. virtual NTSTATUS open(PIRP irp) {return completeDeviceRequest(irp, STATUS_SUCCESS, 0); };//Create
  637. virtual NTSTATUS close(PIRP irp){return completeDeviceRequest(irp, STATUS_SUCCESS, 0); };
  638. virtual NTSTATUS read(PIRP irp) { return device_Default(irp); };
  639. virtual NTSTATUS write(PIRP irp) { return device_Default(irp); };
  640. virtual NTSTATUS deviceControl(PIRP irp) { return device_Default(irp);};
  641. virtual NTSTATUS cleanup(PIRP irp) { return device_Default(irp); };
  642. virtual NTSTATUS flush(PIRP irp) { return device_Default(irp); };
  643. // Standard system startIo
  644. // Actually we do not use it for now.
  645. // Instead we have our own synchronization facilities.
  646. virtual VOID startIo(PIRP irp){};
  647. //---------------------------------------------------------------------------//
  648. // SYNCHRONIZATION FACILITIES //
  649. //---------------------------------------------------------------------------//
  650. // To make synchronization at the driver we have to store and make pending
  651. // all our requests.
  652. // Specific devices should set specific thread which will start all pending Irp.
  653. //---------------------------------------------------------------------------//
  654. // CALLBACK FUNCTION:
  655. // This function will not only complete current Irp but also will dispose
  656. // corresponding IoRequest if any was pending at driver.
  657. #pragma LOCKEDCODE
  658. virtual VOID cancelPendingIrp(PIRP Irp)
  659. {
  660. KIRQL ioIrql;
  661. // 1.
  662. // We keep pending Irp inside list of IoRequests.
  663. // So we do not need to warry about removing Irp from a queue...
  664. // 2.
  665. // As soon as IoRequest started, we do not allow to cancel it.
  666. // So, in this case this function will not be called and it is responsibility
  667. // of the driver to finish (or cancel) active IoRequest.
  668. // It means this function should not warry about active (and removed from our queue)
  669. // IoRequests. But it has to warry about not yet started requests...
  670. TRACE(" CANCELLING IRP %8.8lX...\n", Irp);
  671. // Release cancel spin lock if somebody own it...
  672. lock->releaseCancelSpinLock(Irp->CancelIrql);
  673. // Get our own spin lock in case somebody desided to cancel this Irp
  674. lock->acquireCancelSpinLock(&ioIrql);
  675. // Reset our cancel routine to prevent it being called...
  676. irp->setCancelRoutine(Irp, NULL);
  677. // If Irp was on the queue - remove IoRequest from queue...
  678. if(m_IoRequests)
  679. {
  680. CPendingIRP* IrpReq = m_IoRequests->getFirst();
  681. while (IrpReq)
  682. {
  683. if(IrpReq->Irp == Irp)
  684. { // We found our Irp.
  685. m_IoRequests->remove(IrpReq);
  686. TRACE(" IO REQUEST WAS DISPOSED...\n");
  687. IrpReq->dispose();
  688. break;
  689. }
  690. IrpReq = m_IoRequests->getNext(IrpReq);
  691. }
  692. }
  693. if(m_OpenSessionIrp == Irp)
  694. {
  695. TRACE(" OPEN SESSION IRP WAS CANCELLED...\n");
  696. m_OpenSessionIrp = NULL;
  697. }
  698. // Complete Irp as canceled...
  699. Irp->IoStatus.Status = STATUS_CANCELLED;
  700. Irp->IoStatus.Information = 0;
  701. // Release our spin lock...
  702. lock->releaseCancelSpinLock(ioIrql);
  703. TRACE(" IRP %8.8lX WAS CANCELLED...\n", Irp);
  704. irp->completeRequest(Irp, IO_NO_INCREMENT);
  705. };
  706. #pragma PAGEDCODE
  707. virtual CLinkedList<CPendingIRP>* getIoRequestsQueue()
  708. {
  709. return m_IoRequests;
  710. };
  711. virtual NTSTATUS makeRequestPending(PIRP Irp_request,PDEVICE_OBJECT toDeviceObject,PENDING_REQUEST_TYPE Type)
  712. {
  713. KIRQL OldIrql;
  714. lock->acquireCancelSpinLock(&OldIrql);
  715. if (Irp_request->Cancel)
  716. {
  717. TRACE(" <<<<<< IO REQUEST CANCELLED... %8.8lX>>>>>>\n",Irp_request);
  718. lock->releaseCancelSpinLock(OldIrql);
  719. return STATUS_CANCELLED;
  720. }
  721. else
  722. {
  723. TRACE(" <<<<<< IO REQUEST PENDING %8.8lX>>>>>>\n",Irp_request);
  724. CPendingIRP* IrpReq = new (NonPagedPool) CPendingIRP(Irp_request,Type,toDeviceObject);
  725. if(!IrpReq)
  726. {
  727. lock->releaseCancelSpinLock(OldIrql);
  728. TRACE("ERROR! FAILED TO ALLOCATE IoRequest. LOW ON MEMORY!\n");
  729. return completeDeviceRequest(Irp_request,STATUS_INSUFFICIENT_RESOURCES,0);
  730. }
  731. Irp_request->IoStatus.Information=0;
  732. Irp_request->IoStatus.Status=STATUS_PENDING;
  733. irp->setCancelRoutine(Irp_request, CALLBACK_FUNCTION(cancelPendingIrp));
  734. lock->releaseCancelSpinLock(OldIrql);
  735. irp->markPending(Irp_request);
  736. m_IoRequests->New(IrpReq);
  737. return STATUS_PENDING;
  738. }
  739. };
  740. // Cancel current pending IO request
  741. virtual NTSTATUS cancelPendingRequest(CPendingIRP* IrpReq)
  742. {
  743. // Next function will remove and dispose our request...
  744. cancelPendingIrp(IrpReq->Irp);
  745. return STATUS_CANCELLED;
  746. };
  747. // Cancel all pending IO requests
  748. virtual NTSTATUS cancelAllPendingRequests()
  749. {
  750. // Next function will remove and dispose our request...
  751. if(m_IoRequests)
  752. {
  753. CPendingIRP* IrpReqNext;
  754. CPendingIRP* IrpReq = m_IoRequests->getFirst();
  755. while (IrpReq)
  756. {
  757. IrpReqNext = m_IoRequests->getNext(IrpReq);
  758. cancelPendingRequest(IrpReq);// This call will dispose request...
  759. IrpReq = IrpReqNext;
  760. }
  761. }
  762. if(m_OpenSessionIrp) cancelPendingIrp(m_OpenSessionIrp);
  763. return STATUS_CANCELLED;
  764. };
  765. // Checks if request queue is empty and if it is NOT - starts next request...
  766. // This function will be called by the Irp processing thread.
  767. virtual NTSTATUS startNextPendingRequest()
  768. {
  769. TRACE(" startNextPendingRequest() was called...\n");
  770. if (!m_IoRequests->IsEmpty())
  771. {
  772. KIRQL OldIrql;
  773. CDevice* device;
  774. NTSTATUS status;
  775. CPendingIRP* IrpReq = m_IoRequests->removeHead();
  776. if(!IrpReq) return STATUS_INVALID_PARAMETER;
  777. lock->acquireCancelSpinLock(&OldIrql);
  778. // Now Irp can not be canceled!
  779. irp->setCancelRoutine(IrpReq->Irp, NULL);
  780. if (IrpReq->Irp->Cancel)
  781. {
  782. lock->releaseCancelSpinLock(OldIrql);
  783. // Current Irp was already canceled,
  784. // Cancel function will be called shortly.
  785. // So just forget about current Irp.
  786. return STATUS_SUCCESS;;
  787. }
  788. lock->releaseCancelSpinLock(OldIrql);
  789. device = (CDevice*)IrpReq->DeviceObject->DeviceExtension;
  790. // Call device specific startIo function...
  791. TRACE(" Device startIoRequest() was called...\n");
  792. if(device) status = device->startIoRequest(IrpReq);
  793. else status = STATUS_INVALID_DEVICE_STATE;
  794. return status;
  795. }
  796. return STATUS_SUCCESS;
  797. };
  798. virtual NTSTATUS ThreadRoutine()
  799. {
  800. //NTSTATUS status;
  801. //if(!NT_SUCCESS(status = waitForIdleAndBlock())) return status;
  802. // If somebody inserted pending request - dispatch it...
  803. // It will call specific child device startIoRequest().
  804. // It is up to that device how to handle it.
  805. // If child device is busy - it can insert this request into
  806. // child device request queue again and process it later...
  807. startNextPendingRequest();
  808. //setIdle();
  809. return STATUS_SUCCESS;
  810. };
  811. // Device specific function which processes pending requests...
  812. // It will be redefined by specific devices.
  813. // This function always should be virtual because
  814. // we expect specific device behaviour...
  815. virtual NTSTATUS startIoRequest(CPendingIRP* IoReq)
  816. {
  817. // Default startIo just cancel current request.
  818. // IoReq will be disposed...
  819. if(IoReq)
  820. {
  821. cancelPendingRequest(IoReq);
  822. }
  823. return STATUS_SUCCESS;
  824. };
  825. };
  826. #endif //If not defined