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