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