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