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.

2212 lines
82 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1999 - 2000
  3. Module Name:
  4. MsdvAvc.c
  5. Abstract:
  6. Interface code with for issuing external device control commands.
  7. Last changed by:
  8. Author: Yee J. Wu
  9. Environment:
  10. Kernel mode only
  11. Revision History:
  12. $Revision:: $
  13. $Date:: $
  14. --*/
  15. #include "strmini.h"
  16. #include "ksmedia.h"
  17. #include "1394.h"
  18. #include "61883.h"
  19. #include "avc.h"
  20. #include "dbg.h"
  21. #include "msdvfmt.h"
  22. #include "msdvdef.h"
  23. #include "MsdvUtil.h"
  24. #include "MsdvAvc.h"
  25. #include "EDevCtrl.h"
  26. #define ALWAYS_SET_N_GET_RAW_AVC
  27. PAVCCmdEntry
  28. DVCRFindCmdEntryCompleted(
  29. PDVCR_EXTENSION pDevExt,
  30. DVCR_AVC_COMMAND idxDVCRCmd,
  31. BYTE OpCodeToMatch,
  32. AvcCommandType cmdTypeToMatch
  33. );
  34. NTSTATUS
  35. DVGetExtDeviceProperty(
  36. IN PDVCR_EXTENSION pDevExt,
  37. IN PSTREAM_PROPERTY_DESCRIPTOR pSPD,
  38. OUT PULONG pulActualBytesTransferred
  39. );
  40. NTSTATUS
  41. DVSetExtDeviceProperty(
  42. IN PDVCR_EXTENSION pDevExt,
  43. IN PSTREAM_PROPERTY_DESCRIPTOR pSPD,
  44. OUT ULONG *pulActualBytesTransferred
  45. );
  46. NTSTATUS
  47. DVGetExtTransportProperty(
  48. IN PDVCR_EXTENSION pDevExt,
  49. IN PSTREAM_PROPERTY_DESCRIPTOR pSPD,
  50. OUT ULONG *pulActualBytesTransferred
  51. );
  52. NTSTATUS
  53. DVSetExtTransportProperty(
  54. IN PDVCR_EXTENSION pDevExt,
  55. IN PSTREAM_PROPERTY_DESCRIPTOR pSPD,
  56. OUT ULONG *pulActualBytesTransferred
  57. );
  58. NTSTATUS
  59. DVGetTimecodeReaderProperty(
  60. IN PDVCR_EXTENSION pDevExt,
  61. IN PSTREAM_PROPERTY_DESCRIPTOR pSPD,
  62. OUT PULONG pulActualBytesTransferred
  63. );
  64. NTSTATUS
  65. DVMediaSeekingProperty(
  66. IN PDVCR_EXTENSION pDevExt,
  67. IN PSTREAM_PROPERTY_DESCRIPTOR pSPD,
  68. OUT PULONG pulActualBytesTransferred
  69. );
  70. #if 0 // Enable later
  71. #ifdef ALLOC_PRAGMA
  72. #pragma alloc_text(PAGE, DVCRFindCmdEntryCompleted)
  73. // #pragma alloc_text(PAGE, DVIssueAVCCommand)
  74. #pragma alloc_text(PAGE, DVGetExtDeviceProperty)
  75. #pragma alloc_text(PAGE, DVSetExtDeviceProperty)
  76. #pragma alloc_text(PAGE, DVGetExtTransportProperty)
  77. #pragma alloc_text(PAGE, DVSetExtTransportProperty)
  78. #pragma alloc_text(PAGE, DVGetTimecodeReaderProperty)
  79. #pragma alloc_text(PAGE, DVMediaSeekingProperty)
  80. #pragma alloc_text(PAGE, DVGetDeviceProperty)
  81. #pragma alloc_text(PAGE, DVSetDeviceProperty)
  82. #endif
  83. #endif
  84. KSFCP_PACKET DVcrAVCCmdTable[] = {
  85. // ctype subunitaddr opcode operands
  86. { DV_UNIT_INFO, -1, 0, CMD_STATUS, 5, AVC_CTYPE_STATUS, UNIT_TYPE_ID_DV, 0x30, 0xff, 0xff, 0xff, 0xff, 0xff}
  87. ,{ DV_SUBUNIT_INFO, -1, 0, CMD_STATUS, 5, AVC_CTYPE_STATUS, UNIT_TYPE_ID_DV, 0x31, 0x07, 0xff, 0xff, 0xff, 0xff}
  88. ,{ DV_CONNECT_AV_MODE, -1, 0, CMD_STATUS, 5, AVC_CTYPE_STATUS, UNIT_TYPE_ID_DV, 0x20, 0xf0, 0xff, 0xff, 0x20, 0x20}
  89. ,{ DV_VEN_DEP_CANON_MODE, -1, 0, CMD_STATUS, 7, AVC_CTYPE_STATUS, UNIT_TYPE_ID_VCR, 0x00, 0x00, 0x00, 0x85, 0x00, 0x10, 0x08, 0xff}
  90. ,{ DV_VEN_DEP_DVCPRO, -1, 0, CMD_STATUS, 7, AVC_CTYPE_STATUS, UNIT_TYPE_ID_DV, 0x00, 0x00, 0x80, 0x45, 0x82, 0x48, 0xff, 0xff}
  91. ,{ DV_IN_PLUG_SIGNAL_FMT, -1, 0, CMD_STATUS, 5, AVC_CTYPE_STATUS, UNIT_TYPE_ID_DV, 0x19, 0x00, 0xff, 0xff, 0xff, 0xff}
  92. ,{ DV_OUT_PLUG_SIGNAL_FMT, -1, 0, CMD_STATUS, 5, AVC_CTYPE_STATUS, UNIT_TYPE_ID_DV, 0x18, 0x00, 0xff, 0xff, 0xff, 0xff}
  93. ,{ VCR_TIMECODE_SEARCH, -1, 0, CMD_CONTROL, 5, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0x51, 0x20, 0x00, 0x00, 0x00, 0x00}
  94. ,{ VCR_TIMECODE_READ, -1, 0, CMD_STATUS, 5, AVC_CTYPE_STATUS, UNIT_TYPE_ID_VCR, 0x51, 0x71, 0xff, 0xff, 0xff, 0xff}
  95. ,{ VCR_ATN_SEARCH, -1, 0, CMD_CONTROL, 5, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0x52, 0x20, 0x00, 0x00, 0x00, 0x00}
  96. ,{ VCR_ATN_READ, -1, 0, CMD_STATUS, 5, AVC_CTYPE_STATUS, UNIT_TYPE_ID_VCR, 0x52, 0x71, 0xff, 0xff, 0xff, 0xff}
  97. ,{ VCR_RTC_SEARCH, -1, 0, CMD_CONTROL, 5, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0x57, 0x20, 0x00, 0x00, 0x00, 0x00}
  98. ,{ VCR_RTC_READ, -1, 0, CMD_STATUS, 5, AVC_CTYPE_STATUS, UNIT_TYPE_ID_VCR, 0x57, 0x71, 0xff, 0xff, 0xff, 0xff}
  99. ,{ VCR_OPEN_MIC_CLOSE, -1, 0, CMD_CONTROL, 1, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0x60, 0x00}
  100. ,{ VCR_OPEN_MIC_READ, -1, 0, CMD_CONTROL, 1, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0x60, 0x01}
  101. ,{ VCR_OPEN_MIC_WRITE, -1, 0, CMD_CONTROL, 1, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0x60, 0x03}
  102. ,{ VCR_OPEN_MIC_STATUS, -1, 0, CMD_STATUS, 1, AVC_CTYPE_STATUS, UNIT_TYPE_ID_VCR, 0x60, 0xff}
  103. ,{ VCR_READ_MIC, -1, 0, CMD_CONTROL, -1, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0x61}
  104. ,{ VCR_WRITE_MIC, -1, 0, CMD_CONTROL, -1, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0x62}
  105. ,{ VCR_OUTPUT_SIGNAL_MODE, -1, 0, CMD_STATUS, 1, AVC_CTYPE_STATUS, UNIT_TYPE_ID_VCR, 0x78, 0xff}
  106. ,{ VCR_INPUT_SIGNAL_MODE, -1, 0, CMD_STATUS, 1, AVC_CTYPE_STATUS, UNIT_TYPE_ID_VCR, 0x79, 0xff}
  107. ,{ VCR_LOAD_MEDIUM_EJECT, -1, 0, CMD_CONTROL, 1, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0xc1, 0x60}
  108. ,{ VCR_RECORD, -1, 0, CMD_CONTROL, 1, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0xc2, 0x75}
  109. ,{ VCR_RECORD_PAUSE, -1, 0, CMD_CONTROL, 1, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0xc2, 0x7d}
  110. ,{ VCR_PLAY_FORWARD_STEP, -1, 0, CMD_CONTROL, 1, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0xc3, 0x30} // 00=AVC, 20=VCR, c3=Opcode, 30=Operand[0]
  111. ,{ VCR_PLAY_FORWARD_SLOWEST, -1, 0, CMD_CONTROL, 1, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0xc3, 0x31}
  112. ,{ VCR_PLAY_FORWARD_SLOWEST2, -1, 0, CMD_CONTROL, 1, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0xc3, 0x33}
  113. ,{ VCR_PLAY_FORWARD_FASTEST, -1, 0, CMD_CONTROL, 1, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0xc3, 0x3f}
  114. ,{ VCR_PLAY_REVERSE_STEP, -1, 0, CMD_CONTROL, 1, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0xc3, 0x40}
  115. ,{ VCR_PLAY_REVERSE_SLOWEST, -1, 0, CMD_CONTROL, 1, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0xc3, 0x41}
  116. ,{ VCR_PLAY_REVERSE_SLOWEST2, -1, 0, CMD_CONTROL, 1, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0xc3, 0x43}
  117. ,{ VCR_PLAY_REVERSE_FASTEST, -1, 0, CMD_CONTROL, 1, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0xc3, 0x4f}
  118. ,{ VCR_PLAY_FORWARD, -1, 0, CMD_CONTROL, 1, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0xc3, 0x75}
  119. ,{ VCR_PLAY_FORWARD_PAUSE, -1, 0, CMD_CONTROL, 1, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0xc3, 0x7d}
  120. ,{ VCR_WIND_STOP, -1, 0, CMD_CONTROL, 1, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0xc4, 0x60}
  121. ,{ VCR_WIND_REWIND, -1, 0, CMD_CONTROL, 1, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0xc4, 0x65}
  122. ,{ VCR_WIND_FAST_FORWARD, -1, 0, CMD_CONTROL, 1, AVC_CTYPE_CONTROL,UNIT_TYPE_ID_VCR, 0xc4, 0x75}
  123. ,{ VCR_TRANSPORT_STATE, -1, 0, CMD_STATUS, 1, AVC_CTYPE_STATUS, UNIT_TYPE_ID_VCR, 0xd0, 0x7f}
  124. ,{ VCR_TRANSPORT_STATE_NOTIFY, -1, 0, CMD_NOTIFY, 1, AVC_CTYPE_NOTIFY, UNIT_TYPE_ID_VCR, 0xd0, 0x7f}
  125. ,{ VCR_MEDIUM_INFO, -1, 0, CMD_STATUS, 2, AVC_CTYPE_STATUS, UNIT_TYPE_ID_VCR, 0xda, 0x7f,0x7f}
  126. ,{ VCR_RAW_AVC, 1, 0, CMD_CONTROL | CMD_STATUS | CMD_NOTIFY | CMD_SPEC_INQ | CMD_GEN_INQ, 0}
  127. };
  128. void
  129. DVCRXlateGetMediumInfo(
  130. PMEDIUM_INFO pMediumInfo,
  131. PBYTE pbOperand0,
  132. PBYTE pbOperand1
  133. )
  134. {
  135. switch(*pbOperand0) {
  136. // Support for DigitalHi8; if we get this query, we treat DHi8 as a mini DV tape.
  137. case 0x12: // DHi8
  138. case 0x31:// DVCR standard cassette
  139. case 0x32:// DVCR small cassette
  140. case 0x33:// DVCR medium cassette
  141. pMediumInfo->MediaPresent = TRUE;
  142. pMediumInfo->MediaType = ED_MEDIA_DVC;
  143. pMediumInfo->RecordInhibit = (*pbOperand1 & 0x01) == 0x01;
  144. break;
  145. case 0x22: // VHS cassette
  146. pMediumInfo->MediaPresent = TRUE;
  147. pMediumInfo->MediaType = ED_MEDIA_VHS;
  148. pMediumInfo->RecordInhibit = (*pbOperand1 & 0x01) == 0x01;
  149. break;
  150. case 0x23:
  151. pMediumInfo->MediaPresent = TRUE;
  152. pMediumInfo->MediaType = ED_MEDIA_VHSC;
  153. pMediumInfo->RecordInhibit = (*pbOperand1 & 0x01) == 0x01;
  154. break;
  155. case 0x60:
  156. pMediumInfo->MediaPresent = FALSE;
  157. pMediumInfo->MediaType = ED_MEDIA_NOT_PRESENT;
  158. pMediumInfo->RecordInhibit = TRUE; // Cannot record if there is no tape.
  159. break;
  160. case 0x7e:
  161. pMediumInfo->MediaPresent = TRUE;
  162. pMediumInfo->MediaType = ED_MEDIA_UNKNOWN;
  163. pMediumInfo->RecordInhibit = TRUE; // Actually cannot be determined
  164. break;
  165. default:
  166. pMediumInfo->MediaPresent = TRUE;
  167. pMediumInfo->MediaType = ED_MEDIA_UNKNOWN;
  168. pMediumInfo->RecordInhibit = TRUE;
  169. break;
  170. }
  171. // Reset command opcode/operands
  172. *pbOperand0 = 0x7f;
  173. *pbOperand1 = 0x7f;
  174. }
  175. void
  176. DVCRXlateGetTransportState(
  177. PTRANSPORT_STATE pXPrtState,
  178. PBYTE pbOpcode,
  179. PBYTE pbOperand0
  180. )
  181. {
  182. TRACE(TL_FCP_TRACE,("\'DVCRXlateGetTransportState: OpCode %x, Operand %x\n", *pbOpcode, *pbOperand0));
  183. switch(*pbOpcode) {
  184. case OPC_LOAD_MEDIUM:
  185. pXPrtState->Mode = ED_MEDIA_UNLOAD;
  186. ASSERT(*pbOperand0 == 0x60);
  187. break;
  188. case OPC_RECORD:
  189. pXPrtState->Mode = ED_MODE_RECORD;
  190. switch(*pbOperand0) {
  191. case 0x75: // RECORD
  192. pXPrtState->State = ED_MODE_RECORD;
  193. break;
  194. case 0x7d: // RECORD_FREEZE
  195. pXPrtState->State = ED_MODE_RECORD_FREEZE;
  196. break;
  197. default:
  198. ASSERT(FALSE && "OPC_RECORD: Operand0 undefined!");
  199. break;
  200. }
  201. break;
  202. case OPC_PLAY:
  203. pXPrtState->Mode = ED_MODE_PLAY;
  204. switch(*pbOperand0) {
  205. case 0x30: // NEXT FRAME
  206. pXPrtState->State = ED_MODE_STEP_FWD;
  207. break;
  208. case 0x31: // SLOWEST FORWARD
  209. case 0x32: // SLOW FORWARD 6
  210. case 0x33: // SLOW FORWARD 5
  211. case 0x34: // SLOW FORWARD 4
  212. case 0x35: // SLOW FORWARD 3
  213. case 0x36: // SLOW FORWARD 2
  214. case 0x37: // SLOW FORWARD 1
  215. pXPrtState->State = ED_MODE_PLAY_SLOWEST_FWD;
  216. break;
  217. case 0x38: // PLAY FORWARD 1
  218. pXPrtState->State = ED_MODE_PLAY;
  219. break;
  220. case 0x39: // FAST FORWARD 1
  221. case 0x3a: // FAST FORWARD 2
  222. case 0x3b: // FAST FORWARD 3
  223. case 0x3c: // FAST FORWARD 4
  224. case 0x3d: // FAST FORWARD 5
  225. case 0x3e: // FAST FORWARD 6
  226. case 0x3f: // FASTEST FORWARD
  227. pXPrtState->State = ED_MODE_PLAY_FASTEST_FWD;
  228. break;
  229. case 0x40: // PREVIOUS FRAME
  230. pXPrtState->State = ED_MODE_STEP_REV;
  231. break;
  232. case 0x41: // SLOWEST REVERSE
  233. case 0x42: // SLOW REVERSE 6
  234. case 0x43: // SLOW REVERSE 5
  235. case 0x44: // SLOW REVERSE 4
  236. case 0x45: // SLOW REVERSE 3
  237. case 0x46: // SLOW REVERSE 2
  238. case 0x47: // SLOW REVERSE 1
  239. pXPrtState->State = ED_MODE_PLAY_SLOWEST_REV;
  240. break;
  241. case 0x48: // X1 REVERSE
  242. case 0x65: // REVERSE
  243. pXPrtState->State = ED_MODE_REV_PLAY;
  244. break;
  245. case 0x49: // FAST REVERSE 1
  246. case 0x4a: // FAST REVERSE 2
  247. case 0x4b: // FAST REVERSE 3
  248. case 0x4c: // FAST REVERSE 4
  249. case 0x4d: // FAST REVERSE 5
  250. case 0x4e: // FAST REVERSE 6
  251. case 0x4f: // FASTEST REVERSE
  252. pXPrtState->State = ED_MODE_PLAY_FASTEST_REV;
  253. break;
  254. case 0x75: // FORWARD
  255. pXPrtState->State = ED_MODE_PLAY;
  256. break;
  257. case 0x6d: // REVERSE PAUSE
  258. case 0x7d: // FORWARD PAUSE
  259. pXPrtState->State = ED_MODE_FREEZE;
  260. break;
  261. default:
  262. pXPrtState->State = 0;
  263. ASSERT(FALSE && "OPC_PLAY: Operand0 undefined!");
  264. break;
  265. }
  266. break;
  267. case OPC_WIND:
  268. //pXPrtState->Mode = ED_MODE_WIND;
  269. switch(*pbOperand0) {
  270. case 0x45: // HIGH SPEED REWIND
  271. pXPrtState->State = ED_MODE_REW_FASTEST;
  272. break;
  273. case 0x60: // STOP
  274. pXPrtState->State = ED_MODE_STOP;
  275. break;
  276. case 0x65: // REWIND
  277. pXPrtState->State = ED_MODE_REW;
  278. break;
  279. case 0x75: // FAST FORWARD
  280. pXPrtState->State = ED_MODE_FF;
  281. break;
  282. default:
  283. TRACE(TL_FCP_ERROR,("DVCRXlateGetTransportState: OPC_WIND with unknown operand0 %x\n", *pbOperand0));
  284. break;
  285. }
  286. // Thre is not a state defined for WIND
  287. pXPrtState->Mode = pXPrtState->State;
  288. break;
  289. case OPC_TRANSPORT_STATE: // As a result of the notify command
  290. break;
  291. default:
  292. ASSERT(FALSE && "OpCode undefined!");
  293. break;
  294. }
  295. // Reset command opcode/operands
  296. *pbOpcode = 0xd0;
  297. *pbOperand0 = 0x7f;
  298. }
  299. void
  300. DVCRXlateGetIOSignalMode(
  301. PULONG pIOSignalMode,
  302. PBYTE pbOperand0
  303. )
  304. {
  305. switch(*pbOperand0) {
  306. // Sony's digital Hi8 can take analog 8MM tape and output DV signal.
  307. case 0x06: // Analog 8mm NTSC
  308. case 0x0e: // Analog Hi8 NTSC
  309. TRACE(TL_FCP_WARNING,("\'***** Signal mode:%x (8MM NTSC)\n", *pbOperand0));
  310. case 0x00: // SD 525-60
  311. *pIOSignalMode = ED_TRANSBASIC_SIGNAL_525_60_SD;
  312. break;
  313. case 0x04: // SDL 525-60
  314. *pIOSignalMode = ED_TRANSBASIC_SIGNAL_525_60_SDL;
  315. break;
  316. // Sony's digital Hi8 can take analog 8MM tape and output DV signal.
  317. case 0x86: // Analog 8mm PAL
  318. case 0x8e: // Analog Hi8 PAL
  319. TRACE(TL_FCP_WARNING,("\'***** Signal mode:%x (8MM PAL)\n", *pbOperand0));
  320. case 0x80: // SD 625-50
  321. *pIOSignalMode = ED_TRANSBASIC_SIGNAL_625_50_SD;
  322. break;
  323. case 0x84: // SDL 625-50
  324. *pIOSignalMode = ED_TRANSBASIC_SIGNAL_625_50_SDL;
  325. break;
  326. default:
  327. // This driver does not understand other format;
  328. TRACE(TL_FCP_WARNING,("***** Unknown signal mode:%x\n", *pbOperand0));
  329. ASSERT(FALSE && "Unknown IoSignal!");
  330. break;
  331. }
  332. // Reset command opcode/operands
  333. *pbOperand0 = 0xff;
  334. }
  335. NTSTATUS
  336. DVCRXlateRawAVC(
  337. PAVCCmdEntry pCmdEntry,
  338. PVOID pProperty
  339. )
  340. {
  341. PAVC_COMMAND_IRB pAvcIrb = pCmdEntry->pAvcIrb;
  342. UCHAR ucRespCode = pAvcIrb->ResponseCode;
  343. NTSTATUS Status;
  344. PUCHAR pbRtnBuf;
  345. //PKSPROPERTY_EXTDEVICE_S pExtDeviceProperty;
  346. PKSPROPERTY_EXTXPORT_S pXPrtProperty;
  347. PKSPROPERTY_TIMECODE_S pTmCdReaderProperty;
  348. if(STATUS_SUCCESS != pCmdEntry->Status) {
  349. TRACE(TL_FCP_ERROR,("\'** DVCRXlateRawAVC: Status:%x ** \n", pCmdEntry->Status));
  350. return pCmdEntry->Status;
  351. }
  352. switch (pCmdEntry->idxDVCRCmd) {
  353. case DV_UNIT_INFO:
  354. pbRtnBuf = (PBYTE) pProperty;
  355. memcpy(pbRtnBuf, pAvcIrb->Operands+1, 4);
  356. break;
  357. case DV_SUBUNIT_INFO:
  358. case DV_IN_PLUG_SIGNAL_FMT:
  359. case DV_OUT_PLUG_SIGNAL_FMT:
  360. pbRtnBuf = (PBYTE) pProperty;
  361. memcpy(pbRtnBuf, pAvcIrb->Operands+1, 4);
  362. break;
  363. // special case, return the response code in the first byte
  364. case DV_CONNECT_AV_MODE:
  365. pbRtnBuf = (PBYTE) pProperty;
  366. pbRtnBuf[0] = ucRespCode;
  367. memcpy(&pbRtnBuf[1], pAvcIrb->Operands, 5);
  368. break;
  369. // special case, return the response code in the first byte
  370. case DV_VEN_DEP_CANON_MODE:
  371. pbRtnBuf = (PBYTE) pProperty;
  372. pbRtnBuf[0] = ucRespCode;
  373. memcpy(&pbRtnBuf[1], pAvcIrb->Operands, 7);
  374. break;
  375. case VCR_TIMECODE_READ:
  376. pTmCdReaderProperty = (PKSPROPERTY_TIMECODE_S) pProperty;
  377. if(pAvcIrb->Operands[1] == 0xff ||
  378. pAvcIrb->Operands[2] == 0xff ||
  379. pAvcIrb->Operands[3] == 0xff ||
  380. pAvcIrb->Operands[4] == 0xff ) {
  381. TRACE(TL_FCP_WARNING,("\'TimeCodeRead: %.2x:%.2x:%.2x,%.2x\n", pAvcIrb->Operands[4], pAvcIrb->Operands[3], pAvcIrb->Operands[2], pAvcIrb->Operands[1]));
  382. // Even though command succeded, but the data is not valid!
  383. Status = STATUS_UNSUCCESSFUL;
  384. } else {
  385. // bswap them.
  386. pTmCdReaderProperty->TimecodeSamp.timecode.dwFrames =
  387. (((DWORD) pAvcIrb->Operands[4]) << 24) |
  388. (((DWORD) pAvcIrb->Operands[3]) << 16) |
  389. (((DWORD) pAvcIrb->Operands[2]) << 8) |
  390. ((DWORD) pAvcIrb->Operands[1]);
  391. TRACE(TL_FCP_TRACE,("\'TimeCodeRead: %.2x:%.2x:%.2x,%.2x\n", pAvcIrb->Operands[4], pAvcIrb->Operands[3], pAvcIrb->Operands[2], pAvcIrb->Operands[1]));
  392. }
  393. break;
  394. case VCR_ATN_READ:
  395. pTmCdReaderProperty = (PKSPROPERTY_TIMECODE_S) pProperty;
  396. if(pAvcIrb->Operands[1] == 0x00 &&
  397. pAvcIrb->Operands[2] == 0x00 &&
  398. pAvcIrb->Operands[3] == 0x00 ) {
  399. // Even though command succeded, but the data is not valid!
  400. Status = STATUS_UNSUCCESSFUL;
  401. } else {
  402. pTmCdReaderProperty->TimecodeSamp.dwUser =
  403. pAvcIrb->Operands[1] & 0x01; // Get the Blank flag
  404. // bswap them.
  405. pTmCdReaderProperty->TimecodeSamp.timecode.dwFrames =
  406. ( (((DWORD) pAvcIrb->Operands[3]) << 16) |
  407. (((DWORD) pAvcIrb->Operands[2]) << 8) |
  408. (((DWORD) pAvcIrb->Operands[1]))
  409. ) >> 1;
  410. }
  411. break;
  412. case VCR_INPUT_SIGNAL_MODE:
  413. case VCR_OUTPUT_SIGNAL_MODE:
  414. pXPrtProperty = (PKSPROPERTY_EXTXPORT_S) pProperty;
  415. DVCRXlateGetIOSignalMode(&pXPrtProperty->u.SignalMode, &pAvcIrb->Operands[0]);
  416. break;
  417. case VCR_TRANSPORT_STATE:
  418. case VCR_TRANSPORT_STATE_NOTIFY:
  419. pXPrtProperty = (PKSPROPERTY_EXTXPORT_S) pProperty;
  420. DVCRXlateGetTransportState(&pXPrtProperty->u.XPrtState, &pAvcIrb->Opcode, &pAvcIrb->Operands[0]);
  421. break;
  422. case VCR_MEDIUM_INFO:
  423. pXPrtProperty = (PKSPROPERTY_EXTXPORT_S) pProperty;
  424. DVCRXlateGetMediumInfo(&pXPrtProperty->u.MediumInfo, &pAvcIrb->Operands[0], &pAvcIrb->Operands[1]);
  425. break;
  426. case VCR_RAW_AVC:
  427. // Do nothing.
  428. break;
  429. default:
  430. // No translation necessary
  431. TRACE(TL_FCP_TRACE,("\'No tranlsation: pCmdEntry:%x; idx:%d\n", pCmdEntry, pCmdEntry->idxDVCRCmd));
  432. break;
  433. }
  434. return pCmdEntry->Status;
  435. }
  436. PAVCCmdEntry
  437. DVCRFindCmdEntryCompleted(
  438. PDVCR_EXTENSION pDevExt,
  439. DVCR_AVC_COMMAND idxDVCRCmd,
  440. BYTE OpCodeToMatch,
  441. AvcCommandType cmdTypeToMatch
  442. )
  443. /*++
  444. Routine Description:
  445. Arguments:
  446. Return Value:
  447. PLIST_ENTRY
  448. --*/
  449. {
  450. LIST_ENTRY *pEntry;
  451. KIRQL OldIrql;
  452. PAGED_CODE();
  453. //
  454. // Special case:
  455. //
  456. // ATN: Status 01 20 52; Control 00 20 52
  457. // (resp) 0c 20 52 0f 20 52 (CtrlInterim)
  458. //
  459. // XPrtState: Status 01 20 d0; Notify 03 20 d0
  460. // (resp) 0c 20 xx 0f 20 xx xx (NotifyInterim)
  461. //
  462. // Summary: if we keep cmdType and OpCode, it is unique.
  463. //
  464. KeAcquireSpinLock(&pDevExt->AVCCmdLock, &OldIrql);
  465. pEntry = pDevExt->AVCCmdList.Flink;
  466. while(pEntry != &pDevExt->AVCCmdList) {
  467. PAVCCmdEntry pCmdEntry = (PAVCCmdEntry)pEntry;
  468. if (pCmdEntry->idxDVCRCmd == idxDVCRCmd) {
  469. //
  470. // We only fetch if it is completed!
  471. //
  472. if(pCmdEntry->cmdState != CMD_STATE_ISSUED) {
  473. if (pCmdEntry->cmdType == cmdTypeToMatch) {
  474. // Control/GenInq/SpecInq: OpCode and Operand[n] remina unchanged.
  475. if (pCmdEntry->OpCode == OpCodeToMatch) {
  476. TRACE(TL_FCP_TRACE,("\'DVCRFindCmdEntryCompleted: (1) Found pCmdEntry:%x (%x, %x, %x)\n",
  477. pCmdEntry, pCmdEntry->pAvcIrb, cmdTypeToMatch, OpCodeToMatch));
  478. RemoveEntryList(&pCmdEntry->ListEntry); pDevExt->cntCommandQueued--;
  479. InitializeListHead(&pCmdEntry->ListEntry); // used as a flag for ownership
  480. // pIrp should be NULL (completed).
  481. if(pCmdEntry->pIrp) {
  482. TRACE(TL_FCP_ERROR,("\'*** FindCmdEntry: pCmdEntry:%x; pIrp:%x not completed\n", pCmdEntry, pCmdEntry->pIrp));
  483. }
  484. KeReleaseSpinLock(&pDevExt->AVCCmdLock, OldIrql);
  485. return pCmdEntry; // Found
  486. }
  487. } else {
  488. TRACE(TL_FCP_TRACE,("\'DVCRFindCmdEntryCompleted: cmdType %x != %x\n", pCmdEntry->cmdType, cmdTypeToMatch));
  489. }
  490. }
  491. else {
  492. TRACE(TL_FCP_TRACE,("\'DVCRFindCmdEntryCompleted: (0) Skip %x not completed (%x, %x) match entry %x\n",
  493. pCmdEntry, cmdTypeToMatch, OpCodeToMatch));
  494. }
  495. }
  496. pEntry = pEntry->Flink;
  497. }
  498. KeReleaseSpinLock(&pDevExt->AVCCmdLock, OldIrql);
  499. TRACE(TL_FCP_TRACE,("\'DVCRFindCmdEntryCompleted: (a) No match\n"));
  500. return NULL; // No match
  501. }
  502. void
  503. DVAVCCmdResetAfterBusReset(
  504. PDVCR_EXTENSION pDevExt
  505. )
  506. /*++
  507. Routine Description:
  508. Arguments:
  509. Return Value:
  510. Nothing
  511. --*/
  512. {
  513. KIRQL OldIrql;
  514. KeAcquireSpinLock(&pDevExt->AVCCmdLock, &OldIrql);
  515. TRACE(TL_FCP_TRACE,("\'Flush AVCCmd: <enter> AVCCmd [completed %d]; CmdList:%x\n", pDevExt->cntCommandQueued, pDevExt->AVCCmdList));
  516. // Clear the command list
  517. while (!IsListEmpty(&pDevExt->AVCCmdList)) {
  518. PAVCCmdEntry pCmdEntry = (PAVCCmdEntry)RemoveHeadList(&pDevExt->AVCCmdList); pDevExt->cntCommandQueued--;
  519. InitializeListHead(&pCmdEntry->ListEntry);
  520. TRACE(TL_FCP_TRACE,("\'Flush AVCCmd: Completed:%d; pCmdEntry:%x; cmdState:%d; cmdSt:%x\n",
  521. pDevExt->cntCommandQueued, pCmdEntry, pCmdEntry->cmdState, pCmdEntry->Status));
  522. switch(pCmdEntry->cmdState) {
  523. case CMD_STATE_ISSUED:
  524. case CMD_STATE_RESP_INTERIM: // AVC.sys may still has it!
  525. TRACE(TL_FCP_WARNING,("BusReset: AbortAVC: IoCancelIrp(%x)!\n", pCmdEntry->pIrp));
  526. ASSERT(pCmdEntry->pIrp != NULL);
  527. IoCancelIrp(pCmdEntry->pIrp); // Calls DVIssueAVCCommandCR() with pIrp->Cancel
  528. break;
  529. // Completed command
  530. case CMD_STATE_UNDEFINED:
  531. TRACE(TL_FCP_ERROR,("DVAVCCmdResetAfterBusReset: Unexpected CMD state %d; pCmdEntry %x\n", pCmdEntry->cmdState, pCmdEntry));
  532. case CMD_STATE_RESP_ACCEPTED:
  533. case CMD_STATE_RESP_REJECTED:
  534. case CMD_STATE_RESP_NOT_IMPL:
  535. case CMD_STATE_ABORTED:
  536. break;
  537. default:
  538. TRACE(TL_FCP_ERROR,("DVAVCCmdResetAfterBusReset: Unknown CMD state %d; pCmdEntry %x\n", pCmdEntry->cmdState, pCmdEntry));
  539. ASSERT(FALSE && "Unknown cmdState\n");
  540. break;
  541. }
  542. // We are guaranteed at this point that no one needs the
  543. // results anymore so we will free the resources.
  544. ExFreePool(pCmdEntry->pAvcIrb);
  545. ExFreePool(pCmdEntry);
  546. }
  547. KeReleaseSpinLock(&pDevExt->AVCCmdLock, OldIrql);
  548. #if DBG
  549. if(pDevExt->cntCommandQueued != 0) {
  550. TRACE(TL_FCP_ERROR,("\'Flush AVCCmd: <exit> AVCCmd [completed %d]; CmdList:%x\n", pDevExt->cntCommandQueued, pDevExt->AVCCmdList));
  551. ASSERT(pDevExt->cntCommandQueued == 0 && "All commands should be cancelled or completed.");
  552. }
  553. #endif
  554. }
  555. NTSTATUS
  556. DVIssueAVCCommandCR(
  557. IN PDEVICE_OBJECT DeviceObject,
  558. IN PIRP pIrp,
  559. IN PAVCCmdEntry pCmdEntry
  560. )
  561. /*++
  562. Routine Description:
  563. This is the completion routine for the AVC command when it is completed which imply that
  564. the interim response will not be called here.
  565. Arguments:
  566. Note: pCmdEntry cannot be used if pIrp->Cancel.
  567. Return Value:
  568. Always STATUS_MORE_PROCESSING_REQUIRED.
  569. Note: the real return is in pCmdEntry->Status.
  570. --*/
  571. {
  572. KIRQL oldIrql;
  573. if (!pIrp->Cancel) {
  574. PDVCR_EXTENSION pDevExt = pCmdEntry->pDevExt;
  575. BOOL bSignalInterimCotrolCompleted = FALSE;
  576. BOOL bSignalInterimNotifyCompleted = FALSE;
  577. PKSEVENT_ENTRY pEvent;
  578. // Serialize AVC command response processing
  579. KeAcquireSpinLock(&pDevExt->AVCCmdLock, &oldIrql);
  580. ASSERT(pCmdEntry->pIrp == pIrp);
  581. pCmdEntry->pIrp = NULL; // don't need this anymore
  582. // Check if it's worthwhile to examine the response buffer
  583. if (STATUS_SUCCESS == pIrp->IoStatus.Status) {
  584. PAVC_COMMAND_IRB pAvcIrb = pCmdEntry->pAvcIrb;
  585. // Check Opcode for return state
  586. switch(pAvcIrb->ResponseCode) {
  587. case AVC_RESPONSE_NOTIMPL:
  588. pCmdEntry->cmdState = CMD_STATE_RESP_NOT_IMPL;
  589. pCmdEntry->Status = STATUS_NOT_SUPPORTED; // -> ERROR_NOT_SUPPORTED
  590. break;
  591. case AVC_RESPONSE_ACCEPTED:
  592. if(pCmdEntry->cmdState == CMD_STATE_RESP_INTERIM) {
  593. if(pCmdEntry->cmdType == AVC_CTYPE_CONTROL) {
  594. bSignalInterimCotrolCompleted = TRUE;
  595. TRACE(TL_FCP_TRACE,("--> Accept: control interim\n"));
  596. } else {
  597. TRACE(TL_FCP_ERROR,("\'ACCEPT: Invalid cmdType:%d; pCmdExtry %x\n", pCmdEntry->cmdType, pCmdEntry));
  598. ASSERT(pCmdEntry->cmdType == AVC_CTYPE_CONTROL && "Accept+Interim but not control cmd");
  599. }
  600. }
  601. pCmdEntry->cmdState = CMD_STATE_RESP_ACCEPTED;
  602. pCmdEntry->Status = STATUS_SUCCESS; // -> NOERROR
  603. break;
  604. case AVC_RESPONSE_REJECTED:
  605. if(pCmdEntry->cmdState == CMD_STATE_RESP_INTERIM) {
  606. if(pCmdEntry->cmdType == AVC_CTYPE_CONTROL) {
  607. TRACE(TL_FCP_TRACE,("--> Reject: control interim\n"));
  608. bSignalInterimCotrolCompleted = TRUE;
  609. } else if(pCmdEntry->cmdType == AVC_CTYPE_NOTIFY) {
  610. TRACE(TL_FCP_TRACE,("--> Reject: notify interim\n"));
  611. bSignalInterimNotifyCompleted = TRUE;
  612. } else {
  613. TRACE(TL_FCP_ERROR,("REJECT: Invalid cmdType:%d; pCmdExtry %x\n", pCmdEntry->cmdType, pCmdEntry));
  614. ASSERT((pCmdEntry->cmdType == AVC_CTYPE_CONTROL || pCmdEntry->cmdType == AVC_CTYPE_NOTIFY) && "Reject+Interim but not control or notify cmd");
  615. }
  616. }
  617. pCmdEntry->cmdState = CMD_STATE_RESP_REJECTED;
  618. pCmdEntry->Status = STATUS_REQUEST_NOT_ACCEPTED; // ERROR_REQ_NOT_ACCEPTED
  619. break;
  620. case AVC_RESPONSE_IN_TRANSITION:
  621. pCmdEntry->cmdState = CMD_STATE_RESP_ACCEPTED;
  622. pCmdEntry->Status = STATUS_SUCCESS; // -> NOERROR
  623. break;
  624. case AVC_RESPONSE_STABLE: // == AVC_RESPONSE_IMPLEMENTED:
  625. pCmdEntry->cmdState = CMD_STATE_RESP_ACCEPTED;
  626. pCmdEntry->Status = STATUS_SUCCESS; // -> NOERROR
  627. break;
  628. case AVC_RESPONSE_CHANGED:
  629. #if DBG
  630. if(pCmdEntry->cmdState != CMD_STATE_RESP_INTERIM) {
  631. TRACE(TL_FCP_ERROR,("Err: Changed; pCmdExtry:%x; cmdState:%d\n", pCmdEntry, pCmdEntry->cmdState));
  632. ASSERT(pCmdEntry->cmdState == CMD_STATE_RESP_INTERIM);
  633. }
  634. #endif
  635. if(pCmdEntry->cmdType == AVC_CTYPE_NOTIFY) {
  636. TRACE(TL_FCP_TRACE,("--> Changed: for notify interim\n"));
  637. bSignalInterimNotifyCompleted = TRUE;
  638. } else {
  639. TRACE(TL_FCP_ERROR,("pCmdExtry %x\n", pCmdEntry));
  640. ASSERT(pCmdEntry->cmdType == AVC_CTYPE_NOTIFY && "Changed but not notify cmd!");
  641. }
  642. pCmdEntry->cmdState = CMD_STATE_RESP_ACCEPTED;
  643. pCmdEntry->Status = STATUS_SUCCESS; // -> NOERROR
  644. break;
  645. // AVC.sys should never return this response !!
  646. case AVC_RESPONSE_INTERIM:
  647. ASSERT( pAvcIrb->ResponseCode != AVC_RESPONSE_INTERIM && "CmpRoutine should not has this response!");
  648. pCmdEntry->cmdState = CMD_STATE_RESP_INTERIM;
  649. pCmdEntry->Status = STATUS_MORE_ENTRIES; // ov.Internal
  650. break;
  651. default:
  652. TRACE(TL_FCP_ERROR,("pCmdEntry%x; State:%d; pAvcIrb:%x; RespCode:%x\n", pCmdEntry, pCmdEntry->cmdState, pAvcIrb, pAvcIrb->ResponseCode));
  653. ASSERT(FALSE && "Undefined cmdState");
  654. pCmdEntry->cmdState = CMD_STATE_UNDEFINED;
  655. pCmdEntry->Status = STATUS_NOT_SUPPORTED; // ov.Internal
  656. break;
  657. }
  658. #if DBG
  659. if(pCmdEntry->cmdState != CMD_STATE_UNDEFINED) {
  660. TRACE(TL_FCP_WARNING,("\' AVCRsp: %d:[%.2x %.2x %.2x %.2x]:[%.2x %.2x %.2x %.2x]; cmdSt:%d; St:%x\n",
  661. pAvcIrb->OperandLength+3, // Resp+SuID+OpCd+Opr[]
  662. pAvcIrb->ResponseCode,
  663. pAvcIrb->SubunitAddr[0],
  664. pAvcIrb->Opcode,
  665. pAvcIrb->Operands[0],
  666. pAvcIrb->Operands[1],
  667. pAvcIrb->Operands[2],
  668. pAvcIrb->Operands[3],
  669. pAvcIrb->Operands[4],
  670. pCmdEntry->cmdState,
  671. pCmdEntry->Status
  672. ));
  673. }
  674. #endif
  675. } else {
  676. // Irp returns ERROR !!
  677. if (STATUS_BUS_RESET == pIrp->IoStatus.Status || STATUS_REQUEST_ABORTED == pIrp->IoStatus.Status) {
  678. TRACE(TL_FCP_WARNING,("Bus-Reset or abort (IoStatus.St:%x); pDevRemoved:%d; pCmdEntry:%x; OpC:%x\n", pIrp->IoStatus.Status, pDevExt->bDevRemoved, pCmdEntry, pCmdEntry->OpCode));
  679. // ASSERT only if it was an ABORT while device was NOTt removed.
  680. // ASSERT((pIrp->IoStatus.Status == STATUS_BUS_RESET || pDevExt->bDevRemoved) && "Device not removed but command was aborting ?");
  681. // Busreset while there is an interim pending, signal its client to wake up
  682. // and get the "final" (busreset) result.
  683. if(pCmdEntry->cmdState == CMD_STATE_RESP_INTERIM) {
  684. if(pCmdEntry->cmdType == AVC_CTYPE_CONTROL) {
  685. TRACE(TL_FCP_TRACE,("\'--> BusRest: for control interim\n"));
  686. bSignalInterimCotrolCompleted = TRUE;
  687. } else if(pCmdEntry->cmdType == AVC_CTYPE_NOTIFY) {
  688. TRACE(TL_FCP_TRACE,("\'--> BusRest: for notify interim\n"));
  689. bSignalInterimNotifyCompleted = TRUE;
  690. }
  691. }
  692. }
  693. else {
  694. TRACE(TL_FCP_WARNING,("\'IOCTL_AVC_CLASS Failed, pIrp->IoStatus.Status:%x\n", pIrp->IoStatus.Status));
  695. }
  696. pCmdEntry->cmdState = CMD_STATE_ABORTED;
  697. // If the command was timeout, the application may want to try the command again.
  698. // It is other abort, it might be caused by busreset or dev removal.
  699. if(pIrp->IoStatus.Status == STATUS_TIMEOUT)
  700. pCmdEntry->Status = pIrp->IoStatus.Status;
  701. else if (pIrp->IoStatus.Status == STATUS_DEVICE_DATA_ERROR) // ERROR_CRC
  702. pCmdEntry->Status = pIrp->IoStatus.Status;
  703. else
  704. pCmdEntry->Status = STATUS_REQUEST_ABORTED; // -> ERROR_REQUERT_ABORT
  705. }
  706. //
  707. // If suceeded, translate the AVC response to COM property. if not
  708. // interim's final reponse.
  709. // raw AVC command response
  710. //
  711. if(STATUS_SUCCESS == pCmdEntry->Status &&
  712. !bSignalInterimNotifyCompleted &&
  713. !bSignalInterimCotrolCompleted &&
  714. pCmdEntry->idxDVCRCmd != VCR_RAW_AVC
  715. )
  716. DVCRXlateRawAVC(
  717. pCmdEntry,
  718. pCmdEntry->pProperty
  719. );
  720. // Signal a KS event to inform its client that the final response
  721. // has returned and come and get it.
  722. if(bSignalInterimNotifyCompleted) {
  723. pEvent = NULL;
  724. // There might be multiple instances/threads of IAMExtTransport instance with the same KS event.
  725. // There is only one device so they all enabled event are singalled.
  726. do {
  727. if(pEvent = StreamClassGetNextEvent((PVOID) pDevExt, 0, \
  728. (GUID *)&KSEVENTSETID_EXTDEV_Command, KSEVENT_EXTDEV_COMMAND_NOTIFY_INTERIM_READY, pEvent)) {
  729. // Make sure the right event and then signal it
  730. if(pEvent->EventItem->EventId == KSEVENT_EXTDEV_COMMAND_NOTIFY_INTERIM_READY) {
  731. StreamClassDeviceNotification(SignalDeviceEvent, pDevExt, pEvent);
  732. TRACE(TL_FCP_WARNING,("\'->Signal NOTIFY_INTERIM ready; pEvent:%x, EventId %d.\n", pEvent, pEvent->EventItem->EventId));
  733. }
  734. }
  735. } while (pEvent != NULL);
  736. } else if(bSignalInterimCotrolCompleted) {
  737. pEvent = NULL;
  738. // There might be multiple instances/threads of IAMExtTransport instance with the same KS event.
  739. // There is only one device so they all enabled event are singalled.
  740. do {
  741. if(pEvent = StreamClassGetNextEvent((PVOID) pDevExt, 0, \
  742. (GUID *)&KSEVENTSETID_EXTDEV_Command, KSEVENT_EXTDEV_COMMAND_CONTROL_INTERIM_READY, pEvent)) {
  743. // Make sure the right event and then signal it
  744. if(pEvent->EventItem->EventId == KSEVENT_EXTDEV_COMMAND_CONTROL_INTERIM_READY) {
  745. StreamClassDeviceNotification(SignalDeviceEvent, pDevExt, pEvent);
  746. TRACE(TL_FCP_WARNING,("\'->Signal CONTROL_INTERIM ready; pEvent:%x, EventId %d.\n", pEvent, pEvent->EventItem->EventId));
  747. }
  748. }
  749. } while (pEvent != NULL);
  750. }
  751. // Check that the command entry is ours only to process
  752. // When a command is completed, it will be added to the list and therefore not empty.
  753. // It is designed to be added to the list in this completino routine.
  754. if (!IsListEmpty(&pCmdEntry->ListEntry)) {
  755. if(bSignalInterimNotifyCompleted || bSignalInterimCotrolCompleted) {
  756. // If final reponse is returned, we need to keep them in the list.
  757. TRACE(TL_FCP_TRACE,("\'Final response is completed; stay in the list\n"));
  758. KeReleaseSpinLock(&pDevExt->AVCCmdLock, oldIrql);
  759. }
  760. else {
  761. // This is a undefined path!!!
  762. // The command entry can only be in the list if it is interim of anykind.
  763. // If it is an interim, it will not be removed in the completion routine.
  764. ASSERT(FALSE && "Cannot complete an interim in CR\n");
  765. }
  766. }
  767. else {
  768. // This means that we have completed, but the code that issued the
  769. // command is still executing, and hasn't had a chance to look at
  770. // the results yet. Put this in the command list as a signal that
  771. // we have completed and updated the command state, but are not
  772. // planning to free the command resources.
  773. InsertTailList(&pDevExt->AVCCmdList, &pCmdEntry->ListEntry); pDevExt->cntCommandQueued++;
  774. TRACE(TL_FCP_TRACE,("\'Command completed and Queued(%d); pCmdEntry:%x.\n", pDevExt->cntCommandQueued, pCmdEntry));
  775. KeReleaseSpinLock(&pDevExt->AVCCmdLock, oldIrql);
  776. }
  777. }
  778. else {
  779. TRACE(TL_FCP_WARNING,("DVIssueAVCCommandCR: pCmdEntry:%x; pIrp:%x cancelled\n", pCmdEntry, pIrp));
  780. }
  781. IoFreeIrp(pIrp);
  782. return STATUS_MORE_PROCESSING_REQUIRED;
  783. } // DVIssueAVCCommandCR
  784. NTSTATUS
  785. DVIssueAVCCommand (
  786. IN PDVCR_EXTENSION pDevExt,
  787. IN AvcCommandType cType,
  788. IN DVCR_AVC_COMMAND idxAVCCmd,
  789. IN PVOID pProperty
  790. )
  791. /*++
  792. Routine Description:
  793. Issue a FCP/AVC command.
  794. Arguments:
  795. Return Value:
  796. NTSTATUS
  797. --*/
  798. {
  799. NTSTATUS Status;
  800. PAVCCmdEntry pCmdEntry;
  801. PAVC_COMMAND_IRB pAvcIrb;
  802. PIRP pIrp;
  803. PIO_STACK_LOCATION NextIrpStack;
  804. ULONGLONG tmStart;
  805. DWORD dwElapsed;
  806. KIRQL OldIrql;
  807. LIST_ENTRY *pEntry;
  808. PAGED_CODE();
  809. if(pDevExt->bDevRemoved)
  810. return STATUS_DEVICE_NOT_CONNECTED; // ERROR_NOT_READY
  811. //
  812. // Validate Command type; the command type that each entry of the command table support.
  813. //
  814. switch(cType) {
  815. case AVC_CTYPE_CONTROL:
  816. if((DVcrAVCCmdTable[idxAVCCmd].ulCmdSupported & CMD_CONTROL) != CMD_CONTROL)
  817. return STATUS_NOT_SUPPORTED;
  818. break;
  819. case AVC_CTYPE_STATUS:
  820. if((DVcrAVCCmdTable[idxAVCCmd].ulCmdSupported & CMD_STATUS) != CMD_STATUS)
  821. return STATUS_NOT_SUPPORTED;
  822. break;
  823. case AVC_CTYPE_SPEC_INQ:
  824. if((DVcrAVCCmdTable[idxAVCCmd].ulCmdSupported & CMD_SPEC_INQ) != CMD_SPEC_INQ)
  825. return STATUS_NOT_SUPPORTED;
  826. break;
  827. case AVC_CTYPE_GEN_INQ:
  828. if((DVcrAVCCmdTable[idxAVCCmd].ulCmdSupported & CMD_GEN_INQ) != CMD_GEN_INQ)
  829. return STATUS_NOT_SUPPORTED;
  830. break;
  831. case AVC_CTYPE_NOTIFY:
  832. if((DVcrAVCCmdTable[idxAVCCmd].ulCmdSupported & CMD_NOTIFY) != CMD_NOTIFY)
  833. return STATUS_NOT_SUPPORTED;
  834. break;
  835. default:
  836. TRACE(TL_FCP_ERROR,("DVIssueAVCCommand: Unknown or invalid cmdType: idx %d, ctype (%02x) not supported; (%02x %02x %02x) %d:[%.8x]\n",
  837. idxAVCCmd,
  838. cType,
  839. DVcrAVCCmdTable[idxAVCCmd].CType,
  840. DVcrAVCCmdTable[idxAVCCmd].SubunitAddr,
  841. DVcrAVCCmdTable[idxAVCCmd].Opcode,
  842. DVcrAVCCmdTable[idxAVCCmd].OperandLength,
  843. (DWORD) *(&DVcrAVCCmdTable[idxAVCCmd].Operands[0])
  844. ));
  845. return STATUS_NOT_SUPPORTED;
  846. }
  847. // Restrict only one command to be active at any time.
  848. // "Active" mean, it is in the process of issuing the command to the device
  849. // and is awaiting its first response.
  850. // Even though there is only one device but there might be mulitple thread isssuing
  851. // AVC commands at the same time. By design, application should serialize their command
  852. // but they may not know what COM interface will result in an AVC command. In addition,
  853. // this driver itsefl may issue command to the device. So flow control become necessary.
  854. KeWaitForSingleObject( &pDevExt->hMutexIssueAVCCmd, Executive, KernelMode, FALSE, 0 );
  855. // Check one more time for device removal
  856. if(pDevExt->bDevRemoved) {
  857. KeReleaseMutex(&pDevExt->hMutexIssueAVCCmd, FALSE);
  858. TRACE(TL_FCP_WARNING,("** AVC command but device is removed!\n"));
  859. return STATUS_DEVICE_NOT_CONNECTED; // ERROR_NOT_READY
  860. }
  861. // Most device cannot keep two command of same cmdType and OpCode at the same time
  862. // Go thru list of queued (already issues) command, and search for a possible conflict.
  863. KeAcquireSpinLock(&pDevExt->AVCCmdLock, &OldIrql);
  864. pEntry = pDevExt->AVCCmdList.Flink;
  865. while(pEntry != &pDevExt->AVCCmdList) {
  866. pCmdEntry = (PAVCCmdEntry)pEntry;
  867. // Skip the one that is already completed (many differnt command state).
  868. if(pCmdEntry->cmdState == CMD_STATE_RESP_ACCEPTED ||
  869. pCmdEntry->cmdState == CMD_STATE_RESP_REJECTED ||
  870. pCmdEntry->cmdState == CMD_STATE_RESP_NOT_IMPL ||
  871. pCmdEntry->cmdState == CMD_STATE_ABORTED) {
  872. TRACE(TL_FCP_WARNING,("\'---- pCmdEntry:%x; cmdType:%x; OpCode:%x; completed.\n", pCmdEntry, pCmdEntry->cmdType, pCmdEntry->OpCode));
  873. // Find a matching cmdType and OpCode.
  874. } else if(pCmdEntry->cmdType == cType &&
  875. pCmdEntry->OpCode == DVcrAVCCmdTable[idxAVCCmd].Opcode) {
  876. // Conflict, return error.
  877. TRACE(TL_FCP_ERROR,("---- Conflict pCmdEntry:%x; Current: cmdType:%x, OpCode:%x; rtn STATUS_DEVICE_NOT_READY\n",
  878. pCmdEntry, cType, DVcrAVCCmdTable[idxAVCCmd].Opcode));
  879. // ASSERT(FALSE && "Conflict: duplicate CMD.");
  880. KeReleaseSpinLock(&pDevExt->AVCCmdLock, OldIrql);
  881. KeReleaseMutex(&pDevExt->hMutexIssueAVCCmd, FALSE);
  882. // ERROR_NOT_READY; device not ready for another command
  883. return STATUS_DEVICE_NOT_READY;
  884. }
  885. pEntry = pEntry->Flink;
  886. }
  887. KeReleaseSpinLock(&pDevExt->AVCCmdLock, OldIrql);
  888. // Create an AVC IRB and initialize it -
  889. if(!(pAvcIrb = (AVC_COMMAND_IRB *) ExAllocatePool(NonPagedPool, sizeof(AVC_COMMAND_IRB)))) {
  890. KeReleaseMutex(&pDevExt->hMutexIssueAVCCmd, FALSE);
  891. return STATUS_INSUFFICIENT_RESOURCES;
  892. }
  893. RtlZeroMemory(pAvcIrb, sizeof(AVC_COMMAND_IRB));
  894. pAvcIrb->Function = AVC_FUNCTION_COMMAND;
  895. //
  896. // Set the retry and timeout flag and value. These are adjusted (tuned) to
  897. // some DV device that may not be "semi"-compliant (may take several reteies and
  898. // may take more than 100msec)..
  899. //
  900. pAvcIrb->RetryFlag = 1; // Set to 1 in order to set Retries.
  901. pAvcIrb->Retries = (UCHAR) pDevExt->AVCCmdRetries;
  902. // - set the AVC command type (Control, Status, Notify, General Inquiry, Specific Inquiry)
  903. pAvcIrb->CommandType = cType;
  904. // - override the subunit address in the avc unit driver (if it even has one for us)
  905. pAvcIrb->SubunitAddrFlag = 1;
  906. pAvcIrb->SubunitAddr = &DVcrAVCCmdTable[idxAVCCmd].SubunitAddr;
  907. pAvcIrb->Opcode = DVcrAVCCmdTable[idxAVCCmd].Opcode;
  908. // - include alternate opcodes for the transport state opcode
  909. if (pAvcIrb->Opcode == OPC_TRANSPORT_STATE) {
  910. pAvcIrb->AlternateOpcodesFlag = 1;
  911. pAvcIrb->AlternateOpcodes = pDevExt->TransportModes;
  912. }
  913. // - set up the operand list
  914. pAvcIrb->OperandLength = DVcrAVCCmdTable[idxAVCCmd].OperandLength;
  915. ASSERT(pAvcIrb->OperandLength <= MAX_AVC_OPERAND_BYTES);
  916. RtlCopyMemory(pAvcIrb->Operands, DVcrAVCCmdTable[idxAVCCmd].Operands, pAvcIrb->OperandLength);
  917. // Create an Irp and initialize it
  918. if(!(pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE))) {
  919. ExFreePool(pAvcIrb); pAvcIrb = NULL;
  920. KeReleaseMutex(&pDevExt->hMutexIssueAVCCmd, FALSE);
  921. return STATUS_INSUFFICIENT_RESOURCES;
  922. }
  923. // Create an AVC Command entry and initialize it
  924. if(!(pCmdEntry = (AVCCmdEntry *) ExAllocatePool(NonPagedPool, sizeof(AVCCmdEntry)))) {
  925. ExFreePool(pAvcIrb); pAvcIrb = NULL;
  926. IoFreeIrp(pIrp); pIrp = NULL;
  927. KeReleaseMutex(&pDevExt->hMutexIssueAVCCmd, FALSE);
  928. return STATUS_INSUFFICIENT_RESOURCES;
  929. }
  930. RtlZeroMemory(pCmdEntry, sizeof(AVCCmdEntry));
  931. pCmdEntry->pDevExt = pDevExt; // So we can access pDevExt->AVCCmdList;
  932. pCmdEntry->pProperty = pProperty;
  933. pCmdEntry->cmdState = CMD_STATE_ISSUED;
  934. pCmdEntry->Status = STATUS_UNSUCCESSFUL;
  935. pCmdEntry->cmdType = cType;
  936. pCmdEntry->OpCode = DVcrAVCCmdTable[idxAVCCmd].Opcode;
  937. pCmdEntry->idxDVCRCmd = idxAVCCmd;
  938. pCmdEntry->pAvcIrb = pAvcIrb;
  939. pCmdEntry->pIrp = pIrp;
  940. InitializeListHead(&pCmdEntry->ListEntry); // used as a flag for ownership
  941. TRACE(TL_FCP_WARNING,("\'>>>> AVCCmd: %d:[%.2x %.2x %.2x %.2x]:[%.2x %.2x %.2x %.2x]\n",
  942. pAvcIrb->OperandLength+3, // Resp+SuID+OpCd+Opr[]
  943. cType,
  944. pAvcIrb->SubunitAddr[0],
  945. pAvcIrb->Opcode,
  946. pAvcIrb->Operands[0],
  947. pAvcIrb->Operands[1],
  948. pAvcIrb->Operands[2],
  949. pAvcIrb->Operands[3],
  950. pAvcIrb->Operands[4]
  951. ));
  952. // Finish initializing the Irp
  953. NextIrpStack = IoGetNextIrpStackLocation(pIrp);
  954. NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  955. NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_AVC_CLASS;
  956. NextIrpStack->Parameters.Others.Argument1 = pAvcIrb;
  957. IoSetCompletionRoutine(pIrp, DVIssueAVCCommandCR, pCmdEntry, TRUE, TRUE, TRUE);
  958. pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  959. // Used to monitor response time of an AVC command
  960. tmStart = GetSystemTime();
  961. // Now make the call
  962. // If encounter an interim response, STATUS_PENDING will be returned.
  963. Status =
  964. IoCallDriver(
  965. pDevExt->pBusDeviceObject,
  966. pIrp
  967. );
  968. dwElapsed = (DWORD) ((GetSystemTime() - tmStart)/10000); // Convert 100nsec unit to msec
  969. #if DBG
  970. if(dwElapsed > MAX_RESPONSE_TIME_FOR_ALERT) {
  971. // NON-compliant behaviour
  972. TRACE(TL_FCP_WARNING,("** ST:%x; AVC Cmd took %d msec to response; CmdType:%d; OpCd:%x\n", Status, dwElapsed, cType, DVcrAVCCmdTable[idxAVCCmd].Opcode));
  973. } else {
  974. TRACE(TL_FCP_TRACE,("** ST:%x; AVC Cmd took %d msec to response; CmdType:%d; OpCd:%x\n", Status, dwElapsed, cType, DVcrAVCCmdTable[idxAVCCmd].Opcode));
  975. }
  976. #endif
  977. #ifdef SUPPORT_OPTIMIZE_AVCCMD_RETRIES
  978. //
  979. // Collect statistics of AVC command response time during driver loading phase
  980. //
  981. if(!pDevExt->DrvLoadCompleted) {
  982. if(dwElapsed > pDevExt->AVCCmdRespTimeMax)
  983. pDevExt->AVCCmdRespTimeMax = dwElapsed;
  984. if(dwElapsed < pDevExt->AVCCmdRespTimeMin)
  985. pDevExt->AVCCmdRespTimeMin = dwElapsed;
  986. pDevExt->AVCCmdRespTimeSum += dwElapsed;
  987. pDevExt->AVCCmdCount++;
  988. }
  989. #endif
  990. // Interim response...
  991. if (STATUS_PENDING == Status) {
  992. // WORKITEM: control command can be in interim for a while!!!
  993. // Some DV will return interim but it will completed it with a change quickly.
  994. if(cType == AVC_CTYPE_CONTROL) {
  995. #define MSDV_WAIT_CONTROL_CMD_INTERIM 300
  996. TRACE(TL_FCP_WARNING,("\'!!!!!!!!!!! Control Interim-- Wait %d msec !!!!!!!!\n", MSDV_WAIT_CONTROL_CMD_INTERIM));
  997. DVDelayExecutionThread(MSDV_WAIT_CONTROL_CMD_INTERIM);
  998. #if DBG
  999. if(DVTraceMask & TL_FCP_TRACE) {
  1000. ASSERT(!IsListEmpty(&pCmdEntry->ListEntry) && "Control Cmd was interim after wait.");
  1001. }
  1002. #endif
  1003. }
  1004. KeAcquireSpinLock(&pDevExt->AVCCmdLock, &OldIrql);
  1005. // Check that the Irp didn't complete between the return of IoCallDriver and now
  1006. if (IsListEmpty(&pCmdEntry->ListEntry)) {
  1007. // Enter INTERIM state
  1008. pCmdEntry->cmdState = CMD_STATE_RESP_INTERIM;
  1009. // Return STATUS_MORE_ENTRIES to inform caller that the command is pending.
  1010. pCmdEntry->Status = STATUS_MORE_ENTRIES; // xlate to ERROR_MORE_DATA; No yet done with this command so keep the entry in the list
  1011. // We have submitted a control or notify command, and have gotten
  1012. // an Interim response. Put the command in the list so it can be
  1013. // tracked for possible cancellation, and as an indication to the
  1014. // completion routine that we won't be releasing any resources here.
  1015. InsertTailList(&pDevExt->AVCCmdList, &pCmdEntry->ListEntry); pDevExt->cntCommandQueued++;
  1016. pCmdEntry->pProperty = NULL; // won't be using this, so get rid of it
  1017. TRACE(TL_FCP_TRACE,("\'->AVC command Irp is pending!\n"));
  1018. KeReleaseSpinLock(&pDevExt->AVCCmdLock, OldIrql);
  1019. KeReleaseMutex(&pDevExt->hMutexIssueAVCCmd, FALSE);
  1020. return pCmdEntry->Status;
  1021. } else {
  1022. // Although IoCallDriver indicated that the command was pending,
  1023. // it has since been completed. The completion routine saw that
  1024. // the command entry had not yet been added to the command list,
  1025. // so put it there to let us know that we need to retain control
  1026. // and free the resources.
  1027. //
  1028. // Temporarily change the status so the cleanup code path will
  1029. // be followed.
  1030. TRACE(TL_FCP_TRACE,("\'-> Cmd Rtns Pending but completed; treat as non-pending! ST:%x\n", pCmdEntry->Status));
  1031. Status = STATUS_SUCCESS;
  1032. }
  1033. KeReleaseSpinLock(&pDevExt->AVCCmdLock, OldIrql);
  1034. }
  1035. // Status from IoCallDriver can return:
  1036. // STATUS_PENDING (process above) // If control, we wait and see if it get completed (risky!!)
  1037. // STATUS_TIMEOUT
  1038. // STATUS_SUCCESS
  1039. if(STATUS_PENDING != Status) {
  1040. // The completion routine is usually the only one that frees the Irp. Is
  1041. // it possible that the completion routine never got called? This will let
  1042. // us know, since the completion routine will always make sure that the
  1043. // command entry's Irp pointer is cleared.
  1044. if(pCmdEntry->pIrp) {
  1045. // If for some reason the completion routine never got called, free the Irp
  1046. if(pCmdEntry->pIrp)
  1047. IoFreeIrp(pCmdEntry->pIrp);
  1048. pCmdEntry->pIrp = NULL;
  1049. }
  1050. }
  1051. //
  1052. // pCmdEntry->Status is the command response Status set in the completion routine, which can be
  1053. // STATUS_SUCCESS
  1054. // STATUS_REQ_NOT_ACCEP
  1055. // STATUS_NOT_SUPPORTED
  1056. // STATUS_MORE_ENTRIES // Should not happen!!
  1057. // STATUS_REQUEST_ABORTED
  1058. //
  1059. // One possible valid command from IoCallDriver is STATUS_TIMEOUT, and
  1060. // this shoull be returned, anything else we will get the status from pCmdEntry->Status
  1061. // which was set in the completion routine.
  1062. if (Status != STATUS_TIMEOUT)
  1063. Status = pCmdEntry->Status; // This Status is being returned from this functino
  1064. // Desiding if leaving the command response (entry) in the command list
  1065. #ifndef ALWAYS_SET_N_GET_RAW_AVC
  1066. // Not if it is an (1) interim (all STATUS_MORE_ENTRIES); or (2) suceeded RAW AVC response
  1067. if(STATUS_MORE_ENTRIES == Status ||
  1068. VCR_RAW_AVC == pCmdEntry->idxDVCRCmd && STATUS_SUCCESS == Status) {
  1069. #else
  1070. // Do not remove entrim response or any RAW AVC command response
  1071. if(STATUS_MORE_ENTRIES == Status ||
  1072. VCR_RAW_AVC == pCmdEntry->idxDVCRCmd) {
  1073. #endif
  1074. TRACE(TL_FCP_WARNING,("\'Status:%x; Do not remove (1) interim response or (2) raw AVC command\n", Status));
  1075. }
  1076. // Else we are done!
  1077. else {
  1078. // It's time to clean up the command
  1079. KeAcquireSpinLock(&pDevExt->AVCCmdLock, &OldIrql);
  1080. if (!IsListEmpty(&pCmdEntry->ListEntry)) {
  1081. RemoveEntryList(&pCmdEntry->ListEntry); pDevExt->cntCommandQueued--;
  1082. InitializeListHead(&pCmdEntry->ListEntry); // used as a flag for ownership
  1083. }
  1084. KeReleaseSpinLock(&pDevExt->AVCCmdLock, OldIrql);
  1085. // Free the resources
  1086. ExFreePool(pCmdEntry);
  1087. ExFreePool(pAvcIrb);
  1088. } // else
  1089. #if DBG
  1090. if(!NT_SUCCESS(Status)) {
  1091. TRACE(TL_FCP_WARNING,("\'**** DVIssueAVCCmd (exit): St:%x; pCmdEntry:%x; cmdQueued:%d\n", Status, pCmdEntry, pDevExt->cntCommandQueued));
  1092. }
  1093. #endif
  1094. KeReleaseMutex(&pDevExt->hMutexIssueAVCCmd, FALSE);
  1095. return Status;
  1096. }
  1097. #ifndef OATRUE
  1098. #define OATRUE (-1)
  1099. #endif
  1100. #ifndef OAFALSE
  1101. #define OAFALSE (0)
  1102. #endif
  1103. NTSTATUS
  1104. DVGetExtDeviceProperty(
  1105. IN PDVCR_EXTENSION pDevExt,
  1106. IN PSTREAM_PROPERTY_DESCRIPTOR pSPD,
  1107. OUT PULONG pulActualBytesTransferred
  1108. )
  1109. /*++
  1110. Routine Description:
  1111. Handle Get external device property.
  1112. Arguments:
  1113. pDevExt - Device's extension
  1114. pSPD - Stream property descriptor
  1115. pulActualBytesTransferred - Number of byte transferred.
  1116. Return Value:
  1117. NTSTATUS
  1118. --*/
  1119. {
  1120. NTSTATUS Status = STATUS_SUCCESS;
  1121. PKSPROPERTY_EXTDEVICE_S pExtDeviceProperty;
  1122. PAGED_CODE();
  1123. ASSERT(pDevExt);
  1124. ASSERT(pSPD);
  1125. ASSERT (pSPD->PropertyOutputSize >= sizeof (KSPROPERTY_EXTDEVICE_S));
  1126. pExtDeviceProperty = (PKSPROPERTY_EXTDEVICE_S) pSPD->PropertyInfo; // pointer to the data
  1127. switch (pSPD->Property->Id) {
  1128. case KSPROPERTY_EXTDEVICE_ID:
  1129. if(pDevExt->ulVendorID) {
  1130. // It was not bswap in the monolithic version so for competibility,
  1131. // we will not bswap this.
  1132. pExtDeviceProperty->u.NodeUniqueID[0] = pDevExt->UniqueID.LowPart;
  1133. pExtDeviceProperty->u.NodeUniqueID[1] = pDevExt->UniqueID.HighPart;
  1134. // TRACE(TL_FCP_WARNING,("Vid:%x; Mid:%x\n", bswap(pDevExt->ulVendorID) >> 8, pDevExt->ulModelID ));
  1135. TRACE(TL_FCP_WARNING,("\'Low:%x; High:%x of UniqueID\n", pDevExt->UniqueID.LowPart, pDevExt->UniqueID.HighPart ));
  1136. Status = STATUS_SUCCESS;
  1137. } else {
  1138. TRACE(TL_FCP_ERROR,("Failed: Vid:%x; Mid:%x\n", bswap(pDevExt->ulVendorID) >> 8, pDevExt->ulModelID ));
  1139. Status = STATUS_UNSUCCESSFUL;
  1140. }
  1141. break;
  1142. case KSPROPERTY_EXTDEVICE_VERSION:
  1143. // AV/C VCR Subunit Specification 2.0.1
  1144. wcscpy(pExtDeviceProperty->u.pawchString, L"2.0.1");
  1145. Status = STATUS_SUCCESS;
  1146. break;
  1147. case KSPROPERTY_EXTDEVICE_POWER_STATE:
  1148. switch(pDevExt->PowerState) {
  1149. case PowerDeviceD3:
  1150. pExtDeviceProperty->u.PowerState = ED_POWER_OFF;
  1151. break;
  1152. case PowerDeviceD2:
  1153. case PowerDeviceD1:
  1154. pExtDeviceProperty->u.PowerState = ED_POWER_STANDBY;
  1155. break;
  1156. default:
  1157. case PowerDeviceD0:
  1158. pExtDeviceProperty->u.PowerState = ED_POWER_ON;
  1159. break;
  1160. }
  1161. Status = STATUS_SUCCESS;
  1162. break;
  1163. case KSPROPERTY_EXTDEVICE_PORT:
  1164. pExtDeviceProperty->u.DevPort = DEV_PORT_1394;
  1165. Status = STATUS_SUCCESS;
  1166. break;
  1167. case KSPROPERTY_EXTDEVICE_CAPABILITIES:
  1168. if((GetSystemTime() - pDevExt->tmLastFormatUpdate) > FORMAT_UPDATE_INTERVAL) {
  1169. // Refresh mode of operation whenever capabilities is queried
  1170. // since the mode of operation might have changed and is returned..
  1171. DVGetDevModeOfOperation(pDevExt);
  1172. // Since format can dynamically change, we will query new format here.
  1173. // Note: during data intersection, we compare FrameSize and that is
  1174. // format related.
  1175. if(!DVGetDevSignalFormat(pDevExt, KSPIN_DATAFLOW_OUT,0)) {
  1176. // If querying its format has failed, we cannot open this stream.
  1177. TRACE(TL_FCP_WARNING,("SRB_GET_DATA_INTERSECTION:Failed getting signal format.\n"));
  1178. }
  1179. // Update system time to reflect last update
  1180. pDevExt->tmLastFormatUpdate = GetSystemTime();
  1181. }
  1182. // Can record only in VCR mode and has input plug(s).
  1183. pExtDeviceProperty->u.Capabilities.CanRecord = ((pDevExt->ulDevType == ED_DEVTYPE_VCR) ? (pDevExt->NumInputPlugs > 0 ? OATRUE : OAFALSE): OAFALSE);
  1184. pExtDeviceProperty->u.Capabilities.CanRecordStrobe = OAFALSE;
  1185. pExtDeviceProperty->u.Capabilities.HasAudio = OATRUE;
  1186. pExtDeviceProperty->u.Capabilities.HasVideo = OATRUE;
  1187. pExtDeviceProperty->u.Capabilities.UsesFiles = OAFALSE;
  1188. pExtDeviceProperty->u.Capabilities.CanSave = OAFALSE;
  1189. pExtDeviceProperty->u.Capabilities.DeviceType = pDevExt->ulDevType;
  1190. pExtDeviceProperty->u.Capabilities.TCRead = OATRUE;
  1191. pExtDeviceProperty->u.Capabilities.TCWrite = OAFALSE; // DV decided
  1192. pExtDeviceProperty->u.Capabilities.CTLRead = OAFALSE;
  1193. pExtDeviceProperty->u.Capabilities.IndexRead = OAFALSE;
  1194. pExtDeviceProperty->u.Capabilities.Preroll = 0L; // NOT implemented, supposely can reg in INF and then read from registry
  1195. pExtDeviceProperty->u.Capabilities.Postroll = 0L; // NOT implemented, supposely can reg in INF and then read from registry
  1196. pExtDeviceProperty->u.Capabilities.SyncAcc = ED_CAPABILITY_UNKNOWN;
  1197. pExtDeviceProperty->u.Capabilities.NormRate = ((pDevExt->VideoFormatIndex == FMT_IDX_SD_DVCR_NTSC || pDevExt->VideoFormatIndex == FMT_IDX_SDL_DVCR_NTSC) ? ED_RATE_2997 : ED_RATE_25);
  1198. pExtDeviceProperty->u.Capabilities.CanPreview = OAFALSE; // View what is in the bus or tape
  1199. pExtDeviceProperty->u.Capabilities.CanMonitorSrc = OATRUE; // ViewFinder
  1200. pExtDeviceProperty->u.Capabilities.CanTest = OAFALSE; // To see if a function is iplemented
  1201. pExtDeviceProperty->u.Capabilities.VideoIn = OAFALSE;
  1202. pExtDeviceProperty->u.Capabilities.AudioIn = OAFALSE;
  1203. pExtDeviceProperty->u.Capabilities.Calibrate = OAFALSE;
  1204. pExtDeviceProperty->u.Capabilities.SeekType = ED_CAPABILITY_UNKNOWN;
  1205. TRACE(TL_FCP_INFO,("\'DVCRGetExtDeviceProperty: DeviceType %x\n", pExtDeviceProperty->u.Capabilities.DeviceType));
  1206. Status = STATUS_SUCCESS;
  1207. break;
  1208. default:
  1209. Status = STATUS_NOT_SUPPORTED;
  1210. break;
  1211. }
  1212. *pulActualBytesTransferred = (Status == STATUS_SUCCESS ? sizeof (KSPROPERTY_EXTDEVICE_S) : 0);
  1213. return Status;
  1214. }
  1215. NTSTATUS
  1216. DVSetExtDeviceProperty(
  1217. IN PDVCR_EXTENSION pDevExt,
  1218. IN PSTREAM_PROPERTY_DESCRIPTOR pSPD,
  1219. OUT ULONG *pulActualBytesTransferred
  1220. )
  1221. /*++
  1222. Routine Description:
  1223. Handle Set external device property.
  1224. Arguments:
  1225. pDevExt - Device's extension
  1226. pSPD - Stream property descriptor
  1227. pulActualBytesTransferred - Number of byte transferred.
  1228. Return Value:
  1229. NTSTATUS
  1230. --*/
  1231. {
  1232. NTSTATUS Status = STATUS_SUCCESS;
  1233. PKSPROPERTY_EXTDEVICE_S pExtDeviceProperty;
  1234. PAGED_CODE();
  1235. ASSERT(pDevExt);
  1236. ASSERT(pSPD);
  1237. ASSERT (pSPD->PropertyOutputSize >= sizeof (KSPROPERTY_EXTDEVICE_S));
  1238. pExtDeviceProperty = (PKSPROPERTY_EXTDEVICE_S) pSPD->PropertyInfo; // pointer to the data
  1239. switch (pSPD->Property->Id) {
  1240. default:
  1241. Status = STATUS_NOT_SUPPORTED;
  1242. break;
  1243. }
  1244. *pulActualBytesTransferred = (Status == STATUS_SUCCESS ? sizeof (KSPROPERTY_EXTDEVICE_S) : 0);
  1245. return Status;
  1246. }
  1247. NTSTATUS
  1248. DVGetExtTransportProperty(
  1249. IN PDVCR_EXTENSION pDevExt,
  1250. IN PSTREAM_PROPERTY_DESCRIPTOR pSPD,
  1251. OUT ULONG *pulActualBytesTransferred
  1252. )
  1253. /*++
  1254. Routine Description:
  1255. Handle Get external transport property.
  1256. Arguments:
  1257. pDevExt - Device's extension
  1258. pSPD - Stream property descriptor
  1259. pulActualBytesTransferred - Number of byte transferred.
  1260. Return Value:
  1261. NTSTATUS
  1262. --*/
  1263. {
  1264. NTSTATUS Status = STATUS_NOT_SUPPORTED;
  1265. PKSPROPERTY_EXTXPORT_S pXPrtProperty;
  1266. DVCR_AVC_COMMAND idxDVCRCmd;
  1267. AvcCommandType cType = AVC_CTYPE_STATUS;
  1268. BOOL bHasTape = pDevExt->bHasTape;
  1269. PAVCCmdEntry pCmdEntry;
  1270. PAGED_CODE();
  1271. ASSERT(pDevExt);
  1272. ASSERT(pSPD);
  1273. ASSERT (pSPD->PropertyOutputSize >= sizeof (KSPROPERTY_EXTXPORT_S));
  1274. pXPrtProperty = (PKSPROPERTY_EXTXPORT_S) pSPD->PropertyInfo; // pointer to the data
  1275. *pulActualBytesTransferred = 0;
  1276. switch (pSPD->Property->Id) {
  1277. case KSPROPERTY_EXTXPORT_CAPABILITIES:
  1278. return STATUS_NOT_IMPLEMENTED;
  1279. case KSPROPERTY_RAW_AVC_CMD:
  1280. pCmdEntry = DVCRFindCmdEntryCompleted(
  1281. pDevExt,
  1282. VCR_RAW_AVC,
  1283. DVcrAVCCmdTable[VCR_RAW_AVC].Opcode,
  1284. DVcrAVCCmdTable[VCR_RAW_AVC].CType
  1285. );
  1286. if(pCmdEntry) {
  1287. PAVC_COMMAND_IRB pAvcIrb;
  1288. pAvcIrb = pCmdEntry->pAvcIrb;
  1289. ASSERT(pAvcIrb);
  1290. #ifndef ALWAYS_SET_N_GET_RAW_AVC
  1291. // Only successful response has a valid response to return
  1292. if (pCmdEntry->cmdState == CMD_STATE_RESP_ACCEPTED) {
  1293. #else
  1294. // Any of these response codes has a response to return,
  1295. // include "reject", "not implemented" response code
  1296. if (pCmdEntry->cmdState == CMD_STATE_RESP_ACCEPTED ||
  1297. pCmdEntry->cmdState == CMD_STATE_RESP_REJECTED ||
  1298. pCmdEntry->cmdState == CMD_STATE_RESP_NOT_IMPL ||
  1299. pCmdEntry->cmdState == CMD_STATE_RESP_INTERIM) {
  1300. #endif
  1301. // bytes for operands plus response, subunit addr, and opcode
  1302. pXPrtProperty->u.RawAVC.PayloadSize = pAvcIrb->OperandLength + 3;
  1303. pXPrtProperty->u.RawAVC.Payload[0] = pAvcIrb->ResponseCode;
  1304. pXPrtProperty->u.RawAVC.Payload[1] = pAvcIrb->SubunitAddr[0];
  1305. pXPrtProperty->u.RawAVC.Payload[2] = pAvcIrb->Opcode;
  1306. RtlCopyMemory(&pXPrtProperty->u.RawAVC.Payload[3], pAvcIrb->Operands, pAvcIrb->OperandLength);
  1307. TRACE(TL_FCP_WARNING,("\'RawAVCResp: pEntry:%x; State:%x; Status:%x; Sz:%d; Rsp:%x;SuId:%x;OpCd:%x; Opr:[%x %x %x %x]\n",
  1308. pCmdEntry, pCmdEntry->cmdState, pCmdEntry->Status,
  1309. pXPrtProperty->u.RawAVC.PayloadSize,
  1310. pXPrtProperty->u.RawAVC.Payload[0],
  1311. pXPrtProperty->u.RawAVC.Payload[1],
  1312. pXPrtProperty->u.RawAVC.Payload[2],
  1313. pXPrtProperty->u.RawAVC.Payload[3],
  1314. pXPrtProperty->u.RawAVC.Payload[4],
  1315. pXPrtProperty->u.RawAVC.Payload[5],
  1316. pXPrtProperty->u.RawAVC.Payload[6]
  1317. ));
  1318. // Final Status
  1319. #ifndef ALWAYS_SET_N_GET_RAW_AVC
  1320. Status = pCmdEntry->Status;
  1321. #else
  1322. // If not success, bytes transferred and data will not returned!
  1323. Status = STATUS_SUCCESS;
  1324. #endif
  1325. *pulActualBytesTransferred = sizeof (KSPROPERTY_EXTXPORT_S);
  1326. } else {
  1327. TRACE(TL_FCP_ERROR,("\'RawAVCResp: Found; but pCmdEntry:%x, unexpected cmdState:%d; ST:%x\n", pCmdEntry, pCmdEntry->cmdState, pCmdEntry->Status));
  1328. //ASSERT(pCmdEntry->cmdState == CMD_STATE_RESP_ACCEPTED && "Unexpected command state\n");
  1329. if(pCmdEntry->Status == STATUS_TIMEOUT)
  1330. Status = STATUS_TIMEOUT; // if timeout, application may want to try again.
  1331. else
  1332. Status = STATUS_REQUEST_ABORTED;
  1333. *pulActualBytesTransferred = 0;
  1334. }
  1335. // pIrp is NULL if it has been completed.
  1336. if(pCmdEntry->pIrp) {
  1337. TRACE(TL_FCP_ERROR,("RawAVCResp: pCmdEntry %x; ->pIrp:%x not completd yet!\n", pCmdEntry, pCmdEntry->pIrp));
  1338. ASSERT(pCmdEntry->pIrp == NULL && "pIrp is not completed!");
  1339. IoCancelIrp(pCmdEntry->pIrp);
  1340. }
  1341. // Not used in the completion routine if pIrp->Cancel
  1342. ExFreePool(pCmdEntry);
  1343. ExFreePool(pAvcIrb);
  1344. }
  1345. else {
  1346. TRACE(TL_FCP_ERROR,("\'RAW_AVC_CMD, did not find a match[%x]!\n",
  1347. *((DWORD *) &DVcrAVCCmdTable[VCR_RAW_AVC].CType) ));
  1348. *pulActualBytesTransferred = 0;
  1349. Status = STATUS_NOT_FOUND; // ERROR_MR_MID_NOT_FOUND
  1350. }
  1351. return Status;
  1352. case KSPROPERTY_EXTXPORT_INPUT_SIGNAL_MODE: // MPEG, D-VHS, Analog VHS etc.
  1353. idxDVCRCmd = VCR_INPUT_SIGNAL_MODE;
  1354. break;
  1355. case KSPROPERTY_EXTXPORT_OUTPUT_SIGNAL_MODE: // MPEG, D-VHS, Analog VHS etc.
  1356. idxDVCRCmd = VCR_OUTPUT_SIGNAL_MODE;
  1357. break;
  1358. case KSPROPERTY_EXTXPORT_MEDIUM_INFO: // cassettte_type and tape_grade_and_write_protect
  1359. idxDVCRCmd = VCR_MEDIUM_INFO;
  1360. break;
  1361. case KSPROPERTY_EXTXPORT_STATE:
  1362. idxDVCRCmd = VCR_TRANSPORT_STATE;
  1363. break;
  1364. case KSPROPERTY_EXTXPORT_STATE_NOTIFY:
  1365. // Get final result from previous set command
  1366. pCmdEntry = DVCRFindCmdEntryCompleted(
  1367. pDevExt,
  1368. VCR_TRANSPORT_STATE_NOTIFY,
  1369. DVcrAVCCmdTable[VCR_TRANSPORT_STATE_NOTIFY].Opcode,
  1370. DVcrAVCCmdTable[VCR_TRANSPORT_STATE_NOTIFY].CType
  1371. );
  1372. if(pCmdEntry) {
  1373. PAVC_COMMAND_IRB pAvcIrb;
  1374. pAvcIrb = pCmdEntry->pAvcIrb;
  1375. ASSERT(pCmdEntry->pAvcIrb);
  1376. TRACE(TL_FCP_WARNING,("\'->Notify Resp: pCmdEntry:%x; pIrb:%x; %d:[%.2x %.2x %.2x %.2x]\n",
  1377. pCmdEntry, pAvcIrb,
  1378. pAvcIrb->OperandLength + 3,
  1379. pAvcIrb->ResponseCode,
  1380. pAvcIrb->SubunitAddr[0],
  1381. pAvcIrb->Opcode,
  1382. pAvcIrb->Operands[0]
  1383. ));
  1384. if(pCmdEntry->cmdState == CMD_STATE_RESP_ACCEPTED)
  1385. Status =
  1386. DVCRXlateRawAVC(
  1387. pCmdEntry,
  1388. pXPrtProperty
  1389. );
  1390. // pIrp is NULL if it has been completed.
  1391. if(pCmdEntry->pIrp) {
  1392. TRACE(TL_FCP_ERROR,("XPrtNotifyResp: pCmdEntry %x; ->pIrp:%x not completed; IoCancelIrp(pIrp)\n", pCmdEntry, pCmdEntry->pIrp));
  1393. IoCancelIrp(pCmdEntry->pIrp);
  1394. }
  1395. // These two are not touched in the CompletionRoutine if pIrp->Cancel
  1396. ExFreePool(pCmdEntry);
  1397. ExFreePool(pAvcIrb);
  1398. *pulActualBytesTransferred = STATUS_SUCCESS == Status ? sizeof (KSPROPERTY_EXTXPORT_S) : 0;
  1399. }
  1400. else {
  1401. TRACE(TL_FCP_ERROR,("EXTXPORT_STATE_NOTIFY: no match!\n"));
  1402. *pulActualBytesTransferred = 0;
  1403. Status = STATUS_NOT_FOUND; // ERROR_MR_MID_NOT_FOUND
  1404. }
  1405. return Status;
  1406. default:
  1407. TRACE(TL_FCP_ERROR,("DVCRGetExtTransportProperty: NOT_IMPLEMENTED Property->Id %d\n", pSPD->Property->Id));
  1408. return STATUS_NOT_SUPPORTED;
  1409. }
  1410. Status = DVIssueAVCCommand(pDevExt, cType, idxDVCRCmd, (PVOID) pXPrtProperty);
  1411. TRACE(TL_FCP_TRACE,("\'DVCRGetExtTransportProperty: idxDVCRCmd %d, cmdType %d, Status %x\n", idxDVCRCmd, cType, Status));
  1412. *pulActualBytesTransferred = (Status == STATUS_SUCCESS ? sizeof (KSPROPERTY_EXTXPORT_S) : 0);
  1413. if(STATUS_SUCCESS == Status &&
  1414. idxDVCRCmd == VCR_MEDIUM_INFO) {
  1415. // Update Media info
  1416. pDevExt->bHasTape = pXPrtProperty->u.MediumInfo.MediaPresent;
  1417. pDevExt->bWriteProtected = pXPrtProperty->u.MediumInfo.RecordInhibit;
  1418. TRACE(TL_FCP_TRACE,("\'bHasTape: IN(%d):OUT(%d), ulDevType %d\n", bHasTape, pDevExt->bHasTape, pDevExt->ulDevType));
  1419. }
  1420. return Status;
  1421. }
  1422. NTSTATUS
  1423. DVSetExtTransportProperty(
  1424. IN PDVCR_EXTENSION pDevExt,
  1425. IN PSTREAM_PROPERTY_DESCRIPTOR pSPD,
  1426. OUT ULONG *pulActualBytesTransferred
  1427. )
  1428. /*++
  1429. Routine Description:
  1430. Handle Set external transport property.
  1431. Arguments:
  1432. pDevExt - Device's extension
  1433. pSPD - Stream property descriptor
  1434. pulActualBytesTransferred - Number of byte transferr
  1435. Return Value:
  1436. NTSTATUS
  1437. --*/
  1438. {
  1439. NTSTATUS Status = STATUS_SUCCESS;
  1440. PKSPROPERTY_EXTXPORT_S pXPrtProperty;
  1441. DVCR_AVC_COMMAND idxDVCRCmd;
  1442. AvcCommandType cType = AVC_CTYPE_CONTROL;
  1443. PAGED_CODE();
  1444. ASSERT(pDevExt);
  1445. ASSERT(pSPD);
  1446. ASSERT (pSPD->PropertyOutputSize >= sizeof (KSPROPERTY_EXTXPORT_S));
  1447. pXPrtProperty = (PKSPROPERTY_EXTXPORT_S) pSPD->PropertyInfo; // pointer to the data
  1448. *pulActualBytesTransferred = 0;
  1449. switch (pSPD->Property->Id) {
  1450. case KSPROPERTY_EXTXPORT_STATE:
  1451. switch (pXPrtProperty->u.XPrtState.Mode) {
  1452. // RECORD
  1453. case ED_MODE_RECORD:
  1454. idxDVCRCmd = VCR_RECORD;
  1455. break;
  1456. case ED_MODE_RECORD_FREEZE:
  1457. idxDVCRCmd = VCR_RECORD_PAUSE;
  1458. break;
  1459. // PLAY
  1460. case ED_MODE_STEP_FWD:
  1461. idxDVCRCmd = VCR_PLAY_FORWARD_STEP;
  1462. break;
  1463. case ED_MODE_PLAY_SLOWEST_FWD:
  1464. // DVCPRO does not seem to support the standard play slow fwd so this is an alternate
  1465. if(pDevExt->bDVCPro)
  1466. idxDVCRCmd = VCR_PLAY_FORWARD_SLOWEST2;
  1467. else
  1468. idxDVCRCmd = VCR_PLAY_FORWARD_SLOWEST;
  1469. break;
  1470. case ED_MODE_PLAY_FASTEST_FWD:
  1471. idxDVCRCmd = VCR_PLAY_FORWARD_FASTEST;
  1472. break;
  1473. case ED_MODE_STEP_REV:
  1474. idxDVCRCmd = VCR_PLAY_REVERSE_STEP;
  1475. break;
  1476. case ED_MODE_PLAY_SLOWEST_REV:
  1477. // DVCPRO does not seem to support the standard play slow rev so this is an alternate
  1478. if(pDevExt->bDVCPro)
  1479. idxDVCRCmd = VCR_PLAY_REVERSE_SLOWEST2;
  1480. else
  1481. idxDVCRCmd = VCR_PLAY_REVERSE_SLOWEST;
  1482. break;
  1483. case ED_MODE_PLAY_FASTEST_REV:
  1484. idxDVCRCmd = VCR_PLAY_REVERSE_FASTEST;
  1485. break;
  1486. case ED_MODE_PLAY:
  1487. idxDVCRCmd = VCR_PLAY_FORWARD;
  1488. break;
  1489. case ED_MODE_FREEZE:
  1490. idxDVCRCmd = VCR_PLAY_FORWARD_PAUSE;
  1491. break;
  1492. // WIND
  1493. case ED_MODE_STOP:
  1494. idxDVCRCmd = VCR_WIND_STOP;
  1495. break;
  1496. case ED_MODE_FF:
  1497. idxDVCRCmd = VCR_WIND_FAST_FORWARD;
  1498. break;
  1499. case ED_MODE_REW:
  1500. idxDVCRCmd = VCR_WIND_REWIND;
  1501. break;
  1502. default:
  1503. TRACE(TL_FCP_ERROR,("XPrtState.Mode %d not supported\n", pXPrtProperty->u.XPrtState.Mode));
  1504. return STATUS_NOT_SUPPORTED;
  1505. }
  1506. break;
  1507. case KSPROPERTY_EXTXPORT_STATE_NOTIFY:
  1508. idxDVCRCmd = VCR_TRANSPORT_STATE_NOTIFY;
  1509. cType = AVC_CTYPE_NOTIFY;
  1510. TRACE(TL_FCP_TRACE,("\'->Notify XPrt State Cmd issued.\n"));
  1511. break;
  1512. case KSPROPERTY_EXTXPORT_LOAD_MEDIUM:
  1513. idxDVCRCmd = VCR_LOAD_MEDIUM_EJECT;
  1514. break;
  1515. case KSPROPERTY_EXTXPORT_TIMECODE_SEARCH:
  1516. idxDVCRCmd = VCR_TIMECODE_SEARCH;
  1517. TRACE(TL_FCP_WARNING,("\'KSPROPERTY_EXTXPORT_TIMECODE_SEARCH NOT_SUPPORTED\n"));
  1518. *pulActualBytesTransferred = 0;
  1519. return STATUS_NOT_SUPPORTED;
  1520. case KSPROPERTY_EXTXPORT_ATN_SEARCH:
  1521. idxDVCRCmd = VCR_ATN_SEARCH;
  1522. TRACE(TL_FCP_WARNING,("\'KSPROPERTY_EXTXPORT_ATN_SEARCH NOT_SUPPORTED\n"));
  1523. *pulActualBytesTransferred = 0;
  1524. return STATUS_NOT_SUPPORTED;
  1525. case KSPROPERTY_EXTXPORT_RTC_SEARCH:
  1526. idxDVCRCmd = VCR_RTC_SEARCH;
  1527. TRACE(TL_FCP_WARNING,("\'KSPROPERTY_EXTXPORT_RTC_SEARCH NOT_SUPPORTED\n"));
  1528. *pulActualBytesTransferred = 0;
  1529. return STATUS_NOT_SUPPORTED;
  1530. case KSPROPERTY_RAW_AVC_CMD:
  1531. idxDVCRCmd = VCR_RAW_AVC;
  1532. if(pXPrtProperty->u.RawAVC.PayloadSize <= MAX_FCP_PAYLOAD_SIZE) {
  1533. DVcrAVCCmdTable[idxDVCRCmd].CType = pXPrtProperty->u.RawAVC.Payload[0];
  1534. DVcrAVCCmdTable[idxDVCRCmd].SubunitAddr = pXPrtProperty->u.RawAVC.Payload[1];
  1535. DVcrAVCCmdTable[idxDVCRCmd].Opcode = pXPrtProperty->u.RawAVC.Payload[2];
  1536. DVcrAVCCmdTable[idxDVCRCmd].OperandLength = pXPrtProperty->u.RawAVC.PayloadSize - 3;
  1537. RtlCopyMemory(DVcrAVCCmdTable[idxDVCRCmd].Operands, pXPrtProperty->u.RawAVC.Payload + 3, DVcrAVCCmdTable[idxDVCRCmd].OperandLength);
  1538. // extract command type; for RAW AVC, it can be anything.
  1539. cType = pXPrtProperty->u.RawAVC.Payload[0];
  1540. TRACE(TL_FCP_WARNING,("\'DVCRSetExtTransportProperty: Set*, cType %x, PayLoadSize %d, PayLoad %x %x %x %x\n",
  1541. cType,
  1542. pXPrtProperty->u.RawAVC.PayloadSize,
  1543. pXPrtProperty->u.RawAVC.Payload[0],
  1544. pXPrtProperty->u.RawAVC.Payload[1],
  1545. pXPrtProperty->u.RawAVC.Payload[2],
  1546. pXPrtProperty->u.RawAVC.Payload[3]
  1547. ));
  1548. } else {
  1549. Status = STATUS_INVALID_PARAMETER;
  1550. *pulActualBytesTransferred = 0;
  1551. return Status;
  1552. }
  1553. break;
  1554. default:
  1555. TRACE(TL_FCP_ERROR,("DVCRSetExtTransportProperty: NOT_IMPLEMENTED Property->Id %d\n", pSPD->Property->Id));
  1556. return STATUS_NOT_SUPPORTED;
  1557. }
  1558. Status = DVIssueAVCCommand(pDevExt, cType, idxDVCRCmd, (PVOID) pXPrtProperty);
  1559. #ifdef SUPPORT_XPRT_STATE_WAIT_FOR_STABLE
  1560. #ifdef READ_CUTOMIZE_REG_VALUES
  1561. // Wait for the transport state change to be stablized.
  1562. // This is only necessary for DV camcorder that reject (or not accept) command following
  1563. // a transport state change. Most of application will issue a transport state control
  1564. // command follows by a query transport state status command. The later command usually
  1565. // failed. A wait will allow some time for the transport mechanism to stablized and therefore
  1566. // accepting command again. This ought to be done in a registry set in an INF file.
  1567. if(STATUS_SUCCESS == Status &&
  1568. (KSPROPERTY_EXTXPORT_STATE == pSPD->Property->Id ||
  1569. (VCR_RAW_AVC == pSPD->Property->Id && cType == AVC_CTYPE_CONTROL &&
  1570. (pXPrtProperty->u.RawAVC.Payload[2] == OPC_RECORD ||
  1571. pXPrtProperty->u.RawAVC.Payload[2] == OPC_PLAY ||
  1572. pXPrtProperty->u.RawAVC.Payload[2] == OPC_WIND
  1573. )
  1574. )
  1575. )
  1576. ) {
  1577. #define MAX_XPRT_WAIT 5000
  1578. if(pDevExt->XprtStateChangeWait > MAX_XPRT_WAIT)
  1579. pDevExt->XprtStateChangeWait = MAX_XPRT_WAIT;
  1580. if(pDevExt->XprtStateChangeWait > 0) {
  1581. TRACE(TL_FCP_WARNING,("^^^^^^ Delay %d msec for Xprt state to stablized!^^^^^^\n", pDevExt->XprtStateChangeWait));
  1582. DVDelayExecutionThread(pDevExt->XprtStateChangeWait);
  1583. }
  1584. }
  1585. #endif
  1586. #endif
  1587. TRACE(TL_FCP_TRACE,("\'DVCRSetExtTransportProperty: idxDVCRCmd %d, Status %x\n", idxDVCRCmd, Status));
  1588. *pulActualBytesTransferred = (Status == STATUS_SUCCESS ? sizeof (PKSPROPERTY_EXTXPORT_S) : 0);
  1589. return Status;
  1590. }
  1591. NTSTATUS
  1592. DVGetTimecodeReaderProperty(
  1593. IN PDVCR_EXTENSION pDevExt,
  1594. IN PSTREAM_PROPERTY_DESCRIPTOR pSPD,
  1595. OUT PULONG pulActualBytesTransferred
  1596. )
  1597. /*++
  1598. Routine Description:
  1599. Arguments:
  1600. Return Value:
  1601. NTSTATUS
  1602. --*/
  1603. {
  1604. NTSTATUS Status = STATUS_SUCCESS;
  1605. PKSPROPERTY_TIMECODE_S pTmCdReaderProperty;
  1606. DVCR_AVC_COMMAND idxDVCRCmd;
  1607. PAGED_CODE();
  1608. ASSERT (pSPD->PropertyOutputSize >= sizeof (KSPROPERTY_TIMECODE_S));
  1609. pTmCdReaderProperty = (PKSPROPERTY_TIMECODE_S) pSPD->PropertyInfo; // pointer to the data
  1610. *pulActualBytesTransferred = 0;
  1611. switch (pSPD->Property->Id) {
  1612. case KSPROPERTY_TIMECODE_READER:
  1613. idxDVCRCmd = VCR_TIMECODE_READ;
  1614. #ifdef MSDV_SUPPORT_EXTRACT_SUBCODE_DATA
  1615. // There can only be one active stream.
  1616. if(pDevExt->cndStrmOpen == 1 &&
  1617. pDevExt->paStrmExt[pDevExt->idxStreamNumber]->StreamState == KSSTATE_RUN) {
  1618. if(pDevExt->paStrmExt[pDevExt->idxStreamNumber]->bTimecodeUpdated) {
  1619. // Once it is read, it is stale.
  1620. pDevExt->paStrmExt[pDevExt->idxStreamNumber]->bTimecodeUpdated = FALSE;
  1621. pTmCdReaderProperty->TimecodeSamp.timecode.dwFrames =
  1622. (((DWORD) pDevExt->paStrmExt[pDevExt->idxStreamNumber]->Timecode[0]) << 24) |
  1623. (((DWORD) pDevExt->paStrmExt[pDevExt->idxStreamNumber]->Timecode[1]) << 16) |
  1624. (((DWORD) pDevExt->paStrmExt[pDevExt->idxStreamNumber]->Timecode[2]) << 8) |
  1625. ((DWORD) pDevExt->paStrmExt[pDevExt->idxStreamNumber]->Timecode[3]);
  1626. *pulActualBytesTransferred = (Status == STATUS_SUCCESS ? sizeof (KSPROPERTY_TIMECODE_S) : 0);
  1627. return STATUS_SUCCESS;
  1628. }
  1629. else {
  1630. TRACE(TL_FCP_TRACE,("\'bTimecode stale, issue AVC command to read it.\n"));
  1631. }
  1632. }
  1633. #endif
  1634. break;
  1635. case KSPROPERTY_ATN_READER:
  1636. idxDVCRCmd = VCR_ATN_READ;
  1637. #ifdef MSDV_SUPPORT_EXTRACT_SUBCODE_DATA
  1638. // There can only be one active stream.
  1639. if(pDevExt->cndStrmOpen == 1 &&
  1640. pDevExt->paStrmExt[pDevExt->idxStreamNumber]->StreamState == KSSTATE_RUN) {
  1641. if(pDevExt->paStrmExt[pDevExt->idxStreamNumber]->bATNUpdated) {
  1642. // Once it is read, it is stale.
  1643. pDevExt->paStrmExt[pDevExt->idxStreamNumber]->bATNUpdated = FALSE;
  1644. pTmCdReaderProperty->TimecodeSamp.timecode.dwFrames =
  1645. pDevExt->paStrmExt[pDevExt->idxStreamNumber]->AbsTrackNumber >> 1;
  1646. pTmCdReaderProperty->TimecodeSamp.dwUser =
  1647. pDevExt->paStrmExt[pDevExt->idxStreamNumber]->AbsTrackNumber & 0x00000001;
  1648. *pulActualBytesTransferred = (Status == STATUS_SUCCESS ? sizeof (KSPROPERTY_TIMECODE_S) : 0);
  1649. return STATUS_SUCCESS;
  1650. }
  1651. else {
  1652. TRACE(TL_FCP_WARNING,("\'bATN stale, issue AVC command to read it.\n"));
  1653. }
  1654. }
  1655. #endif
  1656. break;
  1657. case KSPROPERTY_RTC_READER:
  1658. idxDVCRCmd = VCR_RTC_READ;
  1659. break;
  1660. default:
  1661. TRACE(TL_FCP_ERROR,("DVCRGetTimecodeReaderProperty: NOT_IMPLEMENTED Property->Id %d\n", pSPD->Property->Id));
  1662. return STATUS_NOT_SUPPORTED;
  1663. }
  1664. Status =
  1665. DVIssueAVCCommand(
  1666. pDevExt,
  1667. AVC_CTYPE_STATUS,
  1668. idxDVCRCmd,
  1669. (PVOID) pTmCdReaderProperty
  1670. );
  1671. TRACE(TL_FCP_TRACE,("\'DVCRGetTimecodeReaderProperty: idxDVCRCmd %d, Status %x\n", idxDVCRCmd, Status));
  1672. *pulActualBytesTransferred = (Status == STATUS_SUCCESS ? sizeof (KSPROPERTY_TIMECODE_S) : 0);
  1673. return Status;
  1674. }
  1675. NTSTATUS
  1676. DVMediaSeekingProperty(
  1677. IN PDVCR_EXTENSION pDevExt,
  1678. IN PSTREAM_PROPERTY_DESCRIPTOR pSPD,
  1679. OUT PULONG pulActualBytesTransferred
  1680. )
  1681. /*++
  1682. Routine Description:
  1683. Arguments:
  1684. Return Value:
  1685. NTSTATUS
  1686. --*/
  1687. {
  1688. NTSTATUS Status = STATUS_SUCCESS;
  1689. GUID * pTimeFormatGuid;
  1690. KSMULTIPLE_ITEM * pMultipleItem;
  1691. PAGED_CODE();
  1692. *pulActualBytesTransferred = 0;
  1693. switch (pSPD->Property->Id) {
  1694. case KSPROPERTY_MEDIASEEKING_FORMATS:
  1695. // Its is KSMULTIPLE_ITEM so it is a two step process to return the data:
  1696. // (1) return size in pActualBytesTransferred with STATUS_BUFFER_OVERFLOW
  1697. // (2) 2nd time to get its actual data.
  1698. if(pSPD->PropertyOutputSize == 0) {
  1699. *pulActualBytesTransferred = sizeof(KSMULTIPLE_ITEM) + sizeof(GUID);
  1700. Status = STATUS_BUFFER_OVERFLOW;
  1701. } else if(pSPD->PropertyOutputSize >= (sizeof(KSMULTIPLE_ITEM) + sizeof(GUID))) {
  1702. pMultipleItem = (KSMULTIPLE_ITEM *) pSPD->PropertyInfo; // pointer to the data
  1703. pMultipleItem->Count = 1;
  1704. pMultipleItem->Size = sizeof(KSMULTIPLE_ITEM) + sizeof(GUID);
  1705. pTimeFormatGuid = (GUID *) (pMultipleItem + 1); // pointer to the data
  1706. memcpy(pTimeFormatGuid, &KSTIME_FORMAT_MEDIA_TIME, sizeof(GUID));
  1707. *pulActualBytesTransferred = sizeof(KSMULTIPLE_ITEM) + sizeof(GUID);
  1708. Status = STATUS_SUCCESS;
  1709. } else {
  1710. TRACE(TL_FCP_ERROR,("DVCRMediaSeekingProperty: KSPROPERTY_MEDIASEEKING_FORMAT; STATUS_INVALID_PARAMETER\n"));
  1711. Status = STATUS_INVALID_PARAMETER;
  1712. }
  1713. break;
  1714. default:
  1715. TRACE(TL_FCP_ERROR,("\'DVCRMediaSeekingProperty:Not supported ID %d\n", pSPD->Property->Id));
  1716. return STATUS_NOT_SUPPORTED;
  1717. }
  1718. return Status;
  1719. }
  1720. NTSTATUS
  1721. DVGetDeviceProperty(
  1722. IN PDVCR_EXTENSION pDevExt,
  1723. IN PSTREAM_PROPERTY_DESCRIPTOR pSPD,
  1724. IN PULONG pulActualBytesTransferred
  1725. )
  1726. /*++
  1727. Routine Description:
  1728. Handles Get operations for all adapter properties.
  1729. Arguments:
  1730. Return Value:
  1731. NTSTATUS
  1732. --*/
  1733. {
  1734. NTSTATUS Status;
  1735. PAGED_CODE();
  1736. if (IsEqualGUID (&PROPSETID_EXT_DEVICE, &pSPD->Property->Set)) {
  1737. Status =
  1738. DVGetExtDeviceProperty(
  1739. pDevExt,
  1740. pSPD,
  1741. pulActualBytesTransferred
  1742. );
  1743. }
  1744. else
  1745. if (IsEqualGUID (&PROPSETID_EXT_TRANSPORT, &pSPD->Property->Set)) {
  1746. Status =
  1747. DVGetExtTransportProperty(
  1748. pDevExt,
  1749. pSPD,
  1750. pulActualBytesTransferred
  1751. );
  1752. }
  1753. else
  1754. if (IsEqualGUID (&PROPSETID_TIMECODE_READER, &pSPD->Property->Set)) {
  1755. Status =
  1756. DVGetTimecodeReaderProperty(
  1757. pDevExt,
  1758. pSPD,
  1759. pulActualBytesTransferred
  1760. );
  1761. }
  1762. else
  1763. if (IsEqualGUID (&KSPROPSETID_MediaSeeking, &pSPD->Property->Set)) {
  1764. Status =
  1765. DVMediaSeekingProperty(
  1766. pDevExt,
  1767. pSPD,
  1768. pulActualBytesTransferred
  1769. );
  1770. } else {
  1771. //
  1772. // We should never get here
  1773. //
  1774. Status = STATUS_NOT_SUPPORTED;
  1775. TRACE(TL_FCP_ERROR,("get unknown property\n"));
  1776. ASSERT(FALSE);
  1777. }
  1778. return Status;
  1779. }
  1780. NTSTATUS
  1781. DVSetDeviceProperty(
  1782. IN PDVCR_EXTENSION pDevExt,
  1783. IN PSTREAM_PROPERTY_DESCRIPTOR pSPD,
  1784. IN PULONG pulActualBytetransferred
  1785. )
  1786. /*++
  1787. Routine Description:
  1788. Handles Set operations for all adapter properties.
  1789. Arguments:
  1790. Return Value:
  1791. NTSTATUS
  1792. --*/
  1793. {
  1794. NTSTATUS Status;
  1795. PAGED_CODE();
  1796. if (IsEqualGUID (&PROPSETID_EXT_DEVICE, &pSPD->Property->Set)) {
  1797. Status =
  1798. DVSetExtDeviceProperty(
  1799. pDevExt,
  1800. pSPD,
  1801. pulActualBytetransferred
  1802. );
  1803. }
  1804. else
  1805. if (IsEqualGUID (&PROPSETID_EXT_TRANSPORT, &pSPD->Property->Set)) {
  1806. Status =
  1807. DVSetExtTransportProperty(
  1808. pDevExt,
  1809. pSPD,
  1810. pulActualBytetransferred
  1811. );
  1812. }
  1813. else {
  1814. Status = STATUS_NOT_SUPPORTED;
  1815. //
  1816. // We should never get here
  1817. //
  1818. TRACE(TL_FCP_ERROR,("set unknown property\n"));
  1819. ASSERT(FALSE);
  1820. }
  1821. return Status;
  1822. }