[ACPI]
[reactos.git] / reactos / drivers / bus / isapnp / isapnp.c
1 /* $Id$
2 *
3 * PROJECT: ReactOS ISA PnP Bus driver
4 * FILE: isapnp.c
5 * PURPOSE: Driver entry
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * NOTE: Parts adapted from linux ISA PnP driver
8 * UPDATE HISTORY:
9 * 01-05-2001 CSH Created
10 */
11 #include <isapnp.h>
12
13 #ifndef NDEBUG
14 #define NDEBUG
15 #endif
16 #include <debug.h>
17
18
19 #ifdef ALLOC_PRAGMA
20
21 // Make the initialization routines discardable, so that they
22 // don't waste space
23
24 #pragma alloc_text(init, DriverEntry)
25
26
27 #endif /* ALLOC_PRAGMA */
28
29
30 PUCHAR IsaPnPReadPort;
31
32
33 #define UCHAR2USHORT(v0, v1) \
34 ((v1 << 8) | v0)
35
36 #define UCHAR2ULONG(v0, v1, v2, v3) \
37 ((UCHAR2USHORT(v2, v3) << 16) | UCHAR2USHORT(v0, v1))
38
39
40 #ifndef NDEBUG
41
42 struct
43 {
44 PCH Name;
45 } SmallTags[] = {
46 {"Unknown Small Tag"},
47 {"ISAPNP_SRIN_VERSION"},
48 {"ISAPNP_SRIN_LDEVICE_ID"},
49 {"ISAPNP_SRIN_CDEVICE_ID"},
50 {"ISAPNP_SRIN_IRQ_FORMAT"},
51 {"ISAPNP_SRIN_DMA_FORMAT"},
52 {"ISAPNP_SRIN_START_DFUNCTION"},
53 {"ISAPNP_SRIN_END_DFUNCTION"},
54 {"ISAPNP_SRIN_IO_DESCRIPTOR"},
55 {"ISAPNP_SRIN_FL_IO_DESCRIPOTOR"},
56 {"Reserved Small Tag"},
57 {"Reserved Small Tag"},
58 {"Reserved Small Tag"},
59 {"Reserved Small Tag"},
60 {"ISAPNP_SRIN_VENDOR_DEFINED"},
61 {"ISAPNP_SRIN_END_TAG"}
62 };
63
64 struct
65 {
66 PCH Name;
67 } LargeTags[] = {
68 {"Unknown Large Tag"},
69 {"ISAPNP_LRIN_MEMORY_RANGE"},
70 {"ISAPNP_LRIN_ID_STRING_ANSI"},
71 {"ISAPNP_LRIN_ID_STRING_UNICODE"},
72 {"ISAPNP_LRIN_VENDOR_DEFINED"},
73 {"ISAPNP_LRIN_MEMORY_RANGE32"},
74 {"ISAPNP_LRIN_FL_MEMORY_RANGE32"}
75 };
76
77 PCSZ TagName(ULONG Tag, BOOLEAN Small)
78 {
79 if (Small && (Tag <= ISAPNP_SRIN_END_TAG)) {
80 return SmallTags[Tag].Name;
81 } else if (Tag <= ISAPNP_LRIN_FL_MEMORY_RANGE32){
82 return LargeTags[Tag].Name;
83 }
84
85 return NULL;
86 }
87
88 #endif
89
90 static __inline VOID WriteData(UCHAR Value)
91 {
92 WRITE_PORT_UCHAR((PUCHAR)ISAPNP_WRITE_PORT, Value);
93 }
94
95 static __inline VOID WriteAddress(UCHAR Value)
96 {
97 WRITE_PORT_UCHAR((PUCHAR)ISAPNP_ADDRESS_PORT, Value);
98 KeStallExecutionProcessor(20);
99 }
100
101 static __inline UCHAR ReadData(VOID)
102 {
103 return READ_PORT_UCHAR(IsaPnPReadPort);
104 }
105
106 static UCHAR ReadUchar(UCHAR Index)
107 {
108 WriteAddress(Index);
109 return ReadData();
110 }
111
112 #if 0
113 static USHORT ReadUshort(UCHAR Index)
114 {
115 USHORT Value;
116
117 Value = ReadUchar(Index);
118 Value = (Value << 8) + ReadUchar(Index + 1);
119 return Value;
120 }
121
122 static ULONG ReadUlong(UCHAR Index)
123 {
124 ULONG Value;
125
126 Value = ReadUchar(Index);
127 Value = (Value << 8) + ReadUchar(Index + 1);
128 Value = (Value << 8) + ReadUchar(Index + 2);
129 Value = (Value << 8) + ReadUchar(Index + 3);
130 return Value;
131 }
132 #endif
133
134 static VOID WriteUchar(UCHAR Index, UCHAR Value)
135 {
136 WriteAddress(Index);
137 WriteData(Value);
138 }
139
140 #if 0
141 static VOID WriteUshort(UCHAR Index, USHORT Value)
142 {
143 WriteUchar(Index, Value >> 8);
144 WriteUchar(Index + 1, Value);
145 }
146
147 static VOID WriteUlong(UCHAR Index, ULONG Value)
148 {
149 WriteUchar(Index, Value >> 24);
150 WriteUchar(Index + 1, Value >> 16);
151 WriteUchar(Index + 2, Value >> 8);
152 WriteUchar(Index + 3, Value);
153 }
154 #endif
155
156 static __inline VOID SetReadDataPort(ULONG Port)
157 {
158 IsaPnPReadPort = (PUCHAR)Port;
159 WriteUchar(0x00, (UCHAR) (Port >> 2));
160 KeStallExecutionProcessor(100);
161 }
162
163 static VOID SendKey(VOID)
164 {
165 ULONG i;
166 UCHAR msb;
167 UCHAR code;
168
169 /* FIXME: Is there something better? */
170 KeStallExecutionProcessor(1000);
171 WriteAddress(0x00);
172 WriteAddress(0x00);
173
174 code = 0x6a;
175 WriteAddress(code);
176 for (i = 1; i < 32; i++) {
177 msb = ((code & 0x01) ^ ((code & 0x02) >> 1)) << 7;
178 code = (code >> 1) | msb;
179 WriteAddress(code);
180 }
181 }
182
183 /* Place all PnP cards in wait-for-key state */
184 static VOID SendWait(VOID)
185 {
186 WriteUchar(0x02, 0x02);
187 }
188
189 static VOID SendWake(UCHAR csn)
190 {
191 WriteUchar(ISAPNP_CARD_WAKECSN, csn);
192 }
193
194 #if 0
195 static VOID SelectLogicalDevice(UCHAR LogicalDevice)
196 {
197 WriteUchar(ISAPNP_CARD_LOG_DEVICE_NUM, LogicalDevice);
198 }
199
200 static VOID ActivateLogicalDevice(UCHAR LogicalDevice)
201 {
202 SelectLogicalDevice(LogicalDevice);
203 WriteUchar(ISAPNP_CONTROL_ACTIVATE, 0x1);
204 KeStallExecutionProcessor(250);
205 }
206
207 static VOID DeactivateLogicalDevice(UCHAR LogicalDevice)
208 {
209 SelectLogicalDevice(LogicalDevice);
210 WriteUchar(ISAPNP_CONTROL_ACTIVATE, 0x0);
211 KeStallExecutionProcessor(500);
212 }
213 #endif
214
215 #define READ_DATA_PORT_STEP 32 /* Minimum is 4 */
216
217 static ULONG FindNextReadPort(VOID)
218 {
219 ULONG Port;
220
221
222
223 Port = (ULONG)IsaPnPReadPort;
224
225 while (TRUE) {
226
227 Port += READ_DATA_PORT_STEP;
228
229
230
231 if (Port > ISAPNP_MAX_READ_PORT)
232
233 {
234
235 return 0;
236
237 }
238
239
240
241 /*
242
243 * We cannot use NE2000 probe spaces for
244
245 * ISAPnP or we will lock up machines
246
247 */
248
249 if ((Port < 0x280) || (Port > 0x380))
250
251 {
252
253 return Port;
254
255 }
256
257 }
258
259 }
260
261 static BOOLEAN IsolateReadDataPortSelect(VOID)
262 {
263 ULONG Port;
264
265 SendWait();
266 SendKey();
267
268 /* Control: reset CSN and conditionally everything else too */
269 WriteUchar(0x02, 0x05);
270 KeStallExecutionProcessor(2000);
271
272 SendWait();
273 SendKey();
274 SendWake(0x00);
275
276 Port = FindNextReadPort();
277 if (Port == 0) {
278 SendWait();
279 return FALSE;
280 }
281
282 SetReadDataPort(Port);
283 KeStallExecutionProcessor(1000);
284 WriteAddress(0x01);
285 KeStallExecutionProcessor(1000);
286 return TRUE;
287 }
288
289 /*
290 * Isolate (assign uniqued CSN) to all ISA PnP devices
291 */
292 static ULONG IsolatePnPCards(VOID)
293 {
294 UCHAR checksum = 0x6a;
295 UCHAR chksum = 0x00;
296 UCHAR bit = 0x00;
297 ULONG data;
298 ULONG csn = 0;
299 ULONG i;
300 ULONG iteration = 1;
301
302 DPRINT("Called\n");
303
304 IsaPnPReadPort = (PUCHAR)(ISAPNP_MIN_READ_PORT - READ_DATA_PORT_STEP);
305 if (!IsolateReadDataPortSelect()) {
306 DPRINT("Could not set read data port\n");
307 return 0;
308 }
309
310 while (TRUE) {
311 for (i = 1; i <= 64; i++) {
312 data = ReadData() << 8;
313 KeStallExecutionProcessor(250);
314 data = data | ReadData();
315 KeStallExecutionProcessor(250);
316 if (data == 0x55aa)
317 bit = 0x01;
318 checksum = ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7) | (checksum >> 1);
319 bit = 0x00;
320 }
321 for (i = 65; i <= 72; i++) {
322 data = ReadData() << 8;
323 KeStallExecutionProcessor(250);
324 data = data | ReadData();
325 KeStallExecutionProcessor(250);
326 if (data == 0x55aa)
327 chksum |= (1 << (i - 65));
328 }
329 if ((checksum != 0x00) && (checksum == chksum)) {
330 csn++;
331
332 WriteUchar(0x06, (UCHAR) csn);
333 KeStallExecutionProcessor(250);
334 iteration++;
335 SendWake(0x00);
336 SetReadDataPort((ULONG)IsaPnPReadPort);
337 KeStallExecutionProcessor(1000);
338 WriteAddress(0x01);
339 KeStallExecutionProcessor(1000);
340 goto next;
341 }
342 if (iteration == 1) {
343 if (!IsolateReadDataPortSelect()) {
344 DPRINT("Could not set read data port\n");
345 return 0;
346 }
347 } else if (iteration > 1) {
348 break;
349 }
350 next:
351 checksum = 0x6a;
352 chksum = 0x00;
353 bit = 0x00;
354 }
355 SendWait();
356 return csn;
357 }
358
359
360 static VOID Peek(PUCHAR Data, ULONG Count)
361 {
362 ULONG i, j;
363 UCHAR d = 0;
364
365 for (i = 1; i <= Count; i++) {
366 for (j = 0; j < 20; j++) {
367 d = ReadUchar(0x05);
368 if (d & 0x1)
369 break;
370 KeStallExecutionProcessor(100);
371 }
372 if (!(d & 0x1)) {
373 if (Data != NULL)
374 *Data++ = 0xff;
375 continue;
376 }
377 d = ReadUchar(0x04); /* PRESDI */
378 if (Data != NULL)
379 *Data++ = d;
380 }
381 }
382
383
384 /*
385 * Skip specified number of bytes from stream
386 */
387 static VOID Skip(ULONG Count)
388 {
389 Peek(NULL, Count);
390 }
391
392
393 /*
394 * Read one tag from stream
395 */
396 static BOOLEAN ReadTag(PUCHAR Type,
397 PUSHORT Size,
398 PBOOLEAN Small)
399 {
400 UCHAR tag, tmp[2];
401
402 Peek(&tag, 1);
403 if (tag == 0) {
404 /* Invalid tag */
405 DPRINT("Invalid tag with value 0\n");
406 #ifndef NDEBUG
407 for (;;);
408 #endif
409 return FALSE;
410 }
411
412 if (tag & ISAPNP_RESOURCE_ITEM_TYPE) {
413 /* Large resource item */
414 *Type = (tag & 0x7f);
415 Peek(tmp, 2);
416 *Size = UCHAR2USHORT(tmp[0], tmp[1]);
417 *Small = FALSE;
418 #ifndef NDEBUG
419 if (*Type > ISAPNP_LRIN_FL_MEMORY_RANGE32) {
420 DPRINT("Invalid large tag with value 0x%X\n", *Type);
421 for (;;);
422 }
423 #endif
424 } else {
425 /* Small resource item */
426 *Type = (tag >> 3) & 0x0f;
427 *Size = tag & 0x07;
428 *Small = TRUE;
429 #ifndef NDEBUG
430 if (*Type > ISAPNP_SRIN_END_TAG) {
431 DPRINT("Invalid small tag with value 0x%X\n", *Type);
432 for (;;);
433 }
434 #endif
435 }
436 #if 0
437 DPRINT("Tag = 0x%X, Type = 0x%X, Size = %d (%s)\n",
438 tag, *Type, *Size, TagName(*Type, *Small));
439 #endif
440 /* Probably invalid data */
441 if ((*Type == 0xff) && (*Size == 0xffff)) {
442 DPRINT("Invalid data (Type 0x%X Size 0x%X)\n", *Type, *Size);
443 for (;;);
444 return FALSE;
445 }
446
447 return TRUE;
448 }
449
450
451 /*
452 * Parse ANSI name for ISA PnP logical device
453 */
454 static NTSTATUS ParseAnsiName(PUNICODE_STRING Name, PUSHORT Size)
455 {
456 ANSI_STRING AnsiString;
457 UCHAR Buffer[256];
458 USHORT size1;
459
460 size1 = (*Size >= sizeof(Buffer)) ? (sizeof(Buffer) - 1) : *Size;
461
462 Peek(Buffer, size1);
463 Buffer[size1] = '\0';
464 *Size -= size1;
465
466 /* Clean whitespace from end of string */
467 while ((size1 > 0) && (Buffer[--size1] == ' '))
468 Buffer[size1] = '\0';
469
470 DPRINT("ANSI name: %s\n", Buffer);
471
472 RtlInitAnsiString(&AnsiString, (PCSZ)&Buffer);
473 return RtlAnsiStringToUnicodeString(Name, &AnsiString, TRUE);
474 }
475
476
477 /*
478 * Add a resource list to the
479 * resource lists of a logical device
480 */
481 static NTSTATUS AddResourceList(
482 PISAPNP_LOGICAL_DEVICE LogicalDevice,
483 ULONG Priority,
484 PISAPNP_CONFIGURATION_LIST *NewList)
485 {
486 PISAPNP_CONFIGURATION_LIST List;
487
488 DPRINT("Adding resource list for logical device %d on card %d (Priority %d)\n",
489 LogicalDevice->Number,
490 LogicalDevice->Card->CardId,
491 Priority);
492
493 List = (PISAPNP_CONFIGURATION_LIST)
494 ExAllocatePoolWithTag(PagedPool, sizeof(ISAPNP_CONFIGURATION_LIST), TAG_ISAPNP);
495 if (!List)
496 return STATUS_INSUFFICIENT_RESOURCES;
497
498 RtlZeroMemory(List, sizeof(ISAPNP_CONFIGURATION_LIST));
499
500 List->Priority = Priority;
501
502 InitializeListHead(&List->ListHead);
503
504 InsertTailList(&LogicalDevice->Configuration, &List->ListEntry);
505
506 *NewList = List;
507
508 return STATUS_SUCCESS;
509 }
510
511
512 /*
513 * Add a resource entry to the
514 * resource list of a logical device
515 */
516 static NTSTATUS AddResourceDescriptor(
517 PISAPNP_LOGICAL_DEVICE LogicalDevice,
518 ULONG Priority,
519 ULONG Option,
520 PISAPNP_DESCRIPTOR *Descriptor)
521 {
522 PLIST_ENTRY CurrentEntry;
523 PISAPNP_CONFIGURATION_LIST List;
524 PISAPNP_DESCRIPTOR d;
525 NTSTATUS Status;
526
527 DPRINT("Adding resource descriptor for logical device %d on card %d (%d of %d)\n",
528 LogicalDevice->Number,
529 LogicalDevice->Card->CardId,
530 LogicalDevice->CurrentDescriptorCount,
531 LogicalDevice->DescriptorCount);
532
533 d = (PISAPNP_DESCRIPTOR)
534 ExAllocatePoolWithTag(PagedPool, sizeof(ISAPNP_DESCRIPTOR), TAG_ISAPNP);
535 if (!d)
536 return STATUS_NO_MEMORY;
537
538 RtlZeroMemory(d, sizeof(ISAPNP_DESCRIPTOR));
539
540 d->Descriptor.Option = (UCHAR) Option;
541
542 *Descriptor = d;
543
544 CurrentEntry = LogicalDevice->Configuration.Flink;
545 while (CurrentEntry != &LogicalDevice->Configuration) {
546 List = CONTAINING_RECORD(
547 CurrentEntry, ISAPNP_CONFIGURATION_LIST, ListEntry);
548
549 if (List->Priority == Priority) {
550
551 LogicalDevice->ConfigurationSize += sizeof(IO_RESOURCE_DESCRIPTOR);
552 InsertTailList(&List->ListHead, &d->ListEntry);
553 LogicalDevice->CurrentDescriptorCount++;
554 if (LogicalDevice->DescriptorCount <
555 LogicalDevice->CurrentDescriptorCount) {
556 LogicalDevice->DescriptorCount =
557 LogicalDevice->CurrentDescriptorCount;
558 }
559
560 return STATUS_SUCCESS;
561 }
562 CurrentEntry = CurrentEntry->Flink;
563 }
564
565 Status = AddResourceList(LogicalDevice, Priority, &List);
566 if (NT_SUCCESS(Status)) {
567 LogicalDevice->ConfigurationSize += sizeof(IO_RESOURCE_LIST);
568 LogicalDevice->CurrentDescriptorCount = 0;
569 InsertTailList(&List->ListHead, &d->ListEntry);
570 }
571
572 return Status;
573 }
574
575
576 /*
577 * Add IRQ resource to resources list
578 */
579 static NTSTATUS AddIrqResource(
580 PISAPNP_LOGICAL_DEVICE LogicalDevice,
581 ULONG Size,
582 ULONG Priority,
583 ULONG Option)
584 {
585 PISAPNP_DESCRIPTOR Descriptor;
586 UCHAR tmp[3];
587 ULONG irq, i, last = 0;
588 BOOLEAN found;
589 NTSTATUS Status;
590
591 Peek(tmp, Size);
592
593 irq = UCHAR2USHORT(tmp[0], tmp[0]);
594
595 DPRINT("IRQ bitmask: 0x%X\n", irq);
596
597 found = FALSE;
598 for (i = 0; i < 16; i++) {
599 if (!found && (irq & (1 << i))) {
600 last = i;
601 found = TRUE;
602 }
603
604 if ((found && !(irq & (1 << i))) || (irq & (1 << i) && (i == 15))) {
605 Status = AddResourceDescriptor(LogicalDevice,
606 Priority, Option, &Descriptor);
607 if (!NT_SUCCESS(Status))
608 return Status;
609 Descriptor->Descriptor.Type = CmResourceTypeInterrupt;
610 Descriptor->Descriptor.ShareDisposition = CmResourceShareDeviceExclusive;
611 Descriptor->Descriptor.u.Interrupt.MinimumVector = last;
612
613 if ((irq & (1 << i)) && (i == 15))
614 Descriptor->Descriptor.u.Interrupt.MaximumVector = i;
615 else
616 Descriptor->Descriptor.u.Interrupt.MaximumVector = i - 1;
617
618 DPRINT("Found IRQ range %d - %d for logical device %d on card %d\n",
619 Descriptor->Descriptor.u.Interrupt.MinimumVector,
620 Descriptor->Descriptor.u.Interrupt.MaximumVector,
621 LogicalDevice->Number,
622 LogicalDevice->Card->CardId);
623
624 found = FALSE;
625 }
626 }
627
628 return STATUS_SUCCESS;
629 }
630
631 /*
632 * Add DMA resource to resources list
633 */
634 static NTSTATUS AddDmaResource(
635 PISAPNP_LOGICAL_DEVICE LogicalDevice,
636 ULONG Size,
637 ULONG Priority,
638 ULONG Option)
639 {
640 PISAPNP_DESCRIPTOR Descriptor;
641 UCHAR tmp[2];
642 ULONG dma, flags, i, last = 0;
643 BOOLEAN found;
644 NTSTATUS Status;
645
646 Peek(tmp, Size);
647
648 dma = tmp[0];
649 flags = tmp[1];
650
651 DPRINT("DMA bitmask: 0x%X\n", dma);
652
653 found = FALSE;
654 for (i = 0; i < 8; i++) {
655 if (!found && (dma & (1 << i))) {
656 last = i;
657 found = TRUE;
658 }
659
660 if ((found && !(dma & (1 << i))) || (dma & (1 << i) && (i == 15))) {
661 Status = AddResourceDescriptor(LogicalDevice,
662 Priority, Option, &Descriptor);
663 if (!NT_SUCCESS(Status))
664 return Status;
665 Descriptor->Descriptor.Type = CmResourceTypeDma;
666 Descriptor->Descriptor.ShareDisposition = CmResourceShareDeviceExclusive;
667 Descriptor->Descriptor.u.Dma.MinimumChannel = last;
668
669 if ((dma & (1 << i)) && (i == 15))
670 Descriptor->Descriptor.u.Dma.MaximumChannel = i;
671 else
672 Descriptor->Descriptor.u.Dma.MaximumChannel = i - 1;
673
674 /* FIXME: Parse flags */
675
676 DPRINT("Found DMA range %d - %d for logical device %d on card %d\n",
677 Descriptor->Descriptor.u.Dma.MinimumChannel,
678 Descriptor->Descriptor.u.Dma.MaximumChannel,
679 LogicalDevice->Number,
680 LogicalDevice->Card->CardId);
681
682 found = FALSE;
683 }
684 }
685
686 return STATUS_SUCCESS;
687 }
688
689 /*
690 * Add port resource to resources list
691 */
692 static NTSTATUS AddIOPortResource(
693 PISAPNP_LOGICAL_DEVICE LogicalDevice,
694 ULONG Size,
695 ULONG Priority,
696 ULONG Option)
697 {
698 #if 0
699 DPRINT("I/O port: size 0x%X\n", Size);
700 Skip(Size);
701 #else
702 PISAPNP_DESCRIPTOR Descriptor;
703 UCHAR tmp[7];
704 NTSTATUS Status;
705
706 Peek(tmp, Size);
707
708 Status = AddResourceDescriptor(LogicalDevice,
709 Priority, Option, &Descriptor);
710 if (!NT_SUCCESS(Status))
711 return Status;
712 Descriptor->Descriptor.Type = CmResourceTypePort;
713 Descriptor->Descriptor.ShareDisposition = CmResourceShareDeviceExclusive;
714 Descriptor->Descriptor.u.Port.Length = tmp[6];
715 /* FIXME: Parse flags */
716 Descriptor->Descriptor.u.Port.Alignment = 0;
717 Descriptor->Descriptor.u.Port.MinimumAddress.QuadPart = UCHAR2USHORT(tmp[1], tmp[2]);
718 Descriptor->Descriptor.u.Port.MaximumAddress.QuadPart = UCHAR2USHORT(tmp[4], tmp[4]);
719
720 DPRINT("Found I/O port range 0x%X - 0x%X for logical device %d on card %d\n",
721 Descriptor->Descriptor.u.Port.MinimumAddress,
722 Descriptor->Descriptor.u.Port.MaximumAddress,
723 LogicalDevice->Number,
724 LogicalDevice->Card->CardId);
725 #endif
726 return STATUS_SUCCESS;
727 }
728
729 /*
730 * Add fixed port resource to resources list
731 */
732 static NTSTATUS AddFixedIOPortResource(
733 PISAPNP_LOGICAL_DEVICE LogicalDevice,
734 ULONG Size,
735 ULONG Priority,
736 ULONG Option)
737 {
738 #if 0
739 DPRINT("Fixed I/O port: size 0x%X\n", Size);
740 Skip(Size);
741 #else
742 PISAPNP_DESCRIPTOR Descriptor;
743 UCHAR tmp[3];
744 NTSTATUS Status;
745
746 Peek(tmp, Size);
747
748 Status = AddResourceDescriptor(LogicalDevice,
749 Priority, Option, &Descriptor);
750 if (!NT_SUCCESS(Status))
751 return Status;
752 Descriptor->Descriptor.Type = CmResourceTypePort;
753 Descriptor->Descriptor.ShareDisposition = CmResourceShareDeviceExclusive;
754 Descriptor->Descriptor.u.Port.Length = tmp[2];
755 Descriptor->Descriptor.u.Port.Alignment = 0;
756 Descriptor->Descriptor.u.Port.MinimumAddress.QuadPart = UCHAR2USHORT(tmp[0], tmp[1]);
757 Descriptor->Descriptor.u.Port.MaximumAddress.QuadPart = UCHAR2USHORT(tmp[0], tmp[1]);
758
759 DPRINT("Found fixed I/O port range 0x%X - 0x%X for logical device %d on card %d\n",
760 Descriptor->Descriptor.u.Port.MinimumAddress,
761 Descriptor->Descriptor.u.Port.MaximumAddress,
762 LogicalDevice->Number,
763 LogicalDevice->Card->CardId);
764 #endif
765 return STATUS_SUCCESS;
766 }
767
768 /*
769 * Add memory resource to resources list
770 */
771 static NTSTATUS AddMemoryResource(
772 PISAPNP_LOGICAL_DEVICE LogicalDevice,
773 ULONG Size,
774 ULONG Priority,
775 ULONG Option)
776 {
777 #if 0
778 DPRINT("Memory range: size 0x%X\n", Size);
779 Skip(Size);
780 #else
781 PISAPNP_DESCRIPTOR Descriptor;
782 UCHAR tmp[9];
783 NTSTATUS Status;
784
785 Peek(tmp, Size);
786
787 Status = AddResourceDescriptor(LogicalDevice,
788 Priority, Option, &Descriptor);
789 if (!NT_SUCCESS(Status))
790 return Status;
791 Descriptor->Descriptor.Type = CmResourceTypeMemory;
792 Descriptor->Descriptor.ShareDisposition = CmResourceShareDeviceExclusive;
793 Descriptor->Descriptor.u.Memory.Length = UCHAR2USHORT(tmp[7], tmp[8]) << 8;
794 Descriptor->Descriptor.u.Memory.Alignment = UCHAR2USHORT(tmp[5], tmp[6]);
795 Descriptor->Descriptor.u.Memory.MinimumAddress.QuadPart = UCHAR2USHORT(tmp[1], tmp[2]) << 8;
796 Descriptor->Descriptor.u.Memory.MaximumAddress.QuadPart = UCHAR2USHORT(tmp[3], tmp[4]) << 8;
797
798 DPRINT("Found memory range 0x%X - 0x%X for logical device %d on card %d\n",
799 Descriptor->Descriptor.u.Memory.MinimumAddress,
800 Descriptor->Descriptor.u.Memory.MaximumAddress,
801 LogicalDevice->Number,
802 LogicalDevice->Card->CardId);
803 #endif
804 return STATUS_SUCCESS;
805 }
806
807 /*
808 * Add 32-bit memory resource to resources list
809 */
810 static NTSTATUS AddMemory32Resource(
811 PISAPNP_LOGICAL_DEVICE LogicalDevice,
812 ULONG Size,
813 ULONG Priority,
814 ULONG Option)
815 {
816 #if 0
817 DPRINT("Memory32 range: size 0x%X\n", Size);
818 Skip(Size);
819 #else
820 PISAPNP_DESCRIPTOR Descriptor;
821 UCHAR tmp[17];
822 NTSTATUS Status;
823
824 Peek(tmp, Size);
825
826 Status = AddResourceDescriptor(LogicalDevice,
827 Priority, Option, &Descriptor);
828 if (!NT_SUCCESS(Status))
829 return Status;
830 Descriptor->Descriptor.Type = CmResourceTypeMemory;
831 Descriptor->Descriptor.ShareDisposition = CmResourceShareDeviceExclusive;
832 Descriptor->Descriptor.u.Memory.Length =
833 UCHAR2ULONG(tmp[13], tmp[14], tmp[15], tmp[16]);
834 Descriptor->Descriptor.u.Memory.Alignment =
835 UCHAR2ULONG(tmp[9], tmp[10], tmp[11], tmp[12]);
836 Descriptor->Descriptor.u.Memory.MinimumAddress.QuadPart =
837 UCHAR2ULONG(tmp[1], tmp[2], tmp[3], tmp[4]);
838 Descriptor->Descriptor.u.Memory.MaximumAddress.QuadPart =
839 UCHAR2ULONG(tmp[5], tmp[6], tmp[7], tmp[8]);
840
841 DPRINT("Found memory32 range 0x%X - 0x%X for logical device %d on card %d\n",
842 Descriptor->Descriptor.u.Memory.MinimumAddress,
843 Descriptor->Descriptor.u.Memory.MaximumAddress,
844 LogicalDevice->Number,
845 LogicalDevice->Card->CardId);
846 #endif
847 return STATUS_SUCCESS;
848 }
849
850 /*
851 * Add 32-bit fixed memory resource to resources list
852 */
853 static NTSTATUS AddFixedMemory32Resource(
854 PISAPNP_LOGICAL_DEVICE LogicalDevice,
855 ULONG Size,
856 ULONG Priority,
857 ULONG Option)
858 {
859 #if 0
860 DPRINT("Memory32 range: size 0x%X\n", Size);
861 Skip(Size);
862 #else
863 PISAPNP_DESCRIPTOR Descriptor;
864 UCHAR tmp[17];
865 NTSTATUS Status;
866
867 Peek(tmp, Size);
868
869 Status = AddResourceDescriptor(LogicalDevice,
870 Priority, Option, &Descriptor);
871 if (!NT_SUCCESS(Status))
872 return Status;
873 Descriptor->Descriptor.Type = CmResourceTypeMemory;
874 Descriptor->Descriptor.ShareDisposition = CmResourceShareDeviceExclusive;
875 Descriptor->Descriptor.u.Memory.Length =
876 UCHAR2ULONG(tmp[9], tmp[10], tmp[11], tmp[12]);
877 Descriptor->Descriptor.u.Memory.Alignment =
878 UCHAR2ULONG(tmp[5], tmp[6], tmp[7], tmp[8]);
879 Descriptor->Descriptor.u.Memory.MinimumAddress.QuadPart =
880 UCHAR2ULONG(tmp[1], tmp[2], tmp[3], tmp[4]);
881 Descriptor->Descriptor.u.Memory.MaximumAddress.QuadPart =
882 UCHAR2ULONG(tmp[1], tmp[2], tmp[3], tmp[4]);
883
884 DPRINT("Found fixed memory32 range 0x%X - 0x%X for logical device %d on card %d\n",
885 Descriptor->Descriptor.u.Memory.MinimumAddress,
886 Descriptor->Descriptor.u.Memory.MaximumAddress,
887 LogicalDevice->Number,
888 LogicalDevice->Card->CardId);
889 #endif
890 return STATUS_SUCCESS;
891 }
892
893
894 /*
895 * Parse logical device tag
896 */
897 static PISAPNP_LOGICAL_DEVICE ParseLogicalDevice(
898 PISAPNP_DEVICE_EXTENSION DeviceExtension,
899 PISAPNP_CARD Card,
900 ULONG Size,
901 USHORT Number)
902 {
903 UCHAR tmp[6];
904 PISAPNP_LOGICAL_DEVICE LogicalDevice;
905
906 DPRINT("Card %d Number %d\n", Card->CardId, Number);
907
908 Peek(tmp, Size);
909
910 LogicalDevice = (PISAPNP_LOGICAL_DEVICE)ExAllocatePoolWithTag(
911 PagedPool, sizeof(ISAPNP_LOGICAL_DEVICE), TAG_ISAPNP);
912 if (!LogicalDevice)
913 return NULL;
914
915 RtlZeroMemory(LogicalDevice, sizeof(ISAPNP_LOGICAL_DEVICE));
916
917 LogicalDevice->Number = Number;
918 LogicalDevice->VendorId = UCHAR2USHORT(tmp[0], tmp[1]);
919 LogicalDevice->DeviceId = UCHAR2USHORT(tmp[2], tmp[3]);
920 LogicalDevice->Regs = tmp[4];
921 LogicalDevice->Card = Card;
922 if (Size > 5)
923 LogicalDevice->Regs |= tmp[5] << 8;
924
925 InitializeListHead(&LogicalDevice->Configuration);
926
927 ExInterlockedInsertTailList(&Card->LogicalDevices,
928 &LogicalDevice->CardListEntry,
929 &Card->LogicalDevicesLock);
930
931 ExInterlockedInsertTailList(&DeviceExtension->DeviceListHead,
932 &LogicalDevice->DeviceListEntry,
933 &DeviceExtension->GlobalListLock);
934
935 DeviceExtension->DeviceListCount++;
936
937 return LogicalDevice;
938 }
939
940
941 /*
942 * Parse resource map for logical device
943 */
944 static BOOLEAN CreateLogicalDevice(PISAPNP_DEVICE_EXTENSION DeviceExtension,
945 PISAPNP_CARD Card, USHORT Size)
946 {
947 ULONG number = 0, skip = 0, compat = 0;
948 UCHAR type, tmp[17];
949 PISAPNP_LOGICAL_DEVICE LogicalDevice;
950 BOOLEAN Small;
951 ULONG Priority = 0;
952 ULONG Option = IO_RESOURCE_REQUIRED;
953
954 DPRINT("Card %d Size %d\n", Card->CardId, Size);
955
956 LogicalDevice = ParseLogicalDevice(DeviceExtension, Card, Size, (USHORT) number++);
957 if (!LogicalDevice)
958 return FALSE;
959
960 while (TRUE) {
961 if (!ReadTag(&type, &Size, &Small))
962 return FALSE;
963
964 if (skip && !(Small && ((type == ISAPNP_SRIN_LDEVICE_ID)
965 || (type == ISAPNP_SRIN_END_TAG))))
966 goto skip;
967
968 if (Small) {
969 switch (type) {
970 case ISAPNP_SRIN_LDEVICE_ID:
971 if ((Size >= 5) && (Size <= 6)) {
972 LogicalDevice = ParseLogicalDevice(
973 DeviceExtension, Card, Size, (USHORT)number++);
974 if (!LogicalDevice)
975 return FALSE;
976 Size = 0;
977 skip = 0;
978 } else {
979 skip = 1;
980 }
981 Priority = 0;
982 Option = IO_RESOURCE_REQUIRED;
983 compat = 0;
984 break;
985
986 case ISAPNP_SRIN_CDEVICE_ID:
987 if ((Size == 4) && (compat < MAX_COMPATIBLE_ID)) {
988 Peek(tmp, 4);
989 LogicalDevice->CVendorId[compat] = UCHAR2USHORT(tmp[0], tmp[1]);
990 LogicalDevice->CDeviceId[compat] = UCHAR2USHORT(tmp[2], tmp[3]);
991 compat++;
992 Size = 0;
993 }
994 break;
995
996 case ISAPNP_SRIN_IRQ_FORMAT:
997 if ((Size < 2) || (Size > 3))
998 goto skip;
999 AddIrqResource(LogicalDevice, Size, Priority, Option);
1000 Size = 0;
1001 break;
1002
1003 case ISAPNP_SRIN_DMA_FORMAT:
1004 if (Size != 2)
1005 goto skip;
1006 AddDmaResource(LogicalDevice, Size, Priority, Option);
1007 Size = 0;
1008 break;
1009
1010 case ISAPNP_SRIN_START_DFUNCTION:
1011 if (Size > 1)
1012 goto skip;
1013
1014 if (Size > 0) {
1015 Peek(tmp, Size);
1016 Priority = tmp[0];
1017 Size = 0;
1018 /* FIXME: Maybe use IO_RESOURCE_PREFERRED for some */
1019 Option = IO_RESOURCE_ALTERNATIVE;
1020 } else {
1021 Priority = 0;
1022 Option = IO_RESOURCE_ALTERNATIVE;
1023 }
1024
1025 DPRINT(" Start priority %d \n", Priority);
1026
1027 LogicalDevice->CurrentDescriptorCount = 0;
1028
1029 break;
1030
1031 case ISAPNP_SRIN_END_DFUNCTION:
1032
1033 DPRINT(" End priority %d \n", Priority);
1034
1035 if (Size != 0)
1036 goto skip;
1037 Priority = 0;
1038 Option = IO_RESOURCE_REQUIRED;
1039 LogicalDevice->CurrentDescriptorCount = 0;
1040 break;
1041
1042 case ISAPNP_SRIN_IO_DESCRIPTOR:
1043 if (Size != 7)
1044 goto skip;
1045 AddIOPortResource(LogicalDevice, Size, Priority, Option);
1046 Size = 0;
1047 break;
1048
1049 case ISAPNP_SRIN_FL_IO_DESCRIPOTOR:
1050 if (Size != 3)
1051 goto skip;
1052 AddFixedIOPortResource(LogicalDevice, Size, Priority, Option);
1053 Size = 0;
1054 break;
1055
1056 case ISAPNP_SRIN_VENDOR_DEFINED:
1057 break;
1058
1059 case ISAPNP_SRIN_END_TAG:
1060 if (Size > 0)
1061 Skip(Size);
1062 return FALSE;
1063
1064 default:
1065 DPRINT("Ignoring small tag of type 0x%X for logical device %d on card %d\n",
1066 type, LogicalDevice->Number, Card->CardId);
1067 }
1068 } else {
1069 switch (type) {
1070 case ISAPNP_LRIN_MEMORY_RANGE:
1071 if (Size != 9)
1072 goto skip;
1073 AddMemoryResource(LogicalDevice, Size, Priority, Option);
1074 Size = 0;
1075 break;
1076
1077 case ISAPNP_LRIN_ID_STRING_ANSI:
1078 ParseAnsiName(&LogicalDevice->Name, &Size);
1079 break;
1080
1081 case ISAPNP_LRIN_ID_STRING_UNICODE:
1082 break;
1083
1084 case ISAPNP_LRIN_VENDOR_DEFINED:
1085 break;
1086
1087 case ISAPNP_LRIN_MEMORY_RANGE32:
1088 if (Size != 17)
1089 goto skip;
1090 AddMemory32Resource(LogicalDevice, Size, Priority, Option);
1091 Size = 0;
1092 break;
1093
1094 case ISAPNP_LRIN_FL_MEMORY_RANGE32:
1095 if (Size != 17)
1096 goto skip;
1097 AddFixedMemory32Resource(LogicalDevice, Size, Priority, Option);
1098 Size = 0;
1099 break;
1100
1101 default:
1102 DPRINT("Ignoring large tag of type 0x%X for logical device %d on card %d\n",
1103 type, LogicalDevice->Number, Card->CardId);
1104 }
1105 }
1106 skip:
1107 if (Size > 0)
1108 Skip(Size);
1109 }
1110
1111 return TRUE;
1112 }
1113
1114
1115 /*
1116 * Parse resource map for ISA PnP card
1117 */
1118 static BOOLEAN ParseResourceMap(PISAPNP_DEVICE_EXTENSION DeviceExtension,
1119 PISAPNP_CARD Card)
1120 {
1121 UCHAR type, tmp[17];
1122 USHORT size;
1123 BOOLEAN Small;
1124
1125 DPRINT("Card %d\n", Card->CardId);
1126
1127 while (TRUE) {
1128 if (!ReadTag(&type, &size, &Small))
1129 return FALSE;
1130
1131 if (Small) {
1132 switch (type) {
1133 case ISAPNP_SRIN_VERSION:
1134 if (size != 2)
1135 goto skip;
1136 Peek(tmp, 2);
1137 Card->PNPVersion = tmp[0];
1138 Card->ProductVersion = tmp[1];
1139 size = 0;
1140 break;
1141
1142 case ISAPNP_SRIN_LDEVICE_ID:
1143 if ((size >= 5) && (size <= 6)) {
1144 if (!CreateLogicalDevice(DeviceExtension, Card, size))
1145 return FALSE;
1146 size = 0;
1147 }
1148 break;
1149
1150 case ISAPNP_SRIN_CDEVICE_ID:
1151 /* FIXME: Parse compatible IDs */
1152 break;
1153
1154 case ISAPNP_SRIN_END_TAG:
1155 if (size > 0)
1156 Skip(size);
1157 return TRUE;
1158
1159 default:
1160 DPRINT("Ignoring small tag Type 0x%X for Card %d\n", type, Card->CardId);
1161 }
1162 } else {
1163 switch (type) {
1164 case ISAPNP_LRIN_ID_STRING_ANSI:
1165 ParseAnsiName(&Card->Name, &size);
1166 break;
1167
1168 default:
1169 DPRINT("Ignoring large tag Type 0x%X for Card %d\n",
1170 type, Card->CardId);
1171 }
1172 }
1173 skip:
1174 if (size > 0)
1175 Skip(size);
1176 }
1177
1178 return TRUE;
1179 }
1180
1181
1182 /*
1183 * Compute ISA PnP checksum for first eight bytes
1184 */
1185 static UCHAR Checksum(PUCHAR data)
1186 {
1187 ULONG i, j;
1188 UCHAR checksum = 0x6a, bit, b;
1189
1190 for (i = 0; i < 8; i++) {
1191 b = data[i];
1192 for (j = 0; j < 8; j++) {
1193 bit = 0;
1194 if (b & (1 << j))
1195 bit = 1;
1196 checksum = ((((checksum ^ (checksum >> 1)) &
1197 0x01) ^ bit) << 7) | (checksum >> 1);
1198 }
1199 }
1200 return checksum;
1201 }
1202
1203
1204 /*
1205 * Build a resource list for a logical ISA PnP device
1206 */
1207 static NTSTATUS BuildResourceList(PISAPNP_LOGICAL_DEVICE LogicalDevice,
1208 PIO_RESOURCE_LIST DestinationList,
1209 ULONG Priority)
1210 {
1211 PLIST_ENTRY CurrentEntry, Entry;
1212 PISAPNP_CONFIGURATION_LIST List;
1213 PISAPNP_DESCRIPTOR Descriptor;
1214 ULONG i;
1215
1216 if (IsListEmpty(&LogicalDevice->Configuration))
1217 return STATUS_NOT_FOUND;
1218
1219 CurrentEntry = LogicalDevice->Configuration.Flink;
1220 while (CurrentEntry != &LogicalDevice->Configuration) {
1221 List = CONTAINING_RECORD(
1222 CurrentEntry, ISAPNP_CONFIGURATION_LIST, ListEntry);
1223
1224 if (List->Priority == Priority) {
1225
1226 DPRINT("Logical device %d DestinationList %p\n",
1227 LogicalDevice->Number,
1228 DestinationList);
1229
1230 DestinationList->Version = 1;
1231 DestinationList->Revision = 1;
1232 DestinationList->Count = LogicalDevice->DescriptorCount;
1233
1234 i = 0;
1235 Entry = List->ListHead.Flink;
1236 while (Entry != &List->ListHead) {
1237 Descriptor = CONTAINING_RECORD(
1238 Entry, ISAPNP_DESCRIPTOR, ListEntry);
1239
1240 DPRINT("Logical device %d Destination %p(%d)\n",
1241 LogicalDevice->Number,
1242 &DestinationList->Descriptors[i],
1243 i);
1244
1245 RtlCopyMemory(&DestinationList->Descriptors[i],
1246 &Descriptor->Descriptor,
1247 sizeof(IO_RESOURCE_DESCRIPTOR));
1248
1249 i++;
1250
1251 Entry = Entry->Flink;
1252 }
1253
1254 RemoveEntryList(&List->ListEntry);
1255
1256 ExFreePool(List);
1257
1258 return STATUS_SUCCESS;
1259 }
1260
1261 CurrentEntry = CurrentEntry->Flink;
1262 }
1263
1264 return STATUS_UNSUCCESSFUL;
1265 }
1266
1267
1268 /*
1269 * Build resource lists for a logical ISA PnP device
1270 */
1271 static NTSTATUS BuildResourceLists(PISAPNP_LOGICAL_DEVICE LogicalDevice)
1272 {
1273 ULONG ListSize;
1274 ULONG Priority;
1275 ULONG SingleListSize;
1276 PIO_RESOURCE_LIST p;
1277 NTSTATUS Status;
1278
1279 ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST)
1280 - sizeof(IO_RESOURCE_LIST)
1281 + LogicalDevice->ConfigurationSize;
1282
1283 DPRINT("Logical device %d ListSize 0x%X ConfigurationSize 0x%X DescriptorCount %d\n",
1284 LogicalDevice->Number, ListSize,
1285 LogicalDevice->ConfigurationSize,
1286 LogicalDevice->DescriptorCount);
1287
1288 LogicalDevice->ResourceLists =
1289 (PIO_RESOURCE_REQUIREMENTS_LIST)ExAllocatePoolWithTag(
1290 PagedPool, ListSize, TAG_ISAPNP);
1291 if (!LogicalDevice->ResourceLists)
1292 return STATUS_INSUFFICIENT_RESOURCES;
1293
1294 RtlZeroMemory(LogicalDevice->ResourceLists, ListSize);
1295
1296 SingleListSize = sizeof(IO_RESOURCE_LIST) +
1297 (LogicalDevice->DescriptorCount - 1) *
1298 sizeof(IO_RESOURCE_DESCRIPTOR);
1299
1300 DPRINT("SingleListSize %d\n", SingleListSize);
1301
1302 Priority = 0;
1303 p = &LogicalDevice->ResourceLists->List[0];
1304 do {
1305 Status = BuildResourceList(LogicalDevice, p, Priority);
1306 if (NT_SUCCESS(Status)) {
1307 p = (PIO_RESOURCE_LIST)((ULONG)p + SingleListSize);
1308 Priority++;
1309 }
1310 } while (Status != STATUS_NOT_FOUND);
1311
1312 LogicalDevice->ResourceLists->ListSize = ListSize;
1313 LogicalDevice->ResourceLists->AlternativeLists = Priority + 1;
1314
1315 return STATUS_SUCCESS;
1316 }
1317
1318
1319 /*
1320 * Build resource lists for a ISA PnP card
1321 */
1322 static NTSTATUS BuildResourceListsForCard(PISAPNP_CARD Card)
1323 {
1324 PISAPNP_LOGICAL_DEVICE LogicalDevice;
1325 PLIST_ENTRY CurrentEntry;
1326 NTSTATUS Status;
1327
1328 CurrentEntry = Card->LogicalDevices.Flink;
1329 while (CurrentEntry != &Card->LogicalDevices) {
1330 LogicalDevice = CONTAINING_RECORD(
1331 CurrentEntry, ISAPNP_LOGICAL_DEVICE, CardListEntry);
1332 Status = BuildResourceLists(LogicalDevice);
1333 if (!NT_SUCCESS(Status))
1334 return Status;
1335 CurrentEntry = CurrentEntry->Flink;
1336 }
1337
1338 return STATUS_SUCCESS;
1339 }
1340
1341
1342 /*
1343 * Build resource lists for all present ISA PnP cards
1344 */
1345 static NTSTATUS BuildResourceListsForAll(
1346 PISAPNP_DEVICE_EXTENSION DeviceExtension)
1347 {
1348 PLIST_ENTRY CurrentEntry;
1349 PISAPNP_CARD Card;
1350 NTSTATUS Status;
1351
1352 CurrentEntry = DeviceExtension->CardListHead.Flink;
1353 while (CurrentEntry != &DeviceExtension->CardListHead) {
1354 Card = CONTAINING_RECORD(
1355 CurrentEntry, ISAPNP_CARD, ListEntry);
1356 Status = BuildResourceListsForCard(Card);
1357 if (!NT_SUCCESS(Status))
1358 return Status;
1359 CurrentEntry = CurrentEntry->Flink;
1360 }
1361
1362 return STATUS_SUCCESS;
1363 }
1364
1365
1366 /*
1367 * Build device list for all present ISA PnP cards
1368 */
1369 static NTSTATUS BuildDeviceList(PISAPNP_DEVICE_EXTENSION DeviceExtension)
1370 {
1371 ULONG csn;
1372 UCHAR header[9], checksum;
1373 PISAPNP_CARD Card;
1374
1375 DPRINT("Called\n");
1376
1377 SendWait();
1378 SendKey();
1379 for (csn = 1; csn <= 10; csn++) {
1380 SendWake((UCHAR)csn);
1381 Peek(header, 9);
1382 checksum = Checksum(header);
1383
1384 if (checksum == 0x00 || checksum != header[8]) /* Invalid CSN */
1385 continue;
1386
1387 DPRINT("VENDOR: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
1388 header[0], header[1], header[2], header[3],
1389 header[4], header[5], header[6], header[7], header[8]);
1390
1391 Card = (PISAPNP_CARD)ExAllocatePoolWithTag(
1392 PagedPool, sizeof(ISAPNP_CARD), TAG_ISAPNP);
1393 if (!Card)
1394 return STATUS_INSUFFICIENT_RESOURCES;
1395
1396 RtlZeroMemory(Card, sizeof(ISAPNP_CARD));
1397
1398 Card->CardId = (USHORT) csn;
1399 Card->VendorId = (header[1] << 8) | header[0];
1400 Card->DeviceId = (header[3] << 8) | header[2];
1401 Card->Serial = (header[7] << 24) | (header[6] << 16) | (header[5] << 8) | header[4];
1402
1403 InitializeListHead(&Card->LogicalDevices);
1404 KeInitializeSpinLock(&Card->LogicalDevicesLock);
1405
1406 ParseResourceMap(DeviceExtension, Card);
1407
1408 ExInterlockedInsertTailList(&DeviceExtension->CardListHead,
1409 &Card->ListEntry,
1410 &DeviceExtension->GlobalListLock);
1411 }
1412
1413 return STATUS_SUCCESS;
1414 }
1415
1416
1417 static NTSTATUS
1418 ISAPNPQueryBusRelations(
1419 IN PDEVICE_OBJECT DeviceObject,
1420 IN PIRP Irp,
1421 PIO_STACK_LOCATION IrpSp)
1422 {
1423 PISAPNP_DEVICE_EXTENSION DeviceExtension;
1424 PISAPNP_LOGICAL_DEVICE LogicalDevice;
1425 PDEVICE_RELATIONS Relations;
1426 PLIST_ENTRY CurrentEntry;
1427 NTSTATUS Status = STATUS_SUCCESS;
1428 ULONG Size;
1429 ULONG i;
1430
1431 DPRINT("Called\n");
1432
1433 DeviceExtension = (PISAPNP_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1434
1435 if (Irp->IoStatus.Information) {
1436 /* FIXME: Another bus driver has already created a DEVICE_RELATIONS
1437 structure so we must merge this structure with our own */
1438 }
1439
1440 Size = sizeof(DEVICE_RELATIONS) + sizeof(Relations->Objects) *
1441 (DeviceExtension->DeviceListCount - 1);
1442 Relations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag(PagedPool, Size, TAG_ISAPNP);
1443 if (!Relations)
1444 return STATUS_INSUFFICIENT_RESOURCES;
1445
1446 Relations->Count = DeviceExtension->DeviceListCount;
1447
1448 i = 0;
1449 CurrentEntry = DeviceExtension->DeviceListHead.Flink;
1450 while (CurrentEntry != &DeviceExtension->DeviceListHead) {
1451 LogicalDevice = CONTAINING_RECORD(
1452 CurrentEntry, ISAPNP_LOGICAL_DEVICE, DeviceListEntry);
1453
1454 if (!LogicalDevice->Pdo) {
1455 /* Create a physical device object for the
1456 device as it does not already have one */
1457 Status = IoCreateDevice(DeviceObject->DriverObject, 0,
1458 NULL, FILE_DEVICE_CONTROLLER, 0, FALSE, &LogicalDevice->Pdo);
1459 if (!NT_SUCCESS(Status)) {
1460 DPRINT("IoCreateDevice() failed with status 0x%X\n", Status);
1461 ExFreePool(Relations);
1462 return Status;
1463 }
1464
1465 LogicalDevice->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
1466 }
1467
1468 /* Reference the physical device object. The PnP manager
1469 will dereference it again when it is no longer needed */
1470 ObReferenceObject(LogicalDevice->Pdo);
1471
1472 Relations->Objects[i] = LogicalDevice->Pdo;
1473
1474 i++;
1475
1476 CurrentEntry = CurrentEntry->Flink;
1477 }
1478
1479 Irp->IoStatus.Information = (ULONG)Relations;
1480
1481 return Status;
1482 }
1483
1484
1485 static NTSTATUS
1486 ISAPNPQueryDeviceRelations(
1487 IN PDEVICE_OBJECT DeviceObject,
1488 IN PIRP Irp,
1489 PIO_STACK_LOCATION IrpSp)
1490 {
1491 PISAPNP_DEVICE_EXTENSION DeviceExtension;
1492 NTSTATUS Status;
1493
1494 DPRINT("Called\n");
1495
1496 DeviceExtension = (PISAPNP_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1497
1498 if (DeviceExtension->State == dsStopped)
1499 return STATUS_UNSUCCESSFUL;
1500
1501 switch (IrpSp->Parameters.QueryDeviceRelations.Type) {
1502 case BusRelations:
1503 Status = ISAPNPQueryBusRelations(DeviceObject, Irp, IrpSp);
1504 break;
1505
1506 default:
1507 Status = STATUS_NOT_IMPLEMENTED;
1508 }
1509
1510 return Status;
1511 }
1512
1513
1514 static NTSTATUS
1515 ISAPNPStartDevice(
1516 IN PDEVICE_OBJECT DeviceObject,
1517 IN PIRP Irp,
1518 PIO_STACK_LOCATION IrpSp)
1519 {
1520 PISAPNP_DEVICE_EXTENSION DeviceExtension;
1521 NTSTATUS Status;
1522 ULONG NumCards;
1523
1524 DPRINT("Called\n");
1525
1526 DeviceExtension = (PISAPNP_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1527
1528 if (DeviceExtension->State == dsStarted)
1529 return STATUS_SUCCESS;
1530
1531 NumCards = IsolatePnPCards();
1532
1533 DPRINT("Number of ISA PnP cards found: %d\n", NumCards);
1534
1535 Status = BuildDeviceList(DeviceExtension);
1536 if (!NT_SUCCESS(Status)) {
1537 DPRINT("BuildDeviceList() failed with status 0x%X\n", Status);
1538 return Status;
1539 }
1540
1541 Status = BuildResourceListsForAll(DeviceExtension);
1542 if (!NT_SUCCESS(Status)) {
1543 DPRINT("BuildResourceListsForAll() failed with status 0x%X\n", Status);
1544 return Status;
1545 }
1546
1547 DeviceExtension->State = dsStarted;
1548
1549 return STATUS_SUCCESS;
1550 }
1551
1552
1553 static NTSTATUS
1554 ISAPNPStopDevice(
1555 IN PDEVICE_OBJECT DeviceObject,
1556 IN PIRP Irp,
1557 PIO_STACK_LOCATION IrpSp)
1558 {
1559 PISAPNP_DEVICE_EXTENSION DeviceExtension;
1560
1561 DPRINT("Called\n");
1562
1563 DeviceExtension = (PISAPNP_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1564
1565 if (DeviceExtension->State != dsStopped) {
1566 /* FIXME: Stop device */
1567 DeviceExtension->State = dsStopped;
1568 }
1569
1570 return STATUS_SUCCESS;
1571 }
1572
1573
1574 static DRIVER_DISPATCH ISAPNPDispatchOpenClose;
1575 static NTSTATUS
1576 NTAPI
1577 ISAPNPDispatchOpenClose(
1578 IN PDEVICE_OBJECT DeviceObject,
1579 IN PIRP Irp)
1580 {
1581 DPRINT("Called\n");
1582
1583 Irp->IoStatus.Status = STATUS_SUCCESS;
1584 Irp->IoStatus.Information = FILE_OPENED;
1585 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1586
1587 return STATUS_SUCCESS;
1588 }
1589
1590 static DRIVER_DISPATCH ISAPNPDispatchReadWrite;
1591 static NTSTATUS
1592 NTAPI
1593 ISAPNPDispatchReadWrite(
1594 IN PDEVICE_OBJECT PhysicalDeviceObject,
1595 IN PIRP Irp)
1596 {
1597 DPRINT("Called\n");
1598
1599 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
1600 Irp->IoStatus.Information = 0;
1601 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1602
1603 return STATUS_UNSUCCESSFUL;
1604 }
1605
1606 static DRIVER_DISPATCH ISAPNPDispatchDeviceControl;
1607 static NTSTATUS
1608 NTAPI
1609 ISAPNPDispatchDeviceControl(
1610 IN PDEVICE_OBJECT DeviceObject,
1611 IN PIRP Irp)
1612 {
1613 PIO_STACK_LOCATION IrpSp;
1614 NTSTATUS Status;
1615
1616 DPRINT("Called\n");
1617
1618 Irp->IoStatus.Information = 0;
1619
1620 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1621 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
1622 default:
1623 DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
1624 Status = STATUS_NOT_IMPLEMENTED;
1625 break;
1626 }
1627
1628 if (Status != STATUS_PENDING) {
1629 Irp->IoStatus.Status = Status;
1630 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1631 }
1632
1633 DPRINT("Leaving. Status 0x%X\n", Status);
1634
1635 return Status;
1636 }
1637
1638 static DRIVER_DISPATCH ISAPNPControl;
1639 static NTSTATUS
1640 NTAPI
1641 ISAPNPControl(
1642 IN PDEVICE_OBJECT DeviceObject,
1643 IN PIRP Irp)
1644 {
1645 PIO_STACK_LOCATION IrpSp;
1646 NTSTATUS Status;
1647
1648 DPRINT("Called\n");
1649
1650 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1651 switch (IrpSp->MinorFunction) {
1652 case IRP_MN_QUERY_DEVICE_RELATIONS:
1653 Status = ISAPNPQueryDeviceRelations(DeviceObject, Irp, IrpSp);
1654 break;
1655
1656 case IRP_MN_START_DEVICE:
1657 Status = ISAPNPStartDevice(DeviceObject, Irp, IrpSp);
1658 break;
1659
1660 case IRP_MN_STOP_DEVICE:
1661 Status = ISAPNPStopDevice(DeviceObject, Irp, IrpSp);
1662 break;
1663
1664 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
1665 /* Nothing to do here */
1666 DPRINT("IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
1667 Status = Irp->IoStatus.Status;
1668 break;
1669
1670 default:
1671 DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
1672 Status = STATUS_NOT_IMPLEMENTED;
1673 break;
1674 }
1675
1676 if (Status != STATUS_PENDING) {
1677 Irp->IoStatus.Status = Status;
1678 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1679 }
1680
1681 DPRINT("Leaving. Status 0x%X\n", Status);
1682
1683 return Status;
1684 }
1685
1686
1687 static NTSTATUS
1688 NTAPI
1689 ISAPNPAddDevice(
1690 IN PDRIVER_OBJECT DriverObject,
1691 IN PDEVICE_OBJECT PhysicalDeviceObject)
1692 {
1693 PISAPNP_DEVICE_EXTENSION DeviceExtension;
1694 PDEVICE_OBJECT Fdo;
1695 NTSTATUS Status;
1696
1697 DPRINT("Called\n");
1698
1699 Status = IoCreateDevice(DriverObject, sizeof(ISAPNP_DEVICE_EXTENSION),
1700 NULL, FILE_DEVICE_BUS_EXTENDER, FILE_DEVICE_SECURE_OPEN, TRUE, &Fdo);
1701 if (!NT_SUCCESS(Status)) {
1702 DPRINT("IoCreateDevice() failed with status 0x%X\n", Status);
1703 return Status;
1704 }
1705
1706 DeviceExtension = (PISAPNP_DEVICE_EXTENSION)Fdo->DeviceExtension;
1707
1708 DeviceExtension->Pdo = PhysicalDeviceObject;
1709
1710 DeviceExtension->Ldo =
1711 IoAttachDeviceToDeviceStack(Fdo, PhysicalDeviceObject);
1712
1713 InitializeListHead(&DeviceExtension->CardListHead);
1714 InitializeListHead(&DeviceExtension->DeviceListHead);
1715 DeviceExtension->DeviceListCount = 0;
1716 KeInitializeSpinLock(&DeviceExtension->GlobalListLock);
1717
1718 DeviceExtension->State = dsStopped;
1719
1720 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
1721
1722 DPRINT("Done AddDevice\n");
1723
1724 return STATUS_SUCCESS;
1725 }
1726
1727
1728 NTSTATUS
1729 NTAPI
1730 DriverEntry(
1731 IN PDRIVER_OBJECT DriverObject,
1732 IN PUNICODE_STRING RegistryPath)
1733 {
1734 DbgPrint("ISA Plug and Play Bus Driver\n");
1735
1736 DriverObject->MajorFunction[IRP_MJ_CREATE] = ISAPNPDispatchOpenClose;
1737 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ISAPNPDispatchOpenClose;
1738 DriverObject->MajorFunction[IRP_MJ_READ] = ISAPNPDispatchReadWrite;
1739 DriverObject->MajorFunction[IRP_MJ_WRITE] = ISAPNPDispatchReadWrite;
1740 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ISAPNPDispatchDeviceControl;
1741 DriverObject->MajorFunction[IRP_MJ_PNP] = ISAPNPControl;
1742 DriverObject->DriverExtension->AddDevice = ISAPNPAddDevice;
1743
1744 return STATUS_SUCCESS;
1745 }
1746
1747 /* EOF */