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