migrate substitution keywords to SVN
[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 <ddk/ntddk.h>
12 #include <isapnp.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17
18 #ifdef ALLOC_PRAGMA
19
20 // Make the initialization routines discardable, so that they
21 // don't waste space
22
23 #pragma alloc_text(init, DriverEntry)
24
25 // Make the PASSIVE_LEVEL routines pageable, so that they don't
26 // waste nonpaged memory
27
28 #pragma alloc_text(page, ACPIDispatchOpenClose)
29 #pragma alloc_text(page, ACPIDispatchRead)
30 #pragma alloc_text(page, ACPIDispatchWrite)
31
32 #endif /* ALLOC_PRAGMA */
33
34
35 PUCHAR IsaPnPReadPort;
36
37
38 #define UCHAR2USHORT(v0, v1) \
39 ((v1 << 8) | v0)
40
41 #define UCHAR2ULONG(v0, v1, v2, v3) \
42 ((UCHAR2USHORT(v2, v3) << 16) | UCHAR2USHORT(v0, v1))
43
44
45 #ifndef NDEBUG
46
47 struct
48 {
49 PCH Name;
50 } SmallTags[] = {
51 {"Unknown Small Tag"},
52 {"ISAPNP_SRIN_VERSION"},
53 {"ISAPNP_SRIN_LDEVICE_ID"},
54 {"ISAPNP_SRIN_CDEVICE_ID"},
55 {"ISAPNP_SRIN_IRQ_FORMAT"},
56 {"ISAPNP_SRIN_DMA_FORMAT"},
57 {"ISAPNP_SRIN_START_DFUNCTION"},
58 {"ISAPNP_SRIN_END_DFUNCTION"},
59 {"ISAPNP_SRIN_IO_DESCRIPTOR"},
60 {"ISAPNP_SRIN_FL_IO_DESCRIPOTOR"},
61 {"Reserved Small Tag"},
62 {"Reserved Small Tag"},
63 {"Reserved Small Tag"},
64 {"Reserved Small Tag"},
65 {"ISAPNP_SRIN_VENDOR_DEFINED"},
66 {"ISAPNP_SRIN_END_TAG"}
67 };
68
69 struct
70 {
71 PCH Name;
72 } LargeTags[] = {
73 {"Unknown Large Tag"},
74 {"ISAPNP_LRIN_MEMORY_RANGE"},
75 {"ISAPNP_LRIN_ID_STRING_ANSI"},
76 {"ISAPNP_LRIN_ID_STRING_UNICODE"},
77 {"ISAPNP_LRIN_VENDOR_DEFINED"},
78 {"ISAPNP_LRIN_MEMORY_RANGE32"},
79 {"ISAPNP_LRIN_FL_MEMORY_RANGE32"}
80 };
81
82 PCSZ TagName(ULONG Tag, BOOLEAN Small)
83 {
84 if (Small && (Tag <= ISAPNP_SRIN_END_TAG)) {
85 return SmallTags[Tag].Name;
86 } else if (Tag <= ISAPNP_LRIN_FL_MEMORY_RANGE32){
87 return LargeTags[Tag].Name;
88 }
89
90 return NULL;
91 }
92
93 #endif
94
95 static inline VOID WriteData(UCHAR Value)
96 {
97 WRITE_PORT_UCHAR((PUCHAR)ISAPNP_WRITE_PORT, Value);
98 }
99
100 static inline VOID WriteAddress(UCHAR Value)
101 {
102 WRITE_PORT_UCHAR((PUCHAR)ISAPNP_ADDRESS_PORT, Value);
103 KeStallExecutionProcessor(20);
104 }
105
106 static inline UCHAR ReadData(VOID)
107 {
108 return READ_PORT_UCHAR(IsaPnPReadPort);
109 }
110
111 UCHAR ReadUchar(UCHAR Index)
112 {
113 WriteAddress(Index);
114 return ReadData();
115 }
116
117 USHORT ReadUshort(UCHAR Index)
118 {
119 USHORT Value;
120
121 Value = ReadUchar(Index);
122 Value = (Value << 8) + ReadUchar(Index + 1);
123 return Value;
124 }
125
126 ULONG ReadUlong(UCHAR Index)
127 {
128 ULONG Value;
129
130 Value = ReadUchar(Index);
131 Value = (Value << 8) + ReadUchar(Index + 1);
132 Value = (Value << 8) + ReadUchar(Index + 2);
133 Value = (Value << 8) + ReadUchar(Index + 3);
134 return Value;
135 }
136
137 VOID WriteUchar(UCHAR Index, UCHAR Value)
138 {
139 WriteAddress(Index);
140 WriteData(Value);
141 }
142
143 VOID WriteUshort(UCHAR Index, USHORT Value)
144 {
145 WriteUchar(Index, Value >> 8);
146 WriteUchar(Index + 1, Value);
147 }
148
149 VOID WriteUlong(UCHAR Index, ULONG Value)
150 {
151 WriteUchar(Index, Value >> 24);
152 WriteUchar(Index + 1, Value >> 16);
153 WriteUchar(Index + 2, Value >> 8);
154 WriteUchar(Index + 3, Value);
155 }
156
157 static inline VOID SetReadDataPort(ULONG Port)
158 {
159 IsaPnPReadPort = (PUCHAR)Port;
160 WriteUchar(0x00, Port >> 2);
161 KeStallExecutionProcessor(100);
162 }
163
164 static VOID SendKey(VOID)
165 {
166 ULONG i;
167 UCHAR msb;
168 UCHAR code;
169
170 /* FIXME: Is there something better? */
171 KeStallExecutionProcessor(1000);
172 WriteAddress(0x00);
173 WriteAddress(0x00);
174
175 code = 0x6a;
176 WriteAddress(code);
177 for (i = 1; i < 32; i++) {
178 msb = ((code & 0x01) ^ ((code & 0x02) >> 1)) << 7;
179 code = (code >> 1) | msb;
180 WriteAddress(code);
181 }
182 }
183
184 /* Place all PnP cards in wait-for-key state */
185 static VOID SendWait(VOID)
186 {
187 WriteUchar(0x02, 0x02);
188 }
189
190 VOID SendWake(UCHAR csn)
191 {
192 WriteUchar(ISAPNP_CARD_WAKECSN, csn);
193 }
194
195 VOID SelectLogicalDevice(UCHAR LogicalDevice)
196 {
197 WriteUchar(ISAPNP_CARD_LOG_DEVICE_NUM, LogicalDevice);
198 }
199
200 VOID ActivateLogicalDevice(UCHAR LogicalDevice)
201 {
202 SelectLogicalDevice(LogicalDevice);
203 WriteUchar(ISAPNP_CONTROL_ACTIVATE, 0x1);
204 KeStallExecutionProcessor(250);
205 }
206
207 VOID DeactivateLogicalDevice(UCHAR LogicalDevice)
208 {
209 SelectLogicalDevice(LogicalDevice);
210 WriteUchar(ISAPNP_CONTROL_ACTIVATE, 0x0);
211 KeStallExecutionProcessor(500);
212 }
213
214 #define READ_DATA_PORT_STEP 32 /* Minimum is 4 */
215
216 static ULONG FindNextReadPort(VOID)
217 {
218 ULONG Port;
219
220
221
222 Port = (ULONG)IsaPnPReadPort;
223
224 while (TRUE) {
225
226 Port += READ_DATA_PORT_STEP;
227
228
229
230 if (Port > ISAPNP_MAX_READ_PORT)
231
232 {
233
234 return 0;
235
236 }
237
238
239
240 /*
241
242 * We cannot use NE2000 probe spaces for
243
244 * ISAPnP or we will lock up machines
245
246 */
247
248 if ((Port < 0x280) || (Port > 0x380))
249
250 {
251
252 return Port;
253
254 }
255
256 }
257
258 }
259
260 static BOOLEAN IsolateReadDataPortSelect(VOID)
261 {
262 ULONG Port;
263
264 SendWait();
265 SendKey();
266
267 /* Control: reset CSN and conditionally everything else too */
268 WriteUchar(0x02, 0x05);
269 KeStallExecutionProcessor(2000);
270
271 SendWait();
272 SendKey();
273 SendWake(0x00);
274
275 Port = FindNextReadPort();
276 if (Port == 0) {
277 SendWait();
278 return FALSE;
279 }
280
281 SetReadDataPort(Port);
282 KeStallExecutionProcessor(1000);
283 WriteAddress(0x01);
284 KeStallExecutionProcessor(1000);
285 return TRUE;
286 }
287
288 /*
289 * Isolate (assign uniqued CSN) to all ISA PnP devices
290 */
291 static ULONG IsolatePnPCards(VOID)
292 {
293 UCHAR checksum = 0x6a;
294 UCHAR chksum = 0x00;
295 UCHAR bit = 0x00;
296 ULONG data;
297 ULONG csn = 0;
298 ULONG i;
299 ULONG iteration = 1;
300
301 DPRINT("Called\n");
302
303 IsaPnPReadPort = (PUCHAR)ISAPNP_MIN_READ_PORT;
304 if (!IsolateReadDataPortSelect()) {
305 DPRINT("Could not set read data port\n");
306 return 0;
307 }
308
309 while (TRUE) {
310 for (i = 1; i <= 64; i++) {
311 data = ReadData() << 8;
312 KeStallExecutionProcessor(250);
313 data = data | ReadData();
314 KeStallExecutionProcessor(250);
315 if (data == 0x55aa)
316 bit = 0x01;
317 checksum = ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7) | (checksum >> 1);
318 bit = 0x00;
319 }
320 for (i = 65; i <= 72; i++) {
321 data = ReadData() << 8;
322 KeStallExecutionProcessor(250);
323 data = data | ReadData();
324 KeStallExecutionProcessor(250);
325 if (data == 0x55aa)
326 chksum |= (1 << (i - 65));
327 }
328 if ((checksum != 0x00) && (checksum == chksum)) {
329 csn++;
330
331 WriteUchar(0x06, csn);
332 KeStallExecutionProcessor(250);
333 iteration++;
334 SendWake(0x00);
335 SetReadDataPort((ULONG)IsaPnPReadPort);
336 KeStallExecutionProcessor(1000);
337 WriteAddress(0x01);
338 KeStallExecutionProcessor(1000);
339 goto next;
340 }
341 if (iteration == 1) {
342 IsaPnPReadPort += READ_DATA_PORT_STEP;
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 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
437 DPRINT("Tag = 0x%X, Type = 0x%X, Size = %d (%s)\n",
438 tag, *Type, *Size, TagName(*Type, *Small));
439
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 ExAllocatePool(PagedPool, sizeof(ISAPNP_CONFIGURATION_LIST));
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 ExAllocatePool(PagedPool, sizeof(ISAPNP_DESCRIPTOR));
535 if (!d)
536 return STATUS_NO_MEMORY;
537
538 RtlZeroMemory(d, sizeof(ISAPNP_DESCRIPTOR));
539
540 d->Descriptor.Option = 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)ExAllocatePool(
911 PagedPool, sizeof(ISAPNP_LOGICAL_DEVICE));
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, 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, 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 0x%X\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 0x%X(%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)ExAllocatePool(
1290 PagedPool, ListSize);
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(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)ExAllocatePool(
1392 PagedPool, sizeof(ISAPNP_CARD));
1393 if (!Card)
1394 return STATUS_INSUFFICIENT_RESOURCES;
1395
1396 RtlZeroMemory(Card, sizeof(ISAPNP_CARD));
1397
1398 Card->CardId = 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 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)ExAllocatePool(PagedPool, Size);
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 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 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 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 NTSTATUS
1575 STDCALL
1576 ISAPNPDispatchOpenClose(
1577 IN PDEVICE_OBJECT DeviceObject,
1578 IN PIRP Irp)
1579 {
1580 DPRINT("Called\n");
1581
1582 Irp->IoStatus.Status = STATUS_SUCCESS;
1583 Irp->IoStatus.Information = FILE_OPENED;
1584 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1585
1586 return STATUS_SUCCESS;
1587 }
1588
1589
1590 NTSTATUS
1591 STDCALL
1592 ISAPNPDispatchReadWrite(
1593 IN PDEVICE_OBJECT PhysicalDeviceObject,
1594 IN PIRP Irp)
1595 {
1596 DPRINT("Called\n");
1597
1598 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
1599 Irp->IoStatus.Information = 0;
1600 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1601
1602 return STATUS_UNSUCCESSFUL;
1603 }
1604
1605
1606 NTSTATUS
1607 STDCALL
1608 ISAPNPDispatchDeviceControl(
1609 IN PDEVICE_OBJECT DeviceObject,
1610 IN PIRP Irp)
1611 {
1612 PIO_STACK_LOCATION IrpSp;
1613 NTSTATUS Status;
1614
1615 DPRINT("Called\n");
1616
1617 Irp->IoStatus.Information = 0;
1618
1619 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1620 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
1621 default:
1622 DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
1623 Status = STATUS_NOT_IMPLEMENTED;
1624 break;
1625 }
1626
1627 if (Status != STATUS_PENDING) {
1628 Irp->IoStatus.Status = Status;
1629 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1630 }
1631
1632 DPRINT("Leaving. Status 0x%X\n", Status);
1633
1634 return Status;
1635 }
1636
1637
1638 NTSTATUS
1639 STDCALL
1640 ISAPNPControl(
1641 IN PDEVICE_OBJECT DeviceObject,
1642 IN PIRP Irp)
1643 {
1644 PIO_STACK_LOCATION IrpSp;
1645 NTSTATUS Status;
1646
1647 DPRINT("Called\n");
1648
1649 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1650 switch (IrpSp->MinorFunction) {
1651 case IRP_MN_QUERY_DEVICE_RELATIONS:
1652 Status = ISAPNPQueryDeviceRelations(DeviceObject, Irp, IrpSp);
1653 break;
1654
1655 case IRP_MN_START_DEVICE:
1656 Status = ISAPNPStartDevice(DeviceObject, Irp, IrpSp);
1657 break;
1658
1659 case IRP_MN_STOP_DEVICE:
1660 Status = ISAPNPStopDevice(DeviceObject, Irp, IrpSp);
1661 break;
1662
1663 default:
1664 DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
1665 Status = STATUS_NOT_IMPLEMENTED;
1666 break;
1667 }
1668
1669 if (Status != STATUS_PENDING) {
1670 Irp->IoStatus.Status = Status;
1671 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1672 }
1673
1674 DPRINT("Leaving. Status 0x%X\n", Status);
1675
1676 return Status;
1677 }
1678
1679
1680 NTSTATUS
1681 STDCALL
1682 ISAPNPAddDevice(
1683 IN PDRIVER_OBJECT DriverObject,
1684 IN PDEVICE_OBJECT PhysicalDeviceObject)
1685 {
1686 PISAPNP_DEVICE_EXTENSION DeviceExtension;
1687 PDEVICE_OBJECT Fdo;
1688 NTSTATUS Status;
1689
1690 DPRINT("Called\n");
1691
1692 Status = IoCreateDevice(DriverObject, sizeof(ISAPNP_DEVICE_EXTENSION),
1693 NULL, FILE_DEVICE_BUS_EXTENDER, FILE_DEVICE_SECURE_OPEN, TRUE, &Fdo);
1694 if (!NT_SUCCESS(Status)) {
1695 DPRINT("IoCreateDevice() failed with status 0x%X\n", Status);
1696 return Status;
1697 }
1698
1699 DeviceExtension = (PISAPNP_DEVICE_EXTENSION)Fdo->DeviceExtension;
1700
1701 DeviceExtension->Pdo = PhysicalDeviceObject;
1702
1703 DeviceExtension->Ldo =
1704 IoAttachDeviceToDeviceStack(Fdo, PhysicalDeviceObject);
1705
1706 InitializeListHead(&DeviceExtension->CardListHead);
1707 InitializeListHead(&DeviceExtension->DeviceListHead);
1708 DeviceExtension->DeviceListCount = 0;
1709 KeInitializeSpinLock(&DeviceExtension->GlobalListLock);
1710
1711 DeviceExtension->State = dsStopped;
1712
1713 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
1714
1715 DPRINT("Done AddDevice\n");
1716
1717 return STATUS_SUCCESS;
1718 }
1719
1720
1721 NTSTATUS
1722 STDCALL
1723 DriverEntry(
1724 IN PDRIVER_OBJECT DriverObject,
1725 IN PUNICODE_STRING RegistryPath)
1726 {
1727 DbgPrint("ISA Plug and Play Bus Driver\n");
1728
1729 DriverObject->MajorFunction[IRP_MJ_CREATE] = ISAPNPDispatchOpenClose;
1730 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ISAPNPDispatchOpenClose;
1731 DriverObject->MajorFunction[IRP_MJ_READ] = ISAPNPDispatchReadWrite;
1732 DriverObject->MajorFunction[IRP_MJ_WRITE] = ISAPNPDispatchReadWrite;
1733 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ISAPNPDispatchDeviceControl;
1734 DriverObject->MajorFunction[IRP_MJ_PNP] = ISAPNPControl;
1735 DriverObject->DriverExtension->AddDevice = ISAPNPAddDevice;
1736
1737 return STATUS_SUCCESS;
1738 }
1739
1740 /* EOF */