xref: /reactos/drivers/bus/isapnp/isapnp.c (revision 9df05ba4)
1 /*
2  * PROJECT:         ReactOS ISA PnP Bus driver
3  * FILE:            isapnp.c
4  * PURPOSE:         Driver entry
5  * PROGRAMMERS:     Cameron Gutman (cameron.gutman@reactos.org)
6  *                  Hervé Poussineau
7  */
8 
9 #include <isapnp.h>
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 NTSTATUS
15 NTAPI
16 IsaPnpDuplicateUnicodeString(
17     IN ULONG Flags,
18     IN PCUNICODE_STRING SourceString,
19     OUT PUNICODE_STRING DestinationString)
20 {
21     if (SourceString == NULL ||
22         DestinationString == NULL ||
23         SourceString->Length > SourceString->MaximumLength ||
24         (SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL) ||
25         Flags == RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING ||
26         Flags >= 4)
27     {
28         return STATUS_INVALID_PARAMETER;
29     }
30 
31     if ((SourceString->Length == 0) &&
32         (Flags != (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
33                    RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)))
34     {
35         DestinationString->Length = 0;
36         DestinationString->MaximumLength = 0;
37         DestinationString->Buffer = NULL;
38     }
39     else
40     {
41         USHORT DestMaxLength = SourceString->Length;
42 
43         if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
44             DestMaxLength += sizeof(UNICODE_NULL);
45 
46         DestinationString->Buffer = ExAllocatePool(PagedPool, DestMaxLength);
47         if (DestinationString->Buffer == NULL)
48             return STATUS_NO_MEMORY;
49 
50         RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length);
51         DestinationString->Length = SourceString->Length;
52         DestinationString->MaximumLength = DestMaxLength;
53 
54         if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
55             DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0;
56     }
57 
58     return STATUS_SUCCESS;
59 }
60 
61 static
62 NTSTATUS
63 NTAPI
64 IsaFdoCreateDeviceIDs(
65     IN PISAPNP_PDO_EXTENSION PdoExt)
66 {
67     PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice;
68     UNICODE_STRING TempString;
69     WCHAR TempBuffer[256];
70     PWCHAR End;
71     NTSTATUS Status;
72     USHORT i;
73 
74     TempString.Buffer = TempBuffer;
75     TempString.MaximumLength = sizeof(TempBuffer);
76     TempString.Length = 0;
77 
78     /* Device ID */
79     Status = RtlStringCbPrintfExW(TempString.Buffer,
80                                   TempString.MaximumLength / sizeof(WCHAR),
81                                   &End,
82                                   NULL, 0,
83                                   L"ISAPNP\\%.3S%04x",
84                                   LogDev->VendorId,
85                                   LogDev->ProdId);
86     if (!NT_SUCCESS(Status))
87         return Status;
88     TempString.Length = (USHORT)((End - TempString.Buffer) * sizeof(WCHAR));
89     Status = IsaPnpDuplicateUnicodeString(
90         RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
91         &TempString,
92         &PdoExt->DeviceID);
93     if (!NT_SUCCESS(Status))
94         return Status;
95 
96     /* HardwareIDs */
97     Status = RtlStringCbPrintfExW(TempString.Buffer,
98                                   TempString.MaximumLength / sizeof(WCHAR),
99                                   &End,
100                                   NULL, 0,
101                                   L"ISAPNP\\%.3S%04x@"
102                                   L"*%.3S%04x@",
103                                   LogDev->VendorId,
104                                   LogDev->ProdId,
105                                   LogDev->VendorId,
106                                   LogDev->ProdId);
107     if (!NT_SUCCESS(Status))
108         return Status;
109     TempString.Length = (USHORT)((End - TempString.Buffer) * sizeof(WCHAR));
110     Status = IsaPnpDuplicateUnicodeString(
111         RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
112         &TempString,
113         &PdoExt->HardwareIDs);
114     if (!NT_SUCCESS(Status))
115         return Status;
116     for (i = 0; i < PdoExt->HardwareIDs.Length / sizeof(WCHAR); i++)
117         if (PdoExt->HardwareIDs.Buffer[i] == '@')
118             PdoExt->HardwareIDs.Buffer[i] = UNICODE_NULL;
119 
120     /* InstanceID */
121     Status = RtlStringCbPrintfExW(TempString.Buffer,
122                                   TempString.MaximumLength / sizeof(WCHAR),
123                                   &End,
124                                   NULL, 0,
125                                   L"%X",
126                                   LogDev->SerialNumber);
127     if (!NT_SUCCESS(Status))
128         return Status;
129     TempString.Length = (USHORT)((End - TempString.Buffer) * sizeof(WCHAR));
130     Status = IsaPnpDuplicateUnicodeString(
131         RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
132         &TempString,
133         &PdoExt->InstanceID);
134     if (!NT_SUCCESS(Status))
135         return Status;
136 
137     return STATUS_SUCCESS;
138 }
139 
140 static
141 NTSTATUS
142 NTAPI
143 IsaFdoCreateRequirements(
144     IN PISAPNP_PDO_EXTENSION PdoExt)
145 {
146     PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice;
147     RTL_BITMAP IrqBitmap[ARRAYSIZE(LogDev->Irq)];
148     RTL_BITMAP DmaBitmap[ARRAYSIZE(LogDev->Dma)];
149     ULONG IrqData[ARRAYSIZE(LogDev->Irq)];
150     ULONG DmaData[ARRAYSIZE(LogDev->Dma)];
151     ULONG ResourceCount = 0;
152     ULONG ListSize, i, j;
153     BOOLEAN FirstIrq = TRUE, FirstDma = TRUE;
154     PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
155     PIO_RESOURCE_DESCRIPTOR Descriptor;
156 
157     /* Count number of requirements */
158     for (i = 0; i < ARRAYSIZE(LogDev->Io); i++)
159     {
160         if (!LogDev->Io[i].Description.Length)
161             break;
162         ResourceCount++;
163     }
164     for (i = 0; i < ARRAYSIZE(LogDev->Irq); i++)
165     {
166         if (!LogDev->Irq[i].Description.Mask)
167             break;
168         IrqData[i] = LogDev->Irq[i].Description.Mask;
169         RtlInitializeBitMap(&IrqBitmap[i], &IrqData[i], 16);
170         ResourceCount += RtlNumberOfSetBits(&IrqBitmap[i]);
171         if (LogDev->Irq[i].Description.Information & 0x4)
172         {
173             /* Add room for level sensitive */
174             ResourceCount += RtlNumberOfSetBits(&IrqBitmap[i]);
175         }
176     }
177     if (ResourceCount == 0)
178         return STATUS_SUCCESS;
179     for (i = 0; i < ARRAYSIZE(LogDev->Irq); i++)
180     {
181         if (!LogDev->Dma[i].Description.Mask)
182             break;
183         DmaData[i] = LogDev->Dma[i].Description.Mask;
184         RtlInitializeBitMap(&DmaBitmap[i], &DmaData[i], 8);
185         ResourceCount += RtlNumberOfSetBits(&DmaBitmap[i]);
186     }
187 
188     /* Allocate memory to store requirements */
189     ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST)
190              + ResourceCount * sizeof(IO_RESOURCE_DESCRIPTOR);
191     RequirementsList = ExAllocatePool(PagedPool, ListSize);
192     if (!RequirementsList)
193         return STATUS_NO_MEMORY;
194 
195     RtlZeroMemory(RequirementsList, ListSize);
196     RequirementsList->ListSize = ListSize;
197     RequirementsList->InterfaceType = Isa;
198     RequirementsList->AlternativeLists = 1;
199 
200     RequirementsList->List[0].Version = 1;
201     RequirementsList->List[0].Revision = 1;
202     RequirementsList->List[0].Count = ResourceCount;
203 
204     /* Store requirements */
205     Descriptor = RequirementsList->List[0].Descriptors;
206     for (i = 0; i < ARRAYSIZE(LogDev->Io); i++)
207     {
208         if (!LogDev->Io[i].Description.Length)
209             break;
210         DPRINT("Device.Io[%d].Information = 0x%02x\n", i, LogDev->Io[i].Description.Information);
211         DPRINT("Device.Io[%d].Minimum = 0x%02x\n", i, LogDev->Io[i].Description.Minimum);
212         DPRINT("Device.Io[%d].Maximum = 0x%02x\n", i, LogDev->Io[i].Description.Maximum);
213         DPRINT("Device.Io[%d].Alignment = 0x%02x\n", i, LogDev->Io[i].Description.Alignment);
214         DPRINT("Device.Io[%d].Length = 0x%02x\n", i, LogDev->Io[i].Description.Length);
215         Descriptor->Type = CmResourceTypePort;
216         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
217         if (LogDev->Io[i].Description.Information & 0x1)
218             Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
219         else
220             Descriptor->Flags = CM_RESOURCE_PORT_10_BIT_DECODE;
221         Descriptor->u.Port.Length = LogDev->Io[i].Description.Length;
222         Descriptor->u.Port.Alignment = LogDev->Io[i].Description.Alignment;
223         Descriptor->u.Port.MinimumAddress.LowPart = LogDev->Io[i].Description.Minimum;
224         Descriptor->u.Port.MaximumAddress.LowPart = LogDev->Io[i].Description.Maximum + LogDev->Io[i].Description.Length - 1;
225         Descriptor++;
226     }
227     for (i = 0; i < ARRAYSIZE(LogDev->Irq); i++)
228     {
229         if (!LogDev->Irq[i].Description.Mask)
230             break;
231         DPRINT("Device.Irq[%d].Mask = 0x%02x\n", i, LogDev->Irq[i].Description.Mask);
232         DPRINT("Device.Irq[%d].Information = 0x%02x\n", i, LogDev->Irq[i].Description.Information);
233         for (j = 0; j < 15; j++)
234         {
235             if (!RtlCheckBit(&IrqBitmap[i], j))
236                 continue;
237             if (FirstIrq)
238                 FirstIrq = FALSE;
239             else
240                 Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
241             Descriptor->Type = CmResourceTypeInterrupt;
242             Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
243             Descriptor->u.Interrupt.MinimumVector = Descriptor->u.Interrupt.MaximumVector = j;
244             Descriptor++;
245             if (LogDev->Irq[i].Description.Information & 0x4)
246             {
247                 /* Level interrupt */
248                 Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
249                 Descriptor->Type = CmResourceTypeInterrupt;
250                 Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
251                 Descriptor->u.Interrupt.MinimumVector = Descriptor->u.Interrupt.MaximumVector = j;
252                 Descriptor++;
253             }
254         }
255     }
256     for (i = 0; i < ARRAYSIZE(LogDev->Dma); i++)
257     {
258         if (!LogDev->Dma[i].Description.Mask)
259             break;
260         DPRINT("Device.Dma[%d].Mask = 0x%02x\n", i, LogDev->Dma[i].Description.Mask);
261         DPRINT("Device.Dma[%d].Information = 0x%02x\n", i, LogDev->Dma[i].Description.Information);
262         for (j = 0; j < 8; j++)
263         {
264             if (!RtlCheckBit(&DmaBitmap[i], j))
265                 continue;
266             if (FirstDma)
267                 FirstDma = FALSE;
268             else
269                 Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
270             Descriptor->Type = CmResourceTypeDma;
271             switch (LogDev->Dma[i].Description.Information & 0x3)
272             {
273                 case 0x0: Descriptor->Flags |= CM_RESOURCE_DMA_8; break;
274                 case 0x1: Descriptor->Flags |= CM_RESOURCE_DMA_8_AND_16; break;
275                 case 0x2: Descriptor->Flags |= CM_RESOURCE_DMA_16; break;
276                 default: break;
277             }
278             if (LogDev->Dma[i].Description.Information & 0x4)
279                 Descriptor->Flags |= CM_RESOURCE_DMA_BUS_MASTER;
280             switch ((LogDev->Dma[i].Description.Information >> 5) & 0x3)
281             {
282                 case 0x1: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_A; break;
283                 case 0x2: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_B; break;
284                 case 0x3: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_F; break;
285                 default: break;
286             }
287             Descriptor->u.Dma.MinimumChannel = Descriptor->u.Dma.MaximumChannel = j;
288             Descriptor++;
289         }
290     }
291 
292     PdoExt->RequirementsList = RequirementsList;
293     return STATUS_SUCCESS;
294 }
295 
296 static
297 NTSTATUS
298 NTAPI
299 IsaFdoCreateResources(
300     IN PISAPNP_PDO_EXTENSION PdoExt)
301 {
302     PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice;
303     ULONG ResourceCount = 0;
304     ULONG ListSize, i;
305     PCM_RESOURCE_LIST ResourceList;
306     PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
307 
308     /* Count number of required resources */
309     for (i = 0; i < ARRAYSIZE(LogDev->Io); i++)
310     {
311         if (LogDev->Io[i].CurrentBase)
312             ResourceCount++;
313         else
314             break;
315     }
316     for (i = 0; i < ARRAYSIZE(LogDev->Irq); i++)
317     {
318         if (LogDev->Irq[i].CurrentNo)
319             ResourceCount++;
320         else
321             break;
322     }
323     for (i = 0; i < ARRAYSIZE(LogDev->Dma); i++)
324     {
325         if (LogDev->Dma[i].CurrentChannel != 4)
326             ResourceCount++;
327         else
328             break;
329     }
330     if (ResourceCount == 0)
331         return STATUS_SUCCESS;
332 
333     /* Allocate memory to store resources */
334     ListSize = sizeof(CM_RESOURCE_LIST)
335              + (ResourceCount - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
336     ResourceList = ExAllocatePool(PagedPool, ListSize);
337     if (!ResourceList)
338         return STATUS_NO_MEMORY;
339 
340     RtlZeroMemory(ResourceList, ListSize);
341     ResourceList->Count = 1;
342     ResourceList->List[0].InterfaceType = Isa;
343     ResourceList->List[0].PartialResourceList.Version = 1;
344     ResourceList->List[0].PartialResourceList.Revision = 1;
345     ResourceList->List[0].PartialResourceList.Count = ResourceCount;
346 
347     /* Store resources */
348     ResourceCount = 0;
349     for (i = 0; i < ARRAYSIZE(LogDev->Io); i++)
350     {
351         if (!LogDev->Io[i].CurrentBase)
352             continue;
353         Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++];
354         Descriptor->Type = CmResourceTypePort;
355         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
356         if (LogDev->Io[i].Description.Information & 0x1)
357             Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
358         else
359             Descriptor->Flags = CM_RESOURCE_PORT_10_BIT_DECODE;
360         Descriptor->u.Port.Length = LogDev->Io[i].Description.Length;
361         Descriptor->u.Port.Start.LowPart = LogDev->Io[i].CurrentBase;
362     }
363     for (i = 0; i < ARRAYSIZE(LogDev->Irq); i++)
364     {
365         if (!LogDev->Irq[i].CurrentNo)
366             continue;
367         Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++];
368         Descriptor->Type = CmResourceTypeInterrupt;
369         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
370         if (LogDev->Irq[i].CurrentType & 0x01)
371             Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
372         else
373             Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
374         Descriptor->u.Interrupt.Level = LogDev->Irq[i].CurrentNo;
375         Descriptor->u.Interrupt.Vector = LogDev->Irq[i].CurrentNo;
376         Descriptor->u.Interrupt.Affinity = -1;
377     }
378     for (i = 0; i < ARRAYSIZE(LogDev->Dma); i++)
379     {
380         if (LogDev->Dma[i].CurrentChannel == 4)
381             continue;
382         Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++];
383         Descriptor->Type = CmResourceTypeDma;
384         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
385         switch (LogDev->Dma[i].Description.Information & 0x3)
386         {
387             case 0x0: Descriptor->Flags |= CM_RESOURCE_DMA_8; break;
388             case 0x1: Descriptor->Flags |= CM_RESOURCE_DMA_8 | CM_RESOURCE_DMA_16; break;
389             case 0x2: Descriptor->Flags |= CM_RESOURCE_DMA_16; break;
390             default: break;
391         }
392         if (LogDev->Dma[i].Description.Information & 0x4)
393             Descriptor->Flags |= CM_RESOURCE_DMA_BUS_MASTER;
394         switch ((LogDev->Dma[i].Description.Information >> 5) & 0x3)
395         {
396             case 0x1: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_A; break;
397             case 0x2: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_B; break;
398             case 0x3: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_F; break;
399             default: break;
400         }
401         Descriptor->u.Dma.Channel = LogDev->Dma[i].CurrentChannel;
402     }
403 
404     PdoExt->ResourceList = ResourceList;
405     PdoExt->ResourceListSize = ListSize;
406     return STATUS_SUCCESS;
407 }
408 
409 NTSTATUS
410 NTAPI
411 IsaPnpFillDeviceRelations(
412     IN PISAPNP_FDO_EXTENSION FdoExt,
413     IN PIRP Irp,
414     IN BOOLEAN IncludeDataPort)
415 {
416     PISAPNP_PDO_EXTENSION PdoExt;
417     NTSTATUS Status = STATUS_SUCCESS;
418     PLIST_ENTRY CurrentEntry;
419     PISAPNP_LOGICAL_DEVICE IsaDevice;
420     PDEVICE_RELATIONS DeviceRelations;
421     ULONG i = 0;
422 
423     DeviceRelations = ExAllocatePool(NonPagedPool,
424                                      sizeof(DEVICE_RELATIONS) + sizeof(DEVICE_OBJECT) * FdoExt->DeviceCount);
425     if (!DeviceRelations)
426     {
427         return STATUS_NO_MEMORY;
428     }
429 
430     if (IncludeDataPort)
431     {
432         DeviceRelations->Objects[i++] = FdoExt->DataPortPdo;
433         ObReferenceObject(FdoExt->DataPortPdo);
434     }
435 
436     CurrentEntry = FdoExt->DeviceListHead.Flink;
437     while (CurrentEntry != &FdoExt->DeviceListHead)
438     {
439        IsaDevice = CONTAINING_RECORD(CurrentEntry, ISAPNP_LOGICAL_DEVICE, ListEntry);
440 
441        if (!IsaDevice->Pdo)
442        {
443            Status = IoCreateDevice(FdoExt->DriverObject,
444                                    sizeof(ISAPNP_PDO_EXTENSION),
445                                    NULL,
446                                    FILE_DEVICE_CONTROLLER,
447                                    FILE_DEVICE_SECURE_OPEN | FILE_AUTOGENERATED_DEVICE_NAME,
448                                    FALSE,
449                                    &IsaDevice->Pdo);
450            if (!NT_SUCCESS(Status))
451            {
452               break;
453            }
454 
455            IsaDevice->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
456 
457            //Device->Pdo->Flags |= DO_POWER_PAGABLE;
458 
459            PdoExt = (PISAPNP_PDO_EXTENSION)IsaDevice->Pdo->DeviceExtension;
460 
461            RtlZeroMemory(PdoExt, sizeof(ISAPNP_PDO_EXTENSION));
462 
463            PdoExt->Common.IsFdo = FALSE;
464            PdoExt->Common.Self = IsaDevice->Pdo;
465            PdoExt->Common.State = dsStopped;
466            PdoExt->IsaPnpDevice = IsaDevice;
467            PdoExt->FdoExt = FdoExt;
468 
469            Status = IsaFdoCreateDeviceIDs(PdoExt);
470 
471            if (NT_SUCCESS(Status))
472               Status = IsaFdoCreateRequirements(PdoExt);
473 
474            if (NT_SUCCESS(Status))
475               Status = IsaFdoCreateResources(PdoExt);
476 
477            if (!NT_SUCCESS(Status))
478            {
479                IoDeleteDevice(IsaDevice->Pdo);
480                IsaDevice->Pdo = NULL;
481                break;
482            }
483        }
484        DeviceRelations->Objects[i++] = IsaDevice->Pdo;
485 
486        ObReferenceObject(IsaDevice->Pdo);
487 
488        CurrentEntry = CurrentEntry->Flink;
489     }
490 
491     DeviceRelations->Count = i;
492 
493     Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
494 
495     return Status;
496 }
497 
498 
499 static IO_COMPLETION_ROUTINE ForwardIrpCompletion;
500 
501 static
502 NTSTATUS
503 NTAPI
504 ForwardIrpCompletion(
505     IN PDEVICE_OBJECT DeviceObject,
506     IN PIRP Irp,
507     IN PVOID Context)
508 {
509     UNREFERENCED_PARAMETER(DeviceObject);
510 
511     if (Irp->PendingReturned)
512         KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
513 
514     return STATUS_MORE_PROCESSING_REQUIRED;
515 }
516 
517 NTSTATUS
518 NTAPI
519 IsaForwardIrpSynchronous(
520     IN PISAPNP_FDO_EXTENSION FdoExt,
521     IN PIRP Irp)
522 {
523     KEVENT Event;
524     NTSTATUS Status;
525 
526     KeInitializeEvent(&Event, NotificationEvent, FALSE);
527     IoCopyCurrentIrpStackLocationToNext(Irp);
528 
529     IoSetCompletionRoutine(Irp, ForwardIrpCompletion, &Event, TRUE, TRUE, TRUE);
530 
531     Status = IoCallDriver(FdoExt->Ldo, Irp);
532     if (Status == STATUS_PENDING)
533     {
534         Status = KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
535         if (NT_SUCCESS(Status))
536             Status = Irp->IoStatus.Status;
537     }
538 
539     return Status;
540 }
541 
542 static DRIVER_DISPATCH IsaCreateClose;
543 
544 static
545 NTSTATUS
546 NTAPI
547 IsaCreateClose(
548     IN PDEVICE_OBJECT DeviceObject,
549     IN PIRP Irp)
550 {
551     Irp->IoStatus.Status = STATUS_SUCCESS;
552     Irp->IoStatus.Information = FILE_OPENED;
553 
554     DPRINT("%s(%p, %p)\n", __FUNCTION__, DeviceObject, Irp);
555 
556     IoCompleteRequest(Irp, IO_NO_INCREMENT);
557 
558     return STATUS_SUCCESS;
559 }
560 
561 static DRIVER_DISPATCH IsaIoctl;
562 
563 static
564 NTSTATUS
565 NTAPI
566 IsaIoctl(
567     IN PDEVICE_OBJECT DeviceObject,
568     IN PIRP Irp)
569 {
570     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
571     NTSTATUS Status;
572 
573     DPRINT("%s(%p, %p)\n", __FUNCTION__, DeviceObject, Irp);
574 
575     switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
576     {
577         default:
578             DPRINT1("Unknown ioctl code: %x\n", IrpSp->Parameters.DeviceIoControl.IoControlCode);
579             Status = STATUS_NOT_SUPPORTED;
580             break;
581     }
582 
583     Irp->IoStatus.Status = Status;
584     IoCompleteRequest(Irp, IO_NO_INCREMENT);
585 
586     return Status;
587 }
588 
589 static DRIVER_DISPATCH IsaReadWrite;
590 
591 static
592 NTSTATUS
593 NTAPI
594 IsaReadWrite(
595     IN PDEVICE_OBJECT DeviceObject,
596     IN PIRP Irp)
597 {
598     DPRINT("%s(%p, %p)\n", __FUNCTION__, DeviceObject, Irp);
599 
600     Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
601     Irp->IoStatus.Information = 0;
602 
603     IoCompleteRequest(Irp, IO_NO_INCREMENT);
604 
605     return STATUS_NOT_SUPPORTED;
606 }
607 
608 static
609 NTSTATUS
610 NTAPI
611 IsaPnpCreateReadPortDORequirements(
612     IN PISAPNP_PDO_EXTENSION PdoExt)
613 {
614     USHORT Ports[] = { ISAPNP_WRITE_DATA, ISAPNP_ADDRESS, 0x274, 0x3e4, 0x204, 0x2e4, 0x354, 0x2f4 };
615     ULONG ListSize, i;
616     PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
617     PIO_RESOURCE_DESCRIPTOR Descriptor;
618 
619     ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST)
620              + 2 * ARRAYSIZE(Ports) * sizeof(IO_RESOURCE_DESCRIPTOR);
621     RequirementsList = ExAllocatePool(PagedPool, ListSize);
622     if (!RequirementsList)
623         return STATUS_NO_MEMORY;
624 
625     RtlZeroMemory(RequirementsList, ListSize);
626     RequirementsList->ListSize = ListSize;
627     RequirementsList->AlternativeLists = 1;
628 
629     RequirementsList->List[0].Version = 1;
630     RequirementsList->List[0].Revision = 1;
631     RequirementsList->List[0].Count = 2 * ARRAYSIZE(Ports);
632 
633     for (i = 0; i < 2 * ARRAYSIZE(Ports); i += 2)
634     {
635         Descriptor = &RequirementsList->List[0].Descriptors[i];
636 
637         /* Expected port */
638         Descriptor[0].Type = CmResourceTypePort;
639         Descriptor[0].ShareDisposition = CmResourceShareDeviceExclusive;
640         Descriptor[0].Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
641         Descriptor[0].u.Port.Length = Ports[i / 2] & 1 ? 0x01 : 0x04;
642         Descriptor[0].u.Port.Alignment = 0x01;
643         Descriptor[0].u.Port.MinimumAddress.LowPart = Ports[i / 2];
644         Descriptor[0].u.Port.MaximumAddress.LowPart = Ports[i / 2] + Descriptor[0].u.Port.Length - 1;
645 
646         /* ... but mark it as optional */
647         Descriptor[1].Option = IO_RESOURCE_ALTERNATIVE;
648         Descriptor[1].Type = CmResourceTypePort;
649         Descriptor[1].ShareDisposition = CmResourceShareDeviceExclusive;
650         Descriptor[1].Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
651         Descriptor[1].u.Port.Alignment = 0x01;
652     }
653 
654     PdoExt->RequirementsList = RequirementsList;
655     return STATUS_SUCCESS;
656 }
657 
658 static
659 NTSTATUS
660 NTAPI
661 IsaPnpCreateReadPortDOResources(
662     IN PISAPNP_PDO_EXTENSION PdoExt)
663 {
664     USHORT Ports[] = { ISAPNP_WRITE_DATA, ISAPNP_ADDRESS };
665     ULONG ListSize, i;
666     PCM_RESOURCE_LIST ResourceList;
667     PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
668 
669     ListSize = sizeof(CM_RESOURCE_LIST)
670              + (ARRAYSIZE(Ports) - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
671     ResourceList = ExAllocatePool(PagedPool, ListSize);
672     if (!ResourceList)
673         return STATUS_NO_MEMORY;
674 
675     RtlZeroMemory(ResourceList, ListSize);
676     ResourceList->Count = 1;
677     ResourceList->List[0].InterfaceType = Internal;
678     ResourceList->List[0].PartialResourceList.Version = 1;
679     ResourceList->List[0].PartialResourceList.Revision = 1;
680     ResourceList->List[0].PartialResourceList.Count = 2;
681 
682     for (i = 0; i < ARRAYSIZE(Ports); i++)
683     {
684         Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[i];
685         Descriptor->Type = CmResourceTypePort;
686         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
687         Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
688         Descriptor->u.Port.Length = 0x01;
689         Descriptor->u.Port.Start.LowPart = Ports[i];
690     }
691 
692     PdoExt->ResourceList = ResourceList;
693     PdoExt->ResourceListSize = ListSize;
694     return STATUS_SUCCESS;
695 }
696 
697 static
698 NTSTATUS
699 NTAPI
700 IsaPnpCreateReadPortDO(PISAPNP_FDO_EXTENSION FdoExt)
701 {
702     UNICODE_STRING DeviceID = RTL_CONSTANT_STRING(L"ISAPNP\\ReadDataPort\0");
703     UNICODE_STRING HardwareIDs = RTL_CONSTANT_STRING(L"ISAPNP\\ReadDataPort\0\0");
704     UNICODE_STRING CompatibleIDs = RTL_CONSTANT_STRING(L"\0\0");
705     UNICODE_STRING InstanceID = RTL_CONSTANT_STRING(L"0\0");
706     PISAPNP_PDO_EXTENSION PdoExt;
707 
708     NTSTATUS Status;
709     Status = IoCreateDevice(FdoExt->DriverObject,
710                             sizeof(ISAPNP_PDO_EXTENSION),
711                             NULL,
712                             FILE_DEVICE_CONTROLLER,
713                             FILE_DEVICE_SECURE_OPEN,
714                             FALSE,
715                             &FdoExt->DataPortPdo);
716     if (!NT_SUCCESS(Status))
717         return Status;
718     PdoExt = (PISAPNP_PDO_EXTENSION)FdoExt->DataPortPdo->DeviceExtension;
719     RtlZeroMemory(PdoExt, sizeof(ISAPNP_PDO_EXTENSION));
720     PdoExt->Common.IsFdo = FALSE;
721     PdoExt->Common.Self = FdoExt->DataPortPdo;
722     PdoExt->Common.State = dsStopped;
723     PdoExt->FdoExt = FdoExt;
724 
725     Status = IsaPnpDuplicateUnicodeString(0,
726                                           &DeviceID,
727                                           &PdoExt->DeviceID);
728     if (!NT_SUCCESS(Status))
729         return Status;
730 
731     Status = IsaPnpDuplicateUnicodeString(0,
732                                           &HardwareIDs,
733                                           &PdoExt->HardwareIDs);
734     if (!NT_SUCCESS(Status))
735         return Status;
736 
737     Status = IsaPnpDuplicateUnicodeString(0,
738                                           &CompatibleIDs,
739                                           &PdoExt->CompatibleIDs);
740     if (!NT_SUCCESS(Status))
741         return Status;
742 
743     Status = IsaPnpDuplicateUnicodeString(0,
744                                           &InstanceID,
745                                           &PdoExt->InstanceID);
746     if (!NT_SUCCESS(Status))
747         return Status;
748 
749     Status = IsaPnpCreateReadPortDORequirements(PdoExt);
750     if (!NT_SUCCESS(Status))
751         return Status;
752 
753     Status = IsaPnpCreateReadPortDOResources(PdoExt);
754     if (!NT_SUCCESS(Status))
755         return Status;
756 
757     return Status;
758 }
759 
760 static
761 NTSTATUS
762 NTAPI
763 IsaAddDevice(
764     IN PDRIVER_OBJECT DriverObject,
765     IN PDEVICE_OBJECT PhysicalDeviceObject)
766 {
767     PDEVICE_OBJECT Fdo;
768     PISAPNP_FDO_EXTENSION FdoExt;
769     NTSTATUS Status;
770 
771     DPRINT("%s(%p, %p)\n", __FUNCTION__, DriverObject, PhysicalDeviceObject);
772 
773     Status = IoCreateDevice(DriverObject,
774                             sizeof(*FdoExt),
775                             NULL,
776                             FILE_DEVICE_BUS_EXTENDER,
777                             FILE_DEVICE_SECURE_OPEN,
778                             TRUE,
779                             &Fdo);
780     if (!NT_SUCCESS(Status))
781     {
782         DPRINT1("Failed to create FDO (0x%x)\n", Status);
783         return Status;
784     }
785 
786     FdoExt = Fdo->DeviceExtension;
787     RtlZeroMemory(FdoExt, sizeof(*FdoExt));
788 
789     FdoExt->Common.Self = Fdo;
790     FdoExt->Common.IsFdo = TRUE;
791     FdoExt->Common.State = dsStopped;
792     FdoExt->DriverObject = DriverObject;
793     FdoExt->Pdo = PhysicalDeviceObject;
794     FdoExt->Ldo = IoAttachDeviceToDeviceStack(Fdo,
795                                               PhysicalDeviceObject);
796 
797     InitializeListHead(&FdoExt->DeviceListHead);
798     KeInitializeSpinLock(&FdoExt->Lock);
799 
800     Status = IsaPnpCreateReadPortDO(FdoExt);
801     if (!NT_SUCCESS(Status))
802         return Status;
803 
804     Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
805     FdoExt->DataPortPdo->Flags &= ~DO_DEVICE_INITIALIZING;
806 
807     return STATUS_SUCCESS;
808 }
809 
810 DRIVER_DISPATCH IsaPower;
811 NTSTATUS
812 NTAPI
813 IsaPower(
814     IN PDEVICE_OBJECT DeviceObject,
815     IN PIRP Irp)
816 {
817     PISAPNP_COMMON_EXTENSION DevExt = DeviceObject->DeviceExtension;
818     NTSTATUS Status;
819 
820     if (!DevExt->IsFdo)
821     {
822         Status = Irp->IoStatus.Status;
823         IoCompleteRequest(Irp, IO_NO_INCREMENT);
824         return Status;
825     }
826 
827     PoStartNextPowerIrp(Irp);
828     IoSkipCurrentIrpStackLocation(Irp);
829     return PoCallDriver(((PISAPNP_FDO_EXTENSION)DevExt)->Ldo, Irp);
830 }
831 
832 static DRIVER_DISPATCH IsaPnp;
833 
834 static
835 NTSTATUS
836 NTAPI
837 IsaPnp(
838     IN PDEVICE_OBJECT DeviceObject,
839     IN PIRP Irp)
840 {
841     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
842     PISAPNP_COMMON_EXTENSION DevExt = DeviceObject->DeviceExtension;
843 
844     DPRINT("%s(%p, %p)\n", __FUNCTION__, DeviceObject, Irp);
845 
846     if (DevExt->IsFdo)
847     {
848        return IsaFdoPnp((PISAPNP_FDO_EXTENSION)DevExt,
849                         Irp,
850                         IrpSp);
851     }
852     else
853     {
854        return IsaPdoPnp((PISAPNP_PDO_EXTENSION)DevExt,
855                         Irp,
856                         IrpSp);
857     }
858 }
859 
860 NTSTATUS
861 NTAPI
862 DriverEntry(
863     IN PDRIVER_OBJECT DriverObject,
864     IN PUNICODE_STRING RegistryPath)
865 {
866     DPRINT("%s(%p, %wZ)\n", __FUNCTION__, DriverObject, RegistryPath);
867 
868     DriverObject->MajorFunction[IRP_MJ_CREATE] = IsaCreateClose;
869     DriverObject->MajorFunction[IRP_MJ_CLOSE] = IsaCreateClose;
870     DriverObject->MajorFunction[IRP_MJ_READ] = IsaReadWrite;
871     DriverObject->MajorFunction[IRP_MJ_WRITE] = IsaReadWrite;
872     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IsaIoctl;
873     DriverObject->MajorFunction[IRP_MJ_PNP] = IsaPnp;
874     DriverObject->MajorFunction[IRP_MJ_POWER] = IsaPower;
875     DriverObject->DriverExtension->AddDevice = IsaAddDevice;
876 
877     return STATUS_SUCCESS;
878 }
879 
880 /* EOF */
881