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.

770 lines
18 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. serscan.c
  5. Abstract:
  6. This module contains the code for a serial imaging devices
  7. suport class driver.
  8. Author:
  9. Vlad Sadovsky vlads 10-April-1998
  10. Environment:
  11. Kernel mode
  12. Revision History :
  13. vlads 04/10/1998 Created first draft
  14. --*/
  15. #include "serscan.h"
  16. #include "serlog.h"
  17. #include <initguid.h>
  18. #include <devguid.h>
  19. #include <wiaintfc.h>
  20. #if DBG
  21. ULONG SerScanDebugLevel = -1;
  22. #endif
  23. const PHYSICAL_ADDRESS PhysicalZero = {0};
  24. //
  25. // Keep track of the number of Serial port devices created...
  26. //
  27. ULONG g_NumPorts = 0;
  28. //
  29. // Definition of OpenCloseMutex.
  30. //
  31. extern ULONG OpenCloseReferenceCount = 1;
  32. extern PFAST_MUTEX OpenCloseMutex = NULL;
  33. //
  34. //
  35. #ifdef ALLOC_PRAGMA
  36. #pragma alloc_text(INIT, DriverEntry)
  37. #pragma alloc_text(PAGE, SerScanAddDevice)
  38. #endif
  39. NTSTATUS
  40. DriverEntry(
  41. IN PDRIVER_OBJECT DriverObject,
  42. IN PUNICODE_STRING RegistryPath
  43. )
  44. /*++
  45. Routine Description:
  46. This routine is called at system initialization time to initialize
  47. this driver.
  48. Arguments:
  49. DriverObject - Supplies the driver object.
  50. RegistryPath - Supplies the registry path for this driver.
  51. Return Value:
  52. STATUS_SUCCESS - We could initialize at least one device.
  53. STATUS_NO_SUCH_DEVICE - We could not in itialize even one device.
  54. --*/
  55. {
  56. int i;
  57. PAGED_CODE();
  58. #if DBG
  59. DebugDump(SERINITDEV,("Entering DriverEntry\n"));
  60. #endif
  61. //
  62. // Initialize the Driver Object with driver's entry points
  63. //
  64. DriverObject->DriverExtension->AddDevice = SerScanAddDevice;
  65. DriverObject->DriverUnload = SerScanUnload;
  66. #ifdef DEAD_CODE
  67. for (i=0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
  68. DriverObject->MajorFunction[i]= SerScanPassThrough;
  69. }
  70. #endif
  71. DriverObject->MajorFunction[IRP_MJ_CREATE] = SerScanCreateOpen;
  72. DriverObject->MajorFunction[IRP_MJ_CLOSE] = SerScanClose;
  73. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SerScanDeviceControl;
  74. DriverObject->MajorFunction[IRP_MJ_PNP] = SerScanPnp;
  75. DriverObject->MajorFunction[IRP_MJ_POWER] = SerScanPower;
  76. //
  77. // Following are possibly not needed, keep them here to allow
  78. // easier tracing in when debugging. All of them resort to pass-through
  79. // behaviour
  80. //
  81. #ifdef DEAD_CODE
  82. DriverObject->MajorFunction[IRP_MJ_CLEANUP] = SerScanCleanup;
  83. DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = SerScanQueryInformationFile;
  84. DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = SerScanSetInformationFile;
  85. #endif
  86. DriverObject->MajorFunction[IRP_MJ_READ] = SerScanPassThrough;
  87. DriverObject->MajorFunction[IRP_MJ_WRITE] = SerScanPassThrough;
  88. return STATUS_SUCCESS;
  89. }
  90. NTSTATUS
  91. SerScanAddDevice(
  92. IN PDRIVER_OBJECT pDriverObject,
  93. IN PDEVICE_OBJECT pPhysicalDeviceObject
  94. )
  95. /*++
  96. Routine Description:
  97. This routine is called to create a new instance of the device.
  98. It creates FDO and attaches it to PDO
  99. Arguments:
  100. pDriverObject - pointer to the driver object for this instance of port.
  101. pPhysicalDeviceObject - pointer to the device object that represents the port.
  102. Return Value:
  103. STATUS_SUCCESS - if successful.
  104. STATUS_UNSUCCESSFUL - otherwise.
  105. --*/
  106. {
  107. UNICODE_STRING ClassName;
  108. UNICODE_STRING LinkName;
  109. NTSTATUS Status;
  110. PDEVICE_EXTENSION Extension;
  111. PDEVICE_OBJECT pDeviceObject;
  112. PAGED_CODE();
  113. DebugDump(SERINITDEV,("Entering AddDevice\n"));
  114. //
  115. // Get the Class and Link names.
  116. //
  117. if (!SerScanMakeNames (g_NumPorts, &ClassName, &LinkName)) {
  118. SerScanLogError(pDriverObject,
  119. NULL,
  120. PhysicalZero,
  121. PhysicalZero,
  122. 0,
  123. 0,
  124. 0,
  125. 1,
  126. STATUS_SUCCESS,
  127. SER_INSUFFICIENT_RESOURCES);
  128. DebugDump(SERERRORS,("SerScan: Could not form Unicode name strings.\n"));
  129. return STATUS_INSUFFICIENT_RESOURCES;
  130. }
  131. //
  132. // Create the device object for this device.
  133. //
  134. Status = IoCreateDevice(pDriverObject,
  135. sizeof(DEVICE_EXTENSION),
  136. &ClassName,
  137. FILE_DEVICE_SCANNER,
  138. 0,
  139. TRUE,
  140. &pDeviceObject);
  141. if (!NT_SUCCESS(Status)) {
  142. ExFreePool(ClassName.Buffer);
  143. ExFreePool(LinkName.Buffer);
  144. SerScanLogError(pDriverObject,
  145. NULL,
  146. PhysicalZero,
  147. PhysicalZero,
  148. 0,
  149. 0,
  150. 0,
  151. 9,
  152. STATUS_SUCCESS,
  153. SER_INSUFFICIENT_RESOURCES);
  154. DebugDump(SERERRORS, ("SERPORT: Could not create a device for %d\n", g_NumPorts));
  155. return Status;
  156. }
  157. //
  158. // The device object has a pointer to an area of non-paged
  159. // pool allocated for this device. This will be the device
  160. // extension.
  161. //
  162. Extension = pDeviceObject->DeviceExtension;
  163. //
  164. // Zero all of the memory associated with the device
  165. // extension.
  166. //
  167. RtlZeroMemory(Extension, sizeof(DEVICE_EXTENSION));
  168. //
  169. // Get a "back pointer" to the device object.
  170. //
  171. Extension->DeviceObject = pDeviceObject;
  172. Extension->Pdo = pPhysicalDeviceObject;
  173. Extension->AttachedDeviceObject = NULL;
  174. Extension->AttachedFileObject = NULL;
  175. //
  176. // Setup buffered I/O
  177. //
  178. pDeviceObject->Flags |= DO_BUFFERED_IO;
  179. //
  180. // Indicate our power code is pageable
  181. //
  182. pDeviceObject->Flags |= DO_POWER_PAGABLE;
  183. //
  184. // Attach our new Device to our parents stack.
  185. //
  186. Extension->LowerDevice = IoAttachDeviceToDeviceStack(
  187. pDeviceObject,
  188. pPhysicalDeviceObject);
  189. if (NULL == Extension->LowerDevice) {
  190. ExFreePool(ClassName.Buffer);
  191. ExFreePool(LinkName.Buffer);
  192. IoDeleteDevice(pDeviceObject);
  193. return STATUS_UNSUCCESSFUL;
  194. }
  195. Extension->ClassName = ClassName;
  196. Extension->SymbolicLinkName = LinkName;
  197. Status = SerScanHandleSymbolicLink(
  198. pPhysicalDeviceObject,
  199. &Extension->InterfaceNameString,
  200. TRUE
  201. );
  202. //
  203. // We have created the device, so increment the counter
  204. // that keeps track.
  205. //
  206. g_NumPorts++;
  207. //
  208. // Initiliaze the rest of device extension
  209. //
  210. Extension->ReferenceCount = 1;
  211. Extension->Removing = FALSE;
  212. Extension->OpenCount = 0;
  213. KeInitializeEvent(&Extension->RemoveEvent,
  214. NotificationEvent,
  215. FALSE
  216. );
  217. // ExInitializeResourceLite(&Extension->Resource);
  218. ExInitializeFastMutex(&Extension->Mutex);
  219. //
  220. // Clear InInit flag to indicate device object can be used
  221. //
  222. pDeviceObject->Flags &= ~(DO_DEVICE_INITIALIZING);
  223. return STATUS_SUCCESS;
  224. }
  225. BOOLEAN
  226. SerScanMakeNames(
  227. IN ULONG SerialPortNumber,
  228. OUT PUNICODE_STRING ClassName,
  229. OUT PUNICODE_STRING LinkName
  230. )
  231. /*++
  232. Routine Description:
  233. This routine generates the names \Device\SerScanN.
  234. This routine will allocate pool so that the buffers of
  235. these unicode strings need to be eventually freed.
  236. Arguments:
  237. SerialPortNumber - Supplies the serial port number.
  238. ClassName - Returns the class name.
  239. LinkName - Returns the link name.
  240. Return Value:
  241. FALSE - Failure.
  242. TRUE - Success.
  243. --*/
  244. {
  245. UNICODE_STRING Prefix;
  246. UNICODE_STRING Digits;
  247. UNICODE_STRING LinkPrefix;
  248. UNICODE_STRING LinkDigits;
  249. WCHAR DigitsBuffer[10];
  250. WCHAR LinkDigitsBuffer[10];
  251. UNICODE_STRING ClassSuffix;
  252. UNICODE_STRING LinkSuffix;
  253. NTSTATUS Status;
  254. //
  255. // Put together local variables for constructing names.
  256. //
  257. RtlInitUnicodeString(&Prefix, L"\\Device\\");
  258. RtlInitUnicodeString(&LinkPrefix, L"\\DosDevices\\");
  259. //
  260. // WORKWORK: Change the name to be device specific.
  261. //
  262. RtlInitUnicodeString(&ClassSuffix, SERSCAN_NT_SUFFIX);
  263. RtlInitUnicodeString(&LinkSuffix, SERSCAN_LINK_NAME);
  264. Digits.Length = 0;
  265. Digits.MaximumLength = 20;
  266. Digits.Buffer = DigitsBuffer;
  267. LinkDigits.Length = 0;
  268. LinkDigits.MaximumLength = 20;
  269. LinkDigits.Buffer = LinkDigitsBuffer;
  270. Status = RtlIntegerToUnicodeString(SerialPortNumber, 10, &Digits);
  271. if (!NT_SUCCESS(Status)) {
  272. return FALSE;
  273. }
  274. Status = RtlIntegerToUnicodeString(SerialPortNumber + 1, 10, &LinkDigits);
  275. if (!NT_SUCCESS(Status)) {
  276. return FALSE;
  277. }
  278. //
  279. // Make the class name.
  280. //
  281. ClassName->Length = 0;
  282. ClassName->MaximumLength = Prefix.Length + ClassSuffix.Length +
  283. Digits.Length + sizeof(WCHAR);
  284. ClassName->Buffer = ExAllocatePool(PagedPool, ClassName->MaximumLength);
  285. if (!ClassName->Buffer) {
  286. return FALSE;
  287. }
  288. RtlZeroMemory(ClassName->Buffer, ClassName->MaximumLength);
  289. RtlAppendUnicodeStringToString(ClassName, &Prefix);
  290. RtlAppendUnicodeStringToString(ClassName, &ClassSuffix);
  291. RtlAppendUnicodeStringToString(ClassName, &Digits);
  292. //
  293. // Make the link name.
  294. //
  295. LinkName->Length = 0;
  296. LinkName->MaximumLength = LinkPrefix.Length + LinkSuffix.Length +
  297. LinkDigits.Length + sizeof(WCHAR);
  298. LinkName->Buffer = ExAllocatePool(PagedPool, LinkName->MaximumLength);
  299. if (!LinkName->Buffer) {
  300. ExFreePool(ClassName->Buffer);
  301. return FALSE;
  302. }
  303. RtlZeroMemory(LinkName->Buffer, LinkName->MaximumLength);
  304. RtlAppendUnicodeStringToString(LinkName, &LinkPrefix);
  305. RtlAppendUnicodeStringToString(LinkName, &LinkSuffix);
  306. RtlAppendUnicodeStringToString(LinkName, &LinkDigits);
  307. return TRUE;
  308. }
  309. NTSTATUS
  310. SerScanCleanup(
  311. IN PDEVICE_OBJECT DeviceObject,
  312. IN PIRP Irp
  313. )
  314. /*++
  315. Routine Description:
  316. This routine is the dispatch for a cleanup requests.
  317. Arguments:
  318. DeviceObject - Supplies the device object.
  319. Irp - Supplies the I/O request packet.
  320. Return Value:
  321. STATUS_SUCCESS - Success.
  322. --*/
  323. {
  324. NTSTATUS Status;
  325. PDEVICE_EXTENSION Extension;
  326. Extension = DeviceObject->DeviceExtension;
  327. //
  328. // Call down to the parent and wait on the Cleanup IRP to complete...
  329. //
  330. Status = SerScanCallParent(Extension,
  331. Irp,
  332. WAIT,
  333. NULL);
  334. DebugDump(SERIRPPATH,
  335. ("SerScan: [Cleanup] After CallParent Status = %x\n",
  336. Status));
  337. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  338. return Status;
  339. }
  340. VOID
  341. SerScanCancelRequest(
  342. PDEVICE_OBJECT DeviceObject,
  343. PIRP Irp
  344. )
  345. /*++
  346. Routine Description:
  347. This routine is used to cancel any request in the Serial driver.
  348. Arguments:
  349. DeviceObject - Pointer to the device object for this device
  350. Irp - Pointer to the IRP to be canceled.
  351. Return Value:
  352. None.
  353. --*/
  354. {
  355. NTSTATUS Status;
  356. PDEVICE_EXTENSION Extension;
  357. Extension = DeviceObject->DeviceExtension;
  358. //
  359. // Call down to the parent and wait on the Cleanup IRP to complete...
  360. //
  361. Status = SerScanCallParent(Extension,
  362. Irp,
  363. WAIT,
  364. NULL);
  365. DebugDump(SERIRPPATH,
  366. ("SerScan: [Cleanup] After CallParent Status = %x\n",
  367. Status));
  368. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  369. return;
  370. }
  371. NTSTATUS
  372. SerScanQueryInformationFile(
  373. IN PDEVICE_OBJECT DeviceObject,
  374. IN PIRP Irp
  375. )
  376. /*++
  377. Routine Description:
  378. This routine is used to query the end of file information on
  379. the opened Serial port. Any other file information request
  380. is retured with an invalid parameter.
  381. This routine always returns an end of file of 0.
  382. Arguments:
  383. DeviceObject - Supplies the device object.
  384. Irp - Supplies the I/O request packet.
  385. Return Value:
  386. STATUS_SUCCESS - Success.
  387. STATUS_INVALID_PARAMETER - Invalid file information request.
  388. STATUS_BUFFER_TOO_SMALL - Buffer too small.
  389. --*/
  390. {
  391. NTSTATUS Status;
  392. PDEVICE_EXTENSION Extension;
  393. Extension = DeviceObject->DeviceExtension;
  394. Status = SerScanCallParent(Extension,
  395. Irp,
  396. WAIT,
  397. NULL);
  398. DebugDump(SERIRPPATH,
  399. ("SerScan: [Cleanup] After CallParent Status = %x\n",
  400. Status));
  401. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  402. return Status;
  403. }
  404. NTSTATUS
  405. SerScanSetInformationFile(
  406. IN PDEVICE_OBJECT DeviceObject,
  407. IN PIRP Irp
  408. )
  409. /*++
  410. Routine Description:
  411. This routine is used to set the end of file information on
  412. the opened Serial port. Any other file information request
  413. is retured with an invalid parameter.
  414. This routine always ignores the actual end of file since
  415. the query information code always returns an end of file of 0.
  416. Arguments:
  417. DeviceObject - Supplies the device object.
  418. Irp - Supplies the I/O request packet.
  419. Return Value:
  420. STATUS_SUCCESS - Success.
  421. STATUS_INVALID_PARAMETER - Invalid file information request.
  422. --*/
  423. {
  424. NTSTATUS Status;
  425. PDEVICE_EXTENSION Extension;
  426. Extension = DeviceObject->DeviceExtension;
  427. Status = SerScanCallParent(Extension,
  428. Irp,
  429. WAIT,
  430. NULL);
  431. DebugDump(SERIRPPATH,
  432. ("SerScan: [Cleanup] After CallParent Status = %x\n",
  433. Status));
  434. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  435. return Status;
  436. }
  437. VOID
  438. SerScanUnload(
  439. IN PDRIVER_OBJECT DriverObject
  440. )
  441. /*++
  442. Routine Description:
  443. This routine loops through the device list and cleans up after
  444. each of the devices.
  445. Arguments:
  446. DriverObject - Supplies the driver object.
  447. Return Value:
  448. None.
  449. --*/
  450. {
  451. PDEVICE_OBJECT CurrentDevice;
  452. PDEVICE_OBJECT NextDevice;
  453. PDEVICE_EXTENSION Extension;
  454. DebugDump(SERUNLOAD,
  455. ("SerScan: In SerUnload\n"));
  456. CurrentDevice = DriverObject->DeviceObject;
  457. while (NULL != CurrentDevice){
  458. Extension = CurrentDevice->DeviceExtension;
  459. if(NULL != Extension->SymbolicLinkName.Buffer){
  460. if (Extension->CreatedSymbolicLink) {
  461. IoDeleteSymbolicLink(&Extension->SymbolicLinkName);
  462. RtlDeleteRegistryValue(RTL_REGISTRY_DEVICEMAP,
  463. L"Serial Scanners",
  464. Extension->SymbolicLinkName.Buffer);
  465. } // if (Extension->CreatedSymbolicLink)
  466. ExFreePool(Extension->SymbolicLinkName.Buffer);
  467. Extension->SymbolicLinkName.Buffer = NULL;
  468. } // if(NULL != Extension->SymbolicLinkName.Buffer)
  469. if(NULL != Extension->ClassName.Buffer){
  470. ExFreePool(Extension->ClassName.Buffer);
  471. Extension->ClassName.Buffer = NULL;
  472. } // if(NULL != Extension->ClassName.Buffer)
  473. NextDevice = CurrentDevice->NextDevice;
  474. IoDeleteDevice(CurrentDevice);
  475. CurrentDevice = NextDevice;
  476. } // while (CurrentDevice = DriverObject->DeviceObject)
  477. }
  478. NTSTATUS
  479. SerScanHandleSymbolicLink(
  480. PDEVICE_OBJECT DeviceObject,
  481. PUNICODE_STRING InterfaceName,
  482. BOOLEAN Create
  483. )
  484. /*++
  485. Routine Description:
  486. Arguments:
  487. DriverObject - Supplies the driver object.
  488. Return Value:
  489. None.
  490. --*/
  491. {
  492. NTSTATUS Status;
  493. Status = STATUS_SUCCESS;
  494. if (Create) {
  495. Status=IoRegisterDeviceInterface(
  496. DeviceObject,
  497. &GUID_DEVINTERFACE_IMAGE,
  498. NULL,
  499. InterfaceName
  500. );
  501. DebugDump(SERINITDEV,("Called IoRegisterDeviceInterface . Returned=0x%X\n",Status));
  502. if (NT_SUCCESS(Status)) {
  503. IoSetDeviceInterfaceState(
  504. InterfaceName,
  505. TRUE
  506. );
  507. DebugDump(SERINITDEV,("Called IoSetDeviceInterfaceState(TRUE) . \n"));
  508. }
  509. } else {
  510. if (InterfaceName->Buffer != NULL) {
  511. IoSetDeviceInterfaceState(
  512. InterfaceName,
  513. FALSE
  514. );
  515. DebugDump(SERINITDEV,("Called IoSetDeviceInterfaceState(FALSE) . \n"));
  516. RtlFreeUnicodeString(
  517. InterfaceName
  518. );
  519. InterfaceName->Buffer = NULL;
  520. }
  521. }
  522. return Status;
  523. }