3bd9aebff00436522e7f31c51a92bf1f9ff50e87
[reactos.git] / reactos / drivers / wdm / audio / hdaudbus / hdaudbus.cpp
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/hdaudbus/hdaudbus.cpp
5 * PURPOSE: HDA Driver Entry
6 * PROGRAMMER: Johannes Anderwald
7 */
8
9
10 #include "hdaudbus.h"
11
12
13 PVOID
14 AllocateItem(
15 IN POOL_TYPE PoolType,
16 IN SIZE_T NumberOfBytes)
17 {
18 PVOID Item = ExAllocatePoolWithTag(PoolType, NumberOfBytes, TAG_HDA);
19 if (!Item)
20 return Item;
21
22 RtlZeroMemory(Item, NumberOfBytes);
23 return Item;
24 }
25
26 VOID
27 FreeItem(
28 IN PVOID Item)
29 {
30 ExFreePool(Item);
31 }
32
33 BOOLEAN
34 NTAPI
35 HDA_InterruptService(
36 IN PKINTERRUPT Interrupt,
37 IN PVOID ServiceContext)
38 {
39 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
40 ULONG InterruptStatus, Response, ResponseFlags, Cad;
41 UCHAR RirbStatus, CorbStatus;
42 USHORT WritePos;
43 PHDA_CODEC_ENTRY Codec;
44
45 /* get device extension */
46 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)ServiceContext;
47
48 // Check if this interrupt is ours
49 InterruptStatus = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_INTR_STATUS));
50
51 DPRINT1("HDA_InterruptService %lx\n", InterruptStatus);
52 if ((InterruptStatus & INTR_STATUS_GLOBAL) == 0)
53 return FALSE;
54
55 // Controller or stream related?
56 if (InterruptStatus & INTR_STATUS_CONTROLLER) {
57 RirbStatus = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_STATUS);
58 CorbStatus = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_STATUS);
59
60 // Check for incoming responses
61 if (RirbStatus) {
62 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_STATUS, RirbStatus);
63
64 if ((RirbStatus & RIRB_STATUS_RESPONSE) != 0) {
65 WritePos = (READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_WRITE_POS)) + 1) % DeviceExtension->RirbLength;
66
67 for (; DeviceExtension->RirbReadPos != WritePos; DeviceExtension->RirbReadPos = (DeviceExtension->RirbReadPos + 1) % DeviceExtension->RirbLength)
68 {
69
70 Response = DeviceExtension->RirbBase[DeviceExtension->RirbReadPos].response;
71 ResponseFlags = DeviceExtension->RirbBase[DeviceExtension->RirbReadPos].flags;
72 Cad = ResponseFlags & RESPONSE_FLAGS_CODEC_MASK;
73 DPRINT1("Response %lx ResponseFlags %lx Cad %lx\n", Response, ResponseFlags, Cad);
74
75 /* get codec */
76 Codec = DeviceExtension->Codecs[Cad];
77 if (Codec == NULL)
78 {
79 DPRINT1("hda: response for unknown codec %x Response %x ResponseFlags %x\n", Cad, Response, ResponseFlags);
80 continue;
81 }
82
83 /* check response count */
84 if (Codec->ResponseCount >= MAX_CODEC_RESPONSES)
85 {
86 DPRINT1("too many responses for codec %x Response %x ResponseFlags %x\n", Cad, Response, ResponseFlags);
87 continue;
88 }
89
90 // FIXME handle unsolicited responses
91 ASSERT((ResponseFlags & RESPONSE_FLAGS_UNSOLICITED) == 0);
92
93 /* store response */
94 Codec->Responses[Codec->ResponseCount] = Response;
95 Codec->ResponseCount++;
96 }
97 }
98
99 if ((RirbStatus & RIRB_STATUS_OVERRUN) != 0)
100 DPRINT1("hda: RIRB Overflow\n");
101 }
102
103 // Check for sending errors
104 if (CorbStatus) {
105 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_STATUS, CorbStatus);
106
107 if ((CorbStatus & CORB_STATUS_MEMORY_ERROR) != 0)
108 DPRINT1("hda: CORB Memory Error!\n");
109 }
110 }
111 #if 0
112 if ((intrStatus & INTR_STATUS_STREAM_MASK) != 0) {
113 for (uint32 index = 0; index < HDA_MAX_STREAMS; index++) {
114 if ((intrStatus & (1 << index)) != 0) {
115 if (controller->streams[index]) {
116 if (stream_handle_interrupt(controller,
117 controller->streams[index], index)) {
118 handled = B_INVOKE_SCHEDULER;
119 }
120 }
121 else {
122 dprintf("hda: Stream interrupt for unconfigured stream "
123 "%ld!\n", index);
124 }
125 }
126 }
127 }
128 #endif
129 return TRUE;
130 }
131
132 VOID
133 HDA_SendVerbs(
134 IN PDEVICE_OBJECT DeviceObject,
135 IN PHDA_CODEC_ENTRY Codec,
136 IN PULONG Verbs,
137 OUT PULONG Responses,
138 IN ULONG Count)
139 {
140 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
141 ULONG Sent = 0, ReadPosition, WritePosition, Queued;
142
143 /* get device extension */
144 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
145
146 /* reset response count */
147 Codec->ResponseCount = 0;
148
149 while (Sent < Count) {
150 ReadPosition = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
151
152 Queued = 0;
153
154 while (Sent < Count) {
155 WritePosition = (DeviceExtension->CorbWritePos + 1) % DeviceExtension->CorbLength;
156
157 if (WritePosition == ReadPosition) {
158 // There is no space left in the ring buffer; execute the
159 // queued commands and wait until
160 break;
161 }
162
163 DeviceExtension->CorbBase[WritePosition] = Verbs[Sent++];
164 DeviceExtension->CorbWritePos = WritePosition;
165
166 // FIXME HACK
167 // do proper synchronization
168 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS), DeviceExtension->CorbWritePos);
169 KeStallExecutionProcessor(30);
170 Queued++;
171 }
172
173 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS), DeviceExtension->CorbWritePos);
174 }
175
176 if (Responses != NULL) {
177 memcpy(Responses, Codec->Responses, Codec->ResponseCount * sizeof(ULONG));
178 }
179 }
180
181 NTSTATUS
182 HDA_InitCodec(
183 IN PDEVICE_OBJECT DeviceObject,
184 IN ULONG codecAddress)
185 {
186 PHDA_CODEC_ENTRY Entry;
187 ULONG verbs[3];
188 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
189 CODEC_RESPONSE Response;
190 ULONG NodeId, GroupType;
191 NTSTATUS Status;
192 PHDA_CODEC_AUDIO_GROUP AudioGroup;
193 PHDA_PDO_DEVICE_EXTENSION ChildDeviceExtension;
194
195 /* lets allocate the entry */
196 Entry = (PHDA_CODEC_ENTRY)AllocateItem(NonPagedPool, sizeof(HDA_CODEC_ENTRY));
197 if (!Entry)
198 {
199 DPRINT1("hda: failed to allocate memory");
200 return STATUS_UNSUCCESSFUL;
201 }
202
203 /* init codec */
204 Entry->Addr = codecAddress;
205
206 /* get device extension */
207 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
208
209 /* store codec */
210 DeviceExtension->Codecs[codecAddress] = Entry;
211
212 verbs[0] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_VENDOR_ID);
213 verbs[1] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_REVISION_ID);
214 verbs[2] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_SUB_NODE_COUNT);
215
216 /* get basic info */
217 HDA_SendVerbs(DeviceObject, Entry, verbs, (PULONG)&Response, 3);
218
219 /* store codec details */
220 Entry->Major = Response.major;
221 Entry->Minor = Response.minor;
222 Entry->ProductId = Response.device;
223 Entry->Revision = Response.revision;
224 Entry->Stepping = Response.stepping;
225 Entry->VendorId = Response.vendor;
226
227 DPRINT1("hda Codec %ld Vendor: %04lx Product: %04lx, Revision: %lu.%lu.%lu.%lu NodeStart %u NodeCount %u \n", codecAddress, Response.vendor,
228 Response.device, Response.major, Response.minor, Response.revision, Response.stepping, Response.start, Response.count);
229
230 for (NodeId = Response.start; NodeId < Response.start + Response.count; NodeId++) {
231
232 /* get function type */
233 verbs[0] = MAKE_VERB(codecAddress, NodeId, VID_GET_PARAMETER, PID_FUNCTION_GROUP_TYPE);
234
235 HDA_SendVerbs(DeviceObject, Entry, verbs, &GroupType, 1);
236 DPRINT1("NodeId %u GroupType %x\n", NodeId, GroupType);
237
238 if ((GroupType & FUNCTION_GROUP_NODETYPE_MASK) == FUNCTION_GROUP_NODETYPE_AUDIO) {
239
240 AudioGroup = (PHDA_CODEC_AUDIO_GROUP)AllocateItem(NonPagedPool, sizeof(HDA_CODEC_AUDIO_GROUP));
241 if (!AudioGroup)
242 {
243 DPRINT1("hda: insufficient memory\n");
244 return STATUS_INSUFFICIENT_RESOURCES;
245 }
246
247 /* init audio group */
248 AudioGroup->NodeId = NodeId;
249 AudioGroup->FunctionGroup = FUNCTION_GROUP_NODETYPE_AUDIO;
250
251 // Found an Audio Function Group!
252 DPRINT1("NodeId %x found an audio function group!\n");
253
254 Status = IoCreateDevice(DeviceObject->DriverObject, sizeof(HDA_PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_SOUND, 0, FALSE, &AudioGroup->ChildPDO);
255 if (!NT_SUCCESS(Status))
256 {
257 FreeItem(AudioGroup);
258 DPRINT1("hda failed to create device object %x\n", Status);
259 return Status;
260 }
261
262 /* init child pdo*/
263 ChildDeviceExtension = (PHDA_PDO_DEVICE_EXTENSION)AudioGroup->ChildPDO->DeviceExtension;
264 ChildDeviceExtension->IsFDO = FALSE;
265 ChildDeviceExtension->Codec = Entry;
266 ChildDeviceExtension->AudioGroup = AudioGroup;
267
268 /* setup flags */
269 AudioGroup->ChildPDO->Flags |= DO_POWER_PAGABLE;
270 AudioGroup->ChildPDO->Flags &= ~DO_DEVICE_INITIALIZING;
271
272 /* add audio group*/
273 Entry->AudioGroups[Entry->AudioGroupCount] = AudioGroup;
274 Entry->AudioGroupCount++;
275 }
276 }
277 return STATUS_SUCCESS;
278
279 }
280
281 NTSTATUS
282 NTAPI
283 HDA_InitCorbRirbPos(
284 IN PDEVICE_OBJECT DeviceObject)
285 {
286 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
287 UCHAR corbSize, value, rirbSize;
288 PHYSICAL_ADDRESS HighestPhysicalAddress, CorbPhysicalAddress;
289 ULONG Index;
290 USHORT corbReadPointer, rirbWritePointer, interruptValue, corbControl, rirbControl;
291
292 /* get device extension */
293 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
294
295 // Determine and set size of CORB
296 corbSize = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE);
297 if ((corbSize & CORB_SIZE_CAP_256_ENTRIES) != 0) {
298 DeviceExtension->CorbLength = 256;
299
300 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE) & HDAC_CORB_SIZE_MASK;
301 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE, value | CORB_SIZE_256_ENTRIES);
302 }
303 else if (corbSize & CORB_SIZE_CAP_16_ENTRIES) {
304 DeviceExtension->CorbLength = 16;
305
306 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE) & HDAC_CORB_SIZE_MASK;
307 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE, value | CORB_SIZE_16_ENTRIES);
308 }
309 else if (corbSize & CORB_SIZE_CAP_2_ENTRIES) {
310 DeviceExtension->CorbLength = 2;
311
312 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE) & HDAC_CORB_SIZE_MASK;
313 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE, value | CORB_SIZE_2_ENTRIES);
314 }
315
316 // Determine and set size of RIRB
317 rirbSize = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE);
318 if (rirbSize & RIRB_SIZE_CAP_256_ENTRIES) {
319 DeviceExtension->RirbLength = 256;
320
321 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE) & HDAC_RIRB_SIZE_MASK;
322 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE, value | RIRB_SIZE_256_ENTRIES);
323 }
324 else if (rirbSize & RIRB_SIZE_CAP_16_ENTRIES) {
325 DeviceExtension->RirbLength = 16;
326
327 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE) & HDAC_RIRB_SIZE_MASK;
328 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE, value | RIRB_SIZE_16_ENTRIES);
329 }
330 else if (rirbSize & RIRB_SIZE_CAP_2_ENTRIES) {
331 DeviceExtension->RirbLength = 2;
332
333 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE) & HDAC_RIRB_SIZE_MASK;
334 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE, value | RIRB_SIZE_2_ENTRIES);
335 }
336
337 /* init corb */
338 HighestPhysicalAddress.QuadPart = 0x00000000FFFFFFFF;
339 DeviceExtension->CorbBase = (PULONG)MmAllocateContiguousMemory(PAGE_SIZE * 3, HighestPhysicalAddress);
340
341 // FIXME align rirb 128bytes
342 ASSERT(DeviceExtension->CorbLength == 256);
343 ASSERT(DeviceExtension->RirbLength == 256);
344
345 CorbPhysicalAddress = MmGetPhysicalAddress(DeviceExtension->CorbBase);
346
347 // Program CORB/RIRB for these locations
348 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_CORB_BASE_LOWER), CorbPhysicalAddress.LowPart);
349 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_CORB_BASE_UPPER), CorbPhysicalAddress.HighPart);
350
351 DeviceExtension->RirbBase = (PRIRB_RESPONSE)((ULONG_PTR)DeviceExtension->CorbBase + PAGE_SIZE);
352 CorbPhysicalAddress.QuadPart += PAGE_SIZE;
353 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_RIRB_BASE_LOWER), CorbPhysicalAddress.LowPart);
354 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_RIRB_BASE_UPPER), CorbPhysicalAddress.HighPart);
355
356 // Program DMA position update
357 DeviceExtension->StreamPositions = (PVOID)((ULONG_PTR)DeviceExtension->RirbBase + PAGE_SIZE);
358 CorbPhysicalAddress.QuadPart += PAGE_SIZE;
359 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_LOWER), CorbPhysicalAddress.LowPart);
360 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_UPPER), CorbPhysicalAddress.HighPart);
361
362 value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS)) & HDAC_CORB_WRITE_POS_MASK;
363 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS), value);
364
365 // Reset CORB read pointer. Preseve bits marked as RsvdP.
366 // After setting the reset bit, we must wait for the hardware
367 // to acknowledge it, then manually unset it and wait for that
368 // to be acknowledged as well.
369 corbReadPointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
370
371 corbReadPointer |= CORB_READ_POS_RESET;
372 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS), corbReadPointer);
373
374 for (Index = 0; Index < 100; Index++) {
375 KeStallExecutionProcessor(10);
376 corbReadPointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
377 if ((corbReadPointer & CORB_READ_POS_RESET) != 0)
378 break;
379 }
380 if ((corbReadPointer & CORB_READ_POS_RESET) == 0) {
381 DPRINT1("hda: CORB read pointer reset not acknowledged\n");
382
383 // According to HDA spec v1.0a ch3.3.21, software must read the
384 // bit as 1 to verify that the reset completed. However, at least
385 // some nVidia HDA controllers do not update the bit after reset.
386 // Thus don't fail here on nVidia controllers.
387 //if (controller->pci_info.vendor_id != PCI_VENDOR_NVIDIA)
388 // return B_BUSY;
389 }
390
391 corbReadPointer &= ~CORB_READ_POS_RESET;
392 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS), corbReadPointer);
393 for (Index = 0; Index < 10; Index++) {
394 KeStallExecutionProcessor(10);
395 corbReadPointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
396 if ((corbReadPointer & CORB_READ_POS_RESET) == 0)
397 break;
398 }
399 if ((corbReadPointer & CORB_READ_POS_RESET) != 0) {
400 DPRINT1("hda: CORB read pointer reset failed\n");
401 return STATUS_UNSUCCESSFUL;
402 }
403
404 // Reset RIRB write pointer
405 rirbWritePointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_WRITE_POS)) & RIRB_WRITE_POS_RESET;
406 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_WRITE_POS), rirbWritePointer | RIRB_WRITE_POS_RESET);
407
408 // Generate interrupt for every response
409 interruptValue = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RESPONSE_INTR_COUNT)) & HDAC_RESPONSE_INTR_COUNT_MASK;
410 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RESPONSE_INTR_COUNT), interruptValue | 1);
411
412 // Setup cached read/write indices
413 DeviceExtension->RirbReadPos = 1;
414 DeviceExtension->CorbWritePos = 0;
415
416 // Gentlemen, start your engines...
417 corbControl = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_CONTROL)) &HDAC_CORB_CONTROL_MASK;
418 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_CONTROL), corbControl | CORB_CONTROL_RUN | CORB_CONTROL_MEMORY_ERROR_INTR);
419
420 rirbControl = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_CONTROL)) & HDAC_RIRB_CONTROL_MASK;
421 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_CONTROL), rirbControl | RIRB_CONTROL_DMA_ENABLE | RIRB_CONTROL_OVERRUN_INTR | RIRB_CONTROL_RESPONSE_INTR);
422
423 return STATUS_SUCCESS;
424 }
425
426 NTSTATUS
427 NTAPI
428 HDA_ResetController(
429 IN PDEVICE_OBJECT DeviceObject)
430 {
431 USHORT ValCapabilities;
432 ULONG Index;
433 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
434 ULONG InputStreams, OutputStreams, BiDirStreams, Control;
435 UCHAR corbControl, rirbControl;
436
437 /* get device extension */
438 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
439
440 /* read caps */
441 ValCapabilities = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_GLOBAL_CAP));
442
443 InputStreams = GLOBAL_CAP_INPUT_STREAMS(ValCapabilities);
444 OutputStreams = GLOBAL_CAP_OUTPUT_STREAMS(ValCapabilities);
445 BiDirStreams = GLOBAL_CAP_BIDIR_STREAMS(ValCapabilities);
446
447 DPRINT1("NumInputStreams %u\n", InputStreams);
448 DPRINT1("NumOutputStreams %u\n", OutputStreams);
449 DPRINT1("NumBiDirStreams %u\n", BiDirStreams);
450
451 /* stop all streams */
452 for (Index = 0; Index < InputStreams; Index++)
453 {
454 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE + HDAC_INPUT_STREAM_OFFSET(Index), 0);
455 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_STATUS + HDAC_STREAM_BASE + HDAC_INPUT_STREAM_OFFSET(Index), 0);
456 }
457
458 for (Index = 0; Index < OutputStreams; Index++) {
459 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE + HDAC_OUTPUT_STREAM_OFFSET(InputStreams, Index), 0);
460 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_STATUS + HDAC_STREAM_BASE + HDAC_OUTPUT_STREAM_OFFSET(InputStreams, Index), 0);
461 }
462
463 for (Index = 0; Index < BiDirStreams; Index++) {
464 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE + HDAC_BIDIR_STREAM_OFFSET(InputStreams, OutputStreams, Index), 0);
465 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_STATUS + HDAC_STREAM_BASE + HDAC_BIDIR_STREAM_OFFSET(InputStreams, OutputStreams, Index), 0);
466 }
467
468 // stop DMA
469 Control = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL) & HDAC_CORB_CONTROL_MASK;
470 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL, Control);
471
472 Control = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL) & HDAC_RIRB_CONTROL_MASK;
473 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL, Control);
474
475 for (int timeout = 0; timeout < 10; timeout++) {
476 KeStallExecutionProcessor(10);
477
478 corbControl = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL);
479 rirbControl = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL);
480 if (corbControl == 0 && rirbControl == 0)
481 break;
482 }
483 if (corbControl != 0 || rirbControl != 0) {
484 DPRINT1("hda: unable to stop dma\n");
485 return STATUS_UNSUCCESSFUL;
486 }
487
488 // reset DMA position buffer
489 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_LOWER), 0);
490 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_UPPER), 0);
491
492 // Set reset bit - it must be asserted for at least 100us
493 Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
494 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL), Control & ~GLOBAL_CONTROL_RESET);
495
496 for (int timeout = 0; timeout < 10; timeout++) {
497 KeStallExecutionProcessor(10);
498
499 Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
500 if ((Control & GLOBAL_CONTROL_RESET) == 0)
501 break;
502 }
503 if ((Control & GLOBAL_CONTROL_RESET) != 0)
504 {
505 DPRINT1("hda: unable to reset controller\n");
506 return STATUS_UNSUCCESSFUL;
507 }
508
509 // Unset reset bit
510 Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
511 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL), Control | GLOBAL_CONTROL_RESET);
512
513 for (int timeout = 0; timeout < 10; timeout++) {
514 KeStallExecutionProcessor(10);
515
516 Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
517 if ((Control & GLOBAL_CONTROL_RESET) != 0)
518 break;
519 }
520 if ((Control & GLOBAL_CONTROL_RESET) == 0) {
521 DPRINT1("hda: unable to exit reset\n");
522 return STATUS_UNSUCCESSFUL;
523 }
524
525 // Wait for codecs to finish their own reset (apparently needs more
526 // time than documented in the specs)
527 KeStallExecutionProcessor(100);
528
529 // Enable unsolicited responses
530 Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
531 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL), Control | GLOBAL_CONTROL_UNSOLICITED);
532
533 return STATUS_SUCCESS;
534 }
535
536 NTSTATUS
537 NTAPI
538 HDA_QueryId(
539 IN PDEVICE_OBJECT DeviceObject,
540 IN PIRP Irp)
541 {
542 PIO_STACK_LOCATION IoStack;
543 WCHAR DeviceName[200];
544 PHDA_PDO_DEVICE_EXTENSION DeviceExtension;
545 ULONG Length;
546 LPWSTR Device;
547
548 /* get device extension */
549 DeviceExtension = (PHDA_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
550 ASSERT(DeviceExtension->IsFDO == FALSE);
551
552 /* get current irp stack location */
553 IoStack = IoGetCurrentIrpStackLocation(Irp);
554
555 if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID)
556 {
557 UNIMPLEMENTED;
558
559 // FIXME
560 swprintf(DeviceName, L"%08x", 1);
561 Length = wcslen(DeviceName) + 20;
562
563 /* allocate result buffer*/
564 Device = (LPWSTR)AllocateItem(PagedPool, Length * sizeof(WCHAR));
565 if (!Device)
566 return STATUS_INSUFFICIENT_RESOURCES;
567
568 swprintf(Device, L"%08x", 1);
569
570 DPRINT1("ID: %S\n", Device);
571 /* store result */
572 Irp->IoStatus.Information = (ULONG_PTR)Device;
573 return STATUS_SUCCESS;
574 }
575 else if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID ||
576 IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
577 {
578
579 /* calculate size */
580 swprintf(DeviceName, L"HDAUDIO\\FUNC_%02X&VEN_%04X&DEV_%04X&SUBSYS_%08X", DeviceExtension->AudioGroup->FunctionGroup, DeviceExtension->Codec->VendorId, DeviceExtension->Codec->ProductId, DeviceExtension->Codec->VendorId << 16 | DeviceExtension->Codec->ProductId);
581 Length = wcslen(DeviceName) + 20;
582
583 /* allocate result buffer*/
584 Device = (LPWSTR)AllocateItem(PagedPool, Length * sizeof(WCHAR));
585 if (!Device)
586 return STATUS_INSUFFICIENT_RESOURCES;
587
588 swprintf(Device, L"HDAUDIO\\FUNC_%02X&VEN_%04X&DEV_%04X&SUBSYS_%08X", DeviceExtension->AudioGroup->FunctionGroup, DeviceExtension->Codec->VendorId, DeviceExtension->Codec->ProductId, DeviceExtension->Codec->VendorId << 16 | DeviceExtension->Codec->ProductId);
589
590 DPRINT1("ID: %S\n", Device);
591 /* store result */
592 Irp->IoStatus.Information = (ULONG_PTR)Device;
593 return STATUS_SUCCESS;
594 }
595 else
596 {
597 DPRINT1("QueryID Type %x not implemented\n", IoStack->Parameters.QueryId.IdType);
598 return Irp->IoStatus.Status;
599 }
600 return STATUS_NOT_IMPLEMENTED;
601 }
602
603 NTSTATUS
604 NTAPI
605 HDA_StartDevice(
606 IN PDEVICE_OBJECT DeviceObject,
607 IN PIRP Irp)
608 {
609 PIO_STACK_LOCATION IoStack;
610 NTSTATUS Status = STATUS_SUCCESS;
611 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
612 PCM_RESOURCE_LIST Resources;
613 ULONG Index;
614 USHORT Value;
615
616 /* get current irp stack location */
617 IoStack = IoGetCurrentIrpStackLocation(Irp);
618
619 /* get device extension */
620 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
621 ASSERT(DeviceExtension->IsFDO == TRUE);
622
623 Resources = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated;
624 for (Index = 0; Index < Resources->List[0].PartialResourceList.Count; Index++)
625 {
626 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor = &Resources->List[0].PartialResourceList.PartialDescriptors[Index];
627
628 if (Descriptor->Type == CmResourceTypeMemory)
629 {
630 DeviceExtension->RegBase = (PUCHAR)MmMapIoSpace(Descriptor->u.Memory.Start, Descriptor->u.Memory.Length, MmNonCached);
631 if (DeviceExtension->RegBase == NULL)
632 {
633 DPRINT1("[HDAB] Failed to map registers\n");
634 Status = STATUS_UNSUCCESSFUL;
635 break;
636 }
637 }
638 else if (Descriptor->Type == CmResourceTypeInterrupt)
639 {
640 Status = IoConnectInterrupt(&DeviceExtension->Interrupt,
641 HDA_InterruptService,
642 (PVOID)DeviceExtension,
643 NULL,
644 Descriptor->u.Interrupt.Vector,
645 Descriptor->u.Interrupt.Level,
646 Descriptor->u.Interrupt.Level,
647 (KINTERRUPT_MODE)(Descriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED),
648 (Descriptor->ShareDisposition != CmResourceShareDeviceExclusive),
649 Descriptor->u.Interrupt.Affinity,
650 FALSE);
651 if (!NT_SUCCESS(Status))
652 {
653 DPRINT1("[HDAB] Failed to connect interrupt\n");
654 break;
655 }
656
657 }
658 }
659
660 if (NT_SUCCESS(Status))
661 {
662 // Get controller into valid state
663 Status = HDA_ResetController(DeviceObject);
664 if (!NT_SUCCESS(Status)) return Status;
665
666 // Setup CORB/RIRB/DMA POS
667 Status = HDA_InitCorbRirbPos(DeviceObject);
668 if (!NT_SUCCESS(Status)) return Status;
669
670
671 // Don't enable codec state change interrupts. We don't handle
672 // them, as we want to use the STATE_STATUS register to identify
673 // available codecs. We'd have to clear that register in the interrupt
674 // handler to 'ack' the codec change.
675 Value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_WAKE_ENABLE)) & HDAC_WAKE_ENABLE_MASK;
676 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_WAKE_ENABLE), Value);
677
678 // Enable controller interrupts
679 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_INTR_CONTROL), INTR_CONTROL_GLOBAL_ENABLE | INTR_CONTROL_CONTROLLER_ENABLE);
680
681 KeStallExecutionProcessor(100);
682
683 Value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_STATE_STATUS));
684 if (!Value) {
685 DPRINT1("hda: bad codec status\n");
686 return STATUS_UNSUCCESSFUL;
687 }
688 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_STATE_STATUS), Value);
689
690 // Create codecs
691 DPRINT1("Codecs %lx\n", Value);
692 for (Index = 0; Index < HDA_MAX_CODECS; Index++) {
693 if ((Value & (1 << Index)) != 0) {
694 HDA_InitCodec(DeviceObject, Index);
695 }
696 }
697 }
698
699 return Status;
700 }
701
702 NTSTATUS
703 NTAPI
704 HDA_QueryBusRelations(
705 IN PDEVICE_OBJECT DeviceObject,
706 IN PIRP Irp)
707 {
708 ULONG DeviceCount, CodecIndex, AFGIndex;
709 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
710 PHDA_CODEC_ENTRY Codec;
711 PDEVICE_RELATIONS DeviceRelations;
712
713 /* get device extension */
714 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
715 ASSERT(DeviceExtension->IsFDO == TRUE);
716
717 DeviceCount = 0;
718 for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
719 {
720 if (DeviceExtension->Codecs[CodecIndex] == NULL)
721 continue;
722
723 Codec = DeviceExtension->Codecs[CodecIndex];
724 DeviceCount += Codec->AudioGroupCount;
725 }
726
727 if (DeviceCount == 0)
728 return STATUS_UNSUCCESSFUL;
729
730 DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(NonPagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount > 1 ? sizeof(PDEVICE_OBJECT) * (DeviceCount - 1) : 0));
731 if (!DeviceRelations)
732 return STATUS_INSUFFICIENT_RESOURCES;
733
734 DeviceCount = 0;
735 for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
736 {
737 if (DeviceExtension->Codecs[CodecIndex] == NULL)
738 continue;
739
740 Codec = DeviceExtension->Codecs[CodecIndex];
741 for (AFGIndex = 0; AFGIndex < Codec->AudioGroupCount; AFGIndex++)
742 {
743 DeviceRelations->Objects[DeviceRelations->Count] = Codec->AudioGroups[AFGIndex]->ChildPDO;
744 ObReferenceObject(Codec->AudioGroups[AFGIndex]->ChildPDO);
745 DeviceRelations->Count++;
746 }
747 }
748
749 /* FIXME handle existing device relations */
750 ASSERT(Irp->IoStatus.Information == 0);
751
752 /* store device relations */
753 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
754
755 /* done */
756 return STATUS_SUCCESS;
757 }
758
759 NTSTATUS
760 HDA_QueryBusInformation(
761 IN PIRP Irp)
762 {
763 PPNP_BUS_INFORMATION BusInformation;
764
765 /* allocate bus information */
766 BusInformation = (PPNP_BUS_INFORMATION)AllocateItem(PagedPool, sizeof(PNP_BUS_INFORMATION));
767
768 if (!BusInformation)
769 {
770 /* no memory */
771 return STATUS_INSUFFICIENT_RESOURCES;
772 }
773
774 /* return info */
775 BusInformation->BusNumber = 0;
776 BusInformation->LegacyBusType = PCIBus;
777 RtlMoveMemory(&BusInformation->BusTypeGuid, &GUID_HDAUDIO_BUS_INTERFACE, sizeof(GUID));
778
779 /* store result */
780 Irp->IoStatus.Information = (ULONG_PTR)BusInformation;
781
782 /* done */
783 return STATUS_SUCCESS;
784 }
785
786 NTSTATUS
787 HDA_QueryBusDeviceCapabilities(
788 IN PIRP Irp)
789 {
790 PDEVICE_CAPABILITIES Capabilities;
791 PIO_STACK_LOCATION IoStack;
792
793 /* get stack location */
794 IoStack = IoGetCurrentIrpStackLocation(Irp);
795
796 /* get capabilities */
797 Capabilities = IoStack->Parameters.DeviceCapabilities.Capabilities;
798
799 RtlZeroMemory(Capabilities, sizeof(DEVICE_CAPABILITIES));
800
801 /* setup capabilities */
802 Capabilities->UniqueID = TRUE;
803 Capabilities->SilentInstall = TRUE;
804 Capabilities->SurpriseRemovalOK = TRUE;
805 Capabilities->Address = 0;
806 Capabilities->UINumber = 0;
807 Capabilities->SystemWake = PowerSystemWorking; /* FIXME common device extension */
808 Capabilities->DeviceWake = PowerDeviceD0;
809
810 /* done */
811 return STATUS_SUCCESS;
812 }
813
814 NTSTATUS
815 HDA_QueryBusDevicePnpState(
816 IN PIRP Irp)
817 {
818 /* set device flags */
819 Irp->IoStatus.Information = PNP_DEVICE_DONT_DISPLAY_IN_UI | PNP_DEVICE_NOT_DISABLEABLE;
820
821 /* done */
822 return STATUS_SUCCESS;
823 }
824
825 NTSTATUS
826 HDA_PdoHandleQueryDeviceText(
827 IN PIRP Irp)
828 {
829 PIO_STACK_LOCATION IoStack;
830 LPWSTR Buffer;
831 static WCHAR DeviceText[] = L"Audio Device on High Definition Audio Bus";
832
833 IoStack = IoGetCurrentIrpStackLocation(Irp);
834 if (IoStack->Parameters.QueryDeviceText.DeviceTextType == DeviceTextDescription)
835 {
836 DPRINT("HDA_PdoHandleQueryDeviceText DeviceTextDescription\n");
837
838 Buffer = (LPWSTR)AllocateItem(PagedPool, sizeof(DeviceText));
839 if (!Buffer)
840 {
841 Irp->IoStatus.Information = 0;
842 return STATUS_INSUFFICIENT_RESOURCES;
843 }
844
845 wcscpy(Buffer, DeviceText);
846
847 Irp->IoStatus.Information = (ULONG_PTR)Buffer;
848 return STATUS_SUCCESS;
849 }
850 else
851 {
852 DPRINT("HDA_PdoHandleQueryDeviceText DeviceTextLocationInformation\n");
853
854 Buffer = (LPWSTR)AllocateItem(PagedPool, sizeof(DeviceText));
855 if (!Buffer)
856 {
857 Irp->IoStatus.Information = 0;
858 return STATUS_INSUFFICIENT_RESOURCES;
859 }
860
861 wcscpy(Buffer, DeviceText);
862
863 /* save result */
864 Irp->IoStatus.Information = (ULONG_PTR)Buffer;
865 return STATUS_SUCCESS;
866 }
867
868 }
869
870 NTSTATUS
871 NTAPI
872 HDA_Pnp(
873 IN PDEVICE_OBJECT DeviceObject,
874 IN PIRP Irp)
875 {
876 NTSTATUS Status = STATUS_NOT_SUPPORTED;
877 PIO_STACK_LOCATION IoStack;
878 PDEVICE_RELATIONS DeviceRelation;
879 PHDA_FDO_DEVICE_EXTENSION FDODeviceExtension;
880 //PHDA_PDO_DEVICE_EXTENSION ChildDeviceExtension;
881
882 FDODeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
883 //ChildDeviceExtension = (PHDA_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
884
885 IoStack = IoGetCurrentIrpStackLocation(Irp);
886 DPRINT1("HDA_Pnp Minor: %u IsFDO%d\n", IoStack->MinorFunction, FDODeviceExtension->IsFDO);
887
888 if (FDODeviceExtension->IsFDO)
889 {
890 if (IoStack->MinorFunction == IRP_MN_START_DEVICE)
891 {
892 DPRINT1("IRP_MN_START_DEVICE\n");
893 Status = HDA_StartDevice(DeviceObject, Irp);
894 }
895 else if (IoStack->MinorFunction == IRP_MN_QUERY_DEVICE_RELATIONS)
896 {
897 DPRINT1("IRP_MN_QUERY_DEVICE_RELATIONS\n");
898 /* handle bus device relations */
899 if (IoStack->Parameters.QueryDeviceRelations.Type == BusRelations)
900 {
901 Status = HDA_QueryBusRelations(DeviceObject, Irp);
902 }
903 else
904 {
905 Status = Irp->IoStatus.Status;
906 }
907 }
908 else
909 {
910 /* get default status */
911 Status = Irp->IoStatus.Status;
912 }
913 }
914 else
915 {
916 if (IoStack->MinorFunction == IRP_MN_START_DEVICE)
917 {
918 DPRINT1("IRP_MN_START_DEVICE\n");
919 /* no op for pdo */
920 Status = STATUS_SUCCESS;
921 }
922 else if (IoStack->MinorFunction == IRP_MN_QUERY_BUS_INFORMATION)
923 {
924 DPRINT1("IRP_MN_QUERY_BUS_INFORMATION\n");
925 /* query bus information */
926 Status = HDA_QueryBusInformation(Irp);
927 }
928 else if (IoStack->MinorFunction == IRP_MN_QUERY_PNP_DEVICE_STATE)
929 {
930 DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE\n");
931 /* query pnp state */
932 Status = HDA_QueryBusDevicePnpState(Irp);
933 }
934 else if (IoStack->MinorFunction == IRP_MN_QUERY_DEVICE_RELATIONS)
935 {
936 DPRINT1("IRP_MN_QUERY_DEVICE_RELATIONS\n");
937 if (IoStack->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation)
938 {
939 /* handle target device relations */
940 ASSERT(IoStack->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation);
941 ASSERT(Irp->IoStatus.Information == 0);
942
943 /* allocate device relation */
944 DeviceRelation = (PDEVICE_RELATIONS)AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS));
945 if (DeviceRelation)
946 {
947 DeviceRelation->Count = 1;
948 DeviceRelation->Objects[0] = DeviceObject;
949
950 /* reference self */
951 ObReferenceObject(DeviceObject);
952
953 /* store result */
954 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelation;
955
956 /* done */
957 Status = STATUS_SUCCESS;
958 }
959 else
960 {
961 /* no memory */
962 Status = STATUS_INSUFFICIENT_RESOURCES;
963 }
964 }
965 }
966 else if (IoStack->MinorFunction == IRP_MN_QUERY_CAPABILITIES)
967 {
968 DPRINT1("IRP_MN_QUERY_CAPABILITIES\n");
969 /* query capabilities */
970 Status = HDA_QueryBusDeviceCapabilities(Irp);
971 }
972 else if (IoStack->MinorFunction == IRP_MN_QUERY_RESOURCE_REQUIREMENTS)
973 {
974 DPRINT1("IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
975 /* no op */
976 Status = STATUS_SUCCESS;
977 }
978 else if (IoStack->MinorFunction == IRP_MN_QUERY_ID)
979 {
980 DPRINT1("IRP_MN_QUERY_ID\n");
981 Status = HDA_QueryId(DeviceObject, Irp);
982 }
983 else if (IoStack->MinorFunction == IRP_MN_QUERY_DEVICE_TEXT)
984 {
985 DPRINT1("IRP_MN_QUERY_DEVICE_TEXT\n");
986 Status = HDA_PdoHandleQueryDeviceText(Irp);
987 }
988 else
989 {
990 /* get default status */
991 Status = Irp->IoStatus.Status;
992 }
993 }
994
995 Irp->IoStatus.Status = Status;
996 IoCompleteRequest(Irp, IO_NO_INCREMENT);
997
998
999 return Status;
1000 }
1001
1002
1003 //PDRIVER_ADD_DEVICE HDA_AddDevice;
1004
1005 NTSTATUS
1006 NTAPI
1007 HDA_AddDevice(
1008 IN PDRIVER_OBJECT DriverObject,
1009 IN PDEVICE_OBJECT PhysicalDeviceObject)
1010 {
1011 PDEVICE_OBJECT DeviceObject;
1012 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
1013 NTSTATUS Status;
1014
1015 /* create device object */
1016 Status = IoCreateDevice(DriverObject, sizeof(HDA_FDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_BUS_EXTENDER, 0, FALSE, &DeviceObject);
1017 if (!NT_SUCCESS(Status))
1018 {
1019 /* failed */
1020 return Status;
1021 }
1022
1023 /* get device extension*/
1024 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1025
1026 /* init device extension*/
1027 DeviceExtension->IsFDO = TRUE;
1028 DeviceExtension->LowerDevice = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject);
1029 RtlZeroMemory(DeviceExtension->Codecs, sizeof(PHDA_CODEC_ENTRY) * (HDA_MAX_CODECS + 1));
1030
1031
1032 /* set device flags */
1033 DeviceObject->Flags |= DO_POWER_PAGABLE;
1034
1035 return Status;
1036 }
1037 extern "C"
1038 {
1039 NTSTATUS
1040 NTAPI
1041 DriverEntry(
1042 IN PDRIVER_OBJECT DriverObject,
1043 IN PUNICODE_STRING RegistryPathName)
1044 {
1045 DriverObject->DriverExtension->AddDevice = HDA_AddDevice;
1046 DriverObject->MajorFunction[IRP_MJ_PNP] = HDA_Pnp;
1047
1048 return STATUS_SUCCESS;
1049 }
1050
1051 }