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.

633 lines
18 KiB

  1. /*
  2. *************************************************************************
  3. * File: I1394.C
  4. *
  5. * Module: HID1394.SYS
  6. * HID (Human Input Device) minidriver for IEEE 1394 devices.
  7. *
  8. * Copyright (c) 1998 Microsoft Corporation
  9. *
  10. * Author: ervinp
  11. *
  12. *************************************************************************
  13. */
  14. #include <wdm.h>
  15. #include <hidport.h>
  16. #include <1394.h>
  17. #include "hid1394.h"
  18. #include "debug.h"
  19. ULONG resetGeneration = 0;
  20. /*
  21. ********************************************************************************
  22. * HIDT_SubmitIRB
  23. ********************************************************************************
  24. *
  25. *
  26. * Submit an IRB (IO Request Block) to the IEEE 1394 bus
  27. * by sending the bus an IRP with IoControlCode==IOCTL_1394_CLASS.
  28. *
  29. */
  30. NTSTATUS HIDT_SubmitIRB(PDEVICE_OBJECT devObj, PIRB irb)
  31. {
  32. NTSTATUS status;
  33. PDEVICE_EXTENSION devExt;
  34. PIRP irp;
  35. KEVENT event;
  36. IO_STATUS_BLOCK ioStatus;
  37. devExt = GET_MINIDRIVER_DEVICE_EXTENSION(devObj);
  38. KeInitializeEvent(&event, NotificationEvent, FALSE);
  39. irp = IoBuildDeviceIoControlRequest(IOCTL_1394_CLASS,
  40. GET_NEXT_DEVICE_OBJECT(devObj),
  41. NULL,
  42. 0,
  43. NULL,
  44. 0,
  45. TRUE, /* INTERNAL */
  46. &event,
  47. &ioStatus);
  48. if (irp){
  49. PIO_STACK_LOCATION nextSp;
  50. nextSp = IoGetNextIrpStackLocation(irp);
  51. nextSp->Parameters.Others.Argument1 = irb;
  52. status = IoCallDriver(GET_NEXT_DEVICE_OBJECT(devObj), irp);
  53. if (status == STATUS_PENDING) {
  54. NTSTATUS waitStatus;
  55. /*
  56. * Specify a timeout of 5 seconds for this call to complete.
  57. * Negative timeout indicates time relative to now (in 100ns units).
  58. *
  59. * BUGBUG - timeout happens rarely for HumGetReportDescriptor
  60. * when you plug in and out repeatedly very fast.
  61. * Figure out why this call never completes.
  62. */
  63. static LARGE_INTEGER timeout = {(ULONG) -50000000, 0xFFFFFFFF };
  64. waitStatus = KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, &timeout);
  65. if (waitStatus == STATUS_TIMEOUT){
  66. /*
  67. * Note - Return STATUS_IO_TIMEOUT, not STATUS_TIMEOUT.
  68. * STATUS_IO_TIMEOUT is an NT error status, STATUS_TIMEOUT is not.
  69. */
  70. ioStatus.Status = STATUS_IO_TIMEOUT;
  71. // BUGBUG - test timeout with faulty nack-ing device from glens
  72. // BUGBUG - also need to cancel read irps at HIDCLASS level
  73. //
  74. // Cancel the Irp we just sent.
  75. //
  76. IoCancelIrp(irp);
  77. //
  78. // Now wait for the Irp to be cancelled/completed below
  79. //
  80. waitStatus = KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
  81. }
  82. status = ioStatus.Status;
  83. }
  84. }
  85. else {
  86. status = STATUS_DATA_ERROR;
  87. }
  88. return status;
  89. }
  90. NTSTATUS BuildIRB_GetAddrFromDevObj(PIRB irb)
  91. {
  92. NTSTATUS status;
  93. irb->FunctionNumber = REQUEST_GET_ADDR_FROM_DEVICE_OBJECT;
  94. irb->Flags = 0;
  95. irb->u.Get1394AddressFromDeviceObject.fulFlags = 0; // BUGBUG ?
  96. status = STATUS_SUCCESS;
  97. return status;
  98. }
  99. NTSTATUS BuildIRB_BusReset(PIRB irb)
  100. {
  101. NTSTATUS status;
  102. irb->FunctionNumber = REQUEST_BUS_RESET;
  103. irb->Flags = 0;
  104. irb->u.BusReset.fulFlags = 0;
  105. status = STATUS_SUCCESS;
  106. return status;
  107. }
  108. NTSTATUS BuildIRB_AsyncRead( PIRB irb,
  109. PIO_ADDRESS addr,
  110. PMDL bufferMdl,
  111. ULONG bufLen,
  112. ULONG resetGeneration)
  113. {
  114. NTSTATUS status;
  115. irb->FunctionNumber = REQUEST_ASYNC_READ;
  116. irb->Flags = 0;
  117. irb->u.AsyncRead.DestinationAddress = *addr;
  118. irb->u.AsyncRead.nNumberOfBytesToRead = bufLen;
  119. irb->u.AsyncRead.nBlockSize = 0;
  120. irb->u.AsyncRead.fulFlags = 0;
  121. irb->u.AsyncRead.Mdl = bufferMdl;
  122. irb->u.AsyncRead.ulGeneration = resetGeneration;
  123. // BUGBUG FINISH irb->u.AsyncRead.chPriority = ;
  124. // irb->u.AsyncRead.nSpeed = ;
  125. // irb->u.AsyncRead.tCode = ;
  126. irb->u.AsyncRead.Reserved = 0;
  127. status = STATUS_SUCCESS;
  128. return status;
  129. }
  130. NTSTATUS BuildIRB_AsyncWrite( PIRB irb,
  131. PIO_ADDRESS addr,
  132. PMDL bufferMdl,
  133. ULONG bufLen,
  134. ULONG resetGeneration)
  135. {
  136. NTSTATUS status;
  137. irb->FunctionNumber = REQUEST_ASYNC_WRITE;
  138. irb->Flags = 0;
  139. irb->u.AsyncRead.DestinationAddress = *addr;
  140. irb->u.AsyncRead.nNumberOfBytesToRead = bufLen;
  141. irb->u.AsyncRead.nBlockSize = 0;
  142. irb->u.AsyncRead.fulFlags = 0;
  143. irb->u.AsyncRead.Mdl = bufferMdl;
  144. irb->u.AsyncRead.ulGeneration = resetGeneration;
  145. // BUGBUG FINISH irb->u.AsyncRead.chPriority = ;
  146. // irb->u.AsyncRead.nSpeed = ;
  147. // irb->u.AsyncRead.tCode = ;
  148. irb->u.AsyncRead.Reserved = 0;
  149. status = STATUS_SUCCESS;
  150. return status;
  151. }
  152. NTSTATUS BuildIRB_IsochAllocateChannel(PIRB irb, ULONG requestedChannel)
  153. {
  154. NTSTATUS status;
  155. irb->FunctionNumber = REQUEST_ISOCH_ALLOCATE_CHANNEL;
  156. irb->Flags = 0;
  157. irb->u.IsochAllocateChannel.nRequestedChannel = requestedChannel;
  158. // BUGBUG is there a reserved HID channel ?
  159. status = STATUS_SUCCESS;
  160. return status;
  161. }
  162. NTSTATUS BuildIRB_IsochFreeChannel(PIRB irb, ULONG channel)
  163. {
  164. NTSTATUS status;
  165. irb->FunctionNumber = REQUEST_ISOCH_FREE_CHANNEL;
  166. irb->Flags = 0;
  167. irb->u.IsochFreeChannel.nChannel = channel;
  168. status = STATUS_SUCCESS;
  169. return status;
  170. }
  171. NTSTATUS BuildIRB_GetLocalHostInfo(PIRB irb, ULONG level, PVOID infoPtr)
  172. {
  173. NTSTATUS status;
  174. irb->FunctionNumber = REQUEST_GET_LOCAL_HOST_INFO;
  175. irb->Flags = 0;
  176. irb->u.GetLocalHostInformation.nLevel = level;
  177. irb->u.GetLocalHostInformation.Information = infoPtr;
  178. status = STATUS_SUCCESS;
  179. return status;
  180. }
  181. NTSTATUS BuildIRB_GetNodeAddress(PIRB irb)
  182. {
  183. NTSTATUS status;
  184. irb->FunctionNumber = REQUEST_GET_ADDR_FROM_DEVICE_OBJECT;
  185. irb->Flags = 0;
  186. irb->u.Get1394AddressFromDeviceObject.fulFlags = 0;
  187. status = STATUS_SUCCESS;
  188. return status;
  189. }
  190. NTSTATUS BuildIRB_Control(PIRB irb,
  191. ULONG controlCode,
  192. PMDL inBuffer,
  193. ULONG inBufferLen,
  194. PMDL outBuffer,
  195. ULONG outBufferLen)
  196. {
  197. NTSTATUS status;
  198. irb->FunctionNumber = REQUEST_GET_ADDR_FROM_DEVICE_OBJECT;
  199. irb->Flags = 0;
  200. irb->u.Control.ulIoControlCode = controlCode;
  201. irb->u.Control.pInBuffer = inBuffer;
  202. irb->u.Control.ulInBufferLength = inBufferLen;
  203. irb->u.Control.pOutBuffer = outBuffer;
  204. irb->u.Control.ulOutBufferLength = outBufferLen;
  205. irb->u.Control.BytesReturned = 0;
  206. status = STATUS_SUCCESS;
  207. return status;
  208. }
  209. /*
  210. ********************************************************************************
  211. * HIDT_ReadCompletion
  212. ********************************************************************************
  213. *
  214. *
  215. */
  216. NTSTATUS HIDT_ReadCompletion(IN PDEVICE_OBJECT devObj, IN PIRP irp, IN PVOID context)
  217. {
  218. NTSTATUS status;
  219. NTSTATUS result = STATUS_SUCCESS;
  220. PIRB irb;
  221. ULONG bytesRead;
  222. PDEVICE_EXTENSION devExt;
  223. devExt = GET_MINIDRIVER_DEVICE_EXTENSION(devObj);
  224. //
  225. // We passed a pointer to the IRB as our context, get it now.
  226. //
  227. irb = (PIRB)context;
  228. status = irp->IoStatus.Status;
  229. // BUGBUG FINISH
  230. /*
  231. * Free the IRB we allocated in HIDT_ReadReport.
  232. */
  233. ExFreePool(irb);
  234. /*
  235. * If the lower driver returned PENDING, mark our stack location as
  236. * pending also. This prevents the IRP's thread from being freed if
  237. * the client's call returns pending.
  238. */
  239. if (irp->PendingReturned){
  240. IoMarkIrpPending(irp);
  241. }
  242. return status;
  243. }
  244. /*
  245. * HIDT_ReadReport
  246. *
  247. *
  248. *
  249. */
  250. NTSTATUS HIDT_ReadReport(PDEVICE_OBJECT devObj, PIRP irp, OUT BOOLEAN *needsCompletion)
  251. {
  252. PIRB irb;
  253. NTSTATUS status;
  254. ASSERT(irp->UserBuffer);
  255. irb = ExAllocatePoolWithTag( NonPagedPool, sizeof(IRB), HID1394_TAG);
  256. if (irb){
  257. BOOLEAN sentIrb = FALSE;
  258. PIO_STACK_LOCATION irpSp, nextSp;
  259. ULONG bufLen;
  260. PMDL bufferMdl = NULL; // BUGBUG
  261. IO_ADDRESS addr; // BUGBUG
  262. irpSp = IoGetCurrentIrpStackLocation(irp);
  263. nextSp = IoGetCurrentIrpStackLocation(irp);
  264. bufLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  265. ASSERT(bufLen);
  266. // BUGBUG init bufferMdl, addr
  267. if (BuildIRB_AsyncRead(irb, &addr, bufferMdl, bufLen, resetGeneration)){
  268. nextSp->Parameters.Others.Argument1 = irb;
  269. nextSp->MajorFunction = irpSp->MajorFunction;
  270. // BUGBUG ? nextSp->Parameters.DeviceIoControl.IoControlCode = xxx;
  271. nextSp->DeviceObject = GET_NEXT_DEVICE_OBJECT(devObj); // BUGBUG ?
  272. IoSetCompletionRoutine( irp,
  273. HIDT_ReadCompletion,
  274. irb, // context
  275. TRUE,
  276. TRUE,
  277. TRUE);
  278. status = IoCallDriver(GET_NEXT_DEVICE_OBJECT(devObj), irp);
  279. *needsCompletion = FALSE;
  280. sentIrb = TRUE;
  281. }
  282. else {
  283. status = STATUS_DEVICE_DATA_ERROR;
  284. }
  285. if (!sentIrb){
  286. ExFreePool(irb);
  287. }
  288. }
  289. else {
  290. status = STATUS_INSUFFICIENT_RESOURCES;
  291. }
  292. return status;
  293. }
  294. /*
  295. ********************************************************************************
  296. * HIDT_ReadCompletion
  297. ********************************************************************************
  298. *
  299. *
  300. */
  301. NTSTATUS HIDT_WriteCompletion(IN PDEVICE_OBJECT devObj, IN PIRP irp, IN PVOID context)
  302. {
  303. NTSTATUS status;
  304. NTSTATUS result = STATUS_SUCCESS;
  305. PIRB irb;
  306. ULONG bytesRead;
  307. PDEVICE_EXTENSION devExt;
  308. devExt = GET_MINIDRIVER_DEVICE_EXTENSION(devObj);
  309. //
  310. // We passed a pointer to the IRB as our context, get it now.
  311. //
  312. irb = (PIRB)context;
  313. status = irp->IoStatus.Status;
  314. // BUGBUG FINISH
  315. /*
  316. * Free the IRB we allocated in HIDT_ReadReport.
  317. */
  318. ExFreePool(irb);
  319. /*
  320. * If the lower driver returned PENDING, mark our stack location as
  321. * pending also. This prevents the IRP's thread from being freed if
  322. * the client's call returns pending.
  323. */
  324. if (irp->PendingReturned){
  325. IoMarkIrpPending(irp);
  326. }
  327. return status;
  328. }
  329. /*
  330. * HIDT_ReadReport
  331. *
  332. *
  333. *
  334. */
  335. NTSTATUS HIDT_WriteReport(PDEVICE_OBJECT devObj, PIRP irp, OUT BOOLEAN *needsCompletion)
  336. {
  337. PIRB irb;
  338. NTSTATUS status;
  339. ASSERT(irp->UserBuffer);
  340. irb = ExAllocatePoolWithTag( NonPagedPool, sizeof(IRB), HID1394_TAG);
  341. if (irb){
  342. BOOLEAN sentIrb = FALSE;
  343. PIO_STACK_LOCATION irpSp, nextSp;
  344. ULONG bufLen;
  345. PMDL bufferMdl = NULL; // BUGBUG
  346. IO_ADDRESS addr; // BUGBUG
  347. irpSp = IoGetCurrentIrpStackLocation(irp);
  348. nextSp = IoGetCurrentIrpStackLocation(irp);
  349. bufLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
  350. ASSERT(bufLen);
  351. // BUGBUG init bufferMdl, addr
  352. if (BuildIRB_AsyncWrite(irb, &addr, bufferMdl, bufLen, resetGeneration)){
  353. nextSp->Parameters.Others.Argument1 = irb;
  354. nextSp->MajorFunction = irpSp->MajorFunction;
  355. // BUGBUG ? nextSp->Parameters.DeviceIoControl.IoControlCode = xxx;
  356. nextSp->DeviceObject = GET_NEXT_DEVICE_OBJECT(devObj); // BUGBUG ?
  357. IoSetCompletionRoutine( irp,
  358. HIDT_WriteCompletion,
  359. irb, // context
  360. TRUE,
  361. TRUE,
  362. TRUE);
  363. status = IoCallDriver(GET_NEXT_DEVICE_OBJECT(devObj), irp);
  364. *needsCompletion = FALSE;
  365. sentIrb = TRUE;
  366. }
  367. else {
  368. status = STATUS_DEVICE_DATA_ERROR;
  369. }
  370. if (!sentIrb){
  371. ExFreePool(irb);
  372. }
  373. }
  374. else {
  375. status = STATUS_INSUFFICIENT_RESOURCES;
  376. }
  377. return status;
  378. }
  379. #if 0
  380. // BUGBUG: george says using host config rom is wrong;
  381. // use GetConfigurationInfo
  382. /*
  383. * GetConfigROM
  384. *
  385. *
  386. */
  387. NTSTATUS GetConfigROM(PDEVICE_OBJECT devObj)
  388. {
  389. PDEVICE_EXTENSION devExt;
  390. IRB irb;
  391. GET_LOCAL_HOST_INFO5 configRomInfo;
  392. NTSTATUS status;
  393. devExt = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  394. BuildIRB_GetLocalHostInfo(&irb, GET_HOST_CONFIG_ROM, &configRomInfo);
  395. /*
  396. * Make one call just to get the required length.
  397. */
  398. configRomInfo.ConfigRom = NULL;
  399. configRomInfo.ConfigRomLength = 0;
  400. status = HIDT_SubmitIRB(devObj, &irb);
  401. if (NT_SUCCESS(status)){
  402. if (configRomInfo.ConfigRomLength > 0){
  403. configRomInfo.ConfigRom = ExAllocatePoolWithTag(NonPagedPool, configRomInfo.ConfigRomLength, HID1394_TAG);
  404. if (configRomInfo.ConfigRom){
  405. status = HIDT_SubmitIRB(devObj, &irb);
  406. if (NT_SUCCESS(status)){
  407. devExt->configROM = configRomInfo.ConfigRom;
  408. devExt->configROMlength = configRomInfo.ConfigRomLength;
  409. }
  410. else {
  411. ExFreePool(configRomInfo.ConfigRom);
  412. }
  413. }
  414. else {
  415. status = STATUS_INSUFFICIENT_RESOURCES;
  416. }
  417. }
  418. else {
  419. ASSERT(configRomInfo.ConfigRomLength > 0);
  420. status = STATUS_DEVICE_DATA_ERROR;
  421. }
  422. }
  423. ASSERT(NT_SUCCESS(status));
  424. return status;
  425. }
  426. #endif
  427. NTSTATUS GetConfigInfo(PDEVICE_OBJECT devObj)
  428. {
  429. PDEVICE_EXTENSION devExt;
  430. IRB irb;
  431. NTSTATUS status;
  432. devExt = GET_MINIDRIVER_DEVICE_EXTENSION(devObj);
  433. irb.FunctionNumber = REQUEST_GET_CONFIGURATION_INFO;
  434. irb.Flags = 0;
  435. /*
  436. * Make one call just to get the required buffer lengths.
  437. */
  438. irb.u.GetConfigurationInformation.UnitDirectory = NULL;
  439. irb.u.GetConfigurationInformation.UnitDirectoryBufferSize = 0;
  440. irb.u.GetConfigurationInformation.UnitDependentDirectory = NULL;
  441. irb.u.GetConfigurationInformation.UnitDependentDirectoryBufferSize = 0;
  442. irb.u.GetConfigurationInformation.VendorLeaf = NULL;
  443. irb.u.GetConfigurationInformation.VendorLeafBufferSize = 0;
  444. irb.u.GetConfigurationInformation.ModelLeaf = NULL;
  445. irb.u.GetConfigurationInformation.ModelLeafBufferSize = 0;
  446. status = HIDT_SubmitIRB(devObj, &irb);
  447. if (NT_SUCCESS(status)){
  448. if (irb.u.GetConfigurationInformation.UnitDirectoryBufferSize &&
  449. irb.u.GetConfigurationInformation.UnitDependentDirectoryBufferSize &&
  450. irb.u.GetConfigurationInformation.VendorLeafBufferSize &&
  451. irb.u.GetConfigurationInformation.ModelLeafBufferSize){
  452. /*
  453. * Allocate the required buffers
  454. */
  455. irb.u.GetConfigurationInformation.UnitDirectory =
  456. ExAllocatePoolWithTag(NonPagedPool, irb.u.GetConfigurationInformation.UnitDirectoryBufferSize, HID1394_TAG);
  457. irb.u.GetConfigurationInformation.UnitDependentDirectory =
  458. ExAllocatePoolWithTag(NonPagedPool, irb.u.GetConfigurationInformation.UnitDependentDirectoryBufferSize, HID1394_TAG);
  459. irb.u.GetConfigurationInformation.VendorLeaf =
  460. ExAllocatePoolWithTag(NonPagedPool, irb.u.GetConfigurationInformation.VendorLeafBufferSize, HID1394_TAG);
  461. irb.u.GetConfigurationInformation.ModelLeaf =
  462. ExAllocatePoolWithTag(NonPagedPool, irb.u.GetConfigurationInformation.ModelLeafBufferSize, HID1394_TAG);
  463. if (irb.u.GetConfigurationInformation.UnitDirectory &&
  464. irb.u.GetConfigurationInformation.UnitDependentDirectory &&
  465. irb.u.GetConfigurationInformation.VendorLeaf &&
  466. irb.u.GetConfigurationInformation.ModelLeaf){
  467. irb.u.GetConfigurationInformation.ConfigRom = &devExt->configROM;
  468. status = HIDT_SubmitIRB(devObj, &irb);
  469. // BUGBUG FINISH
  470. // UnitDirectory contains sequence of keys.
  471. // look for HID key ?
  472. }
  473. else {
  474. status = STATUS_INSUFFICIENT_RESOURCES;
  475. }
  476. if (!NT_SUCCESS(status)){
  477. /*
  478. * Free any of the buffers which we were able to allocate
  479. */
  480. if (irb.u.GetConfigurationInformation.UnitDirectory){
  481. ExFreePool(irb.u.GetConfigurationInformation.UnitDirectory);
  482. }
  483. if (irb.u.GetConfigurationInformation.UnitDependentDirectory){
  484. ExFreePool(irb.u.GetConfigurationInformation.UnitDependentDirectory);
  485. }
  486. if (irb.u.GetConfigurationInformation.VendorLeaf){
  487. ExFreePool(irb.u.GetConfigurationInformation.VendorLeaf);
  488. }
  489. if (irb.u.GetConfigurationInformation.ModelLeaf){
  490. ExFreePool(irb.u.GetConfigurationInformation.ModelLeaf);
  491. }
  492. }
  493. }
  494. else {
  495. status = STATUS_BAD_DEVICE_TYPE;
  496. }
  497. }
  498. ASSERT(NT_SUCCESS(status));
  499. return status;
  500. }