1 /*******************************************************************
2 uLan Communication - uL_DRV - multiplatform uLan driver
4 ul_kdmnt.c - Windows NT KMD specific support
6 (C) Copyright 1996-2004 by Pavel Pisa - project originator
7 http://cmp.felk.cvut.cz/~pisa
8 (C) Copyright 1996-2004 PiKRON Ltd.
10 (C) Copyright 2002-2004 Petr Smolik
13 The uLan driver project can be used and distributed
14 in compliance with any of next licenses
15 - GPL - GNU Public License
16 See file COPYING for details.
17 - LGPL - Lesser GNU Public License
18 - MPL - Mozilla Public License
19 - and other licenses added by project originator
21 Code can be modified and re-distributed under any combination
22 of the above listed licenses. If contributor does not agree with
23 some of the licenses, he/she can delete appropriate line.
24 WARNING: if you delete all lines, you are not allowed to
25 distribute code or sources in any form.
26 *******************************************************************/
28 //-------------------------------------------------------------------
30 // Declare forward function references
33 VOID UnloadDriver (IN PDRIVER_OBJECT DriverObject);
35 BOOLEAN ReportUsage(IN PDRIVER_OBJECT DriverObject,
36 IN PDEVICE_OBJECT DeviceObject,
37 IN INTERFACE_TYPE InterfaceType,
39 IN PHYSICAL_ADDRESS PortAddress,
42 IN BOOLEAN *ConflictDetected);
44 //---------------------------------------------------------------------------
48 // This routine registers (reports) the I/O and IRQ usage for this driver.
51 // DriverObject - Pointer to the driver object
52 // DeviceObject - Pointer to the Device object
53 // PortAddress - Address of I/O port used
54 // ConflictDetected - TRUE if a resource conflict was detected.
57 // TRUE - If a Resource conflict was detected
58 // FALSE - If no conflict was detected
60 BOOLEAN ReportUsage(IN PDRIVER_OBJECT DriverObject,
61 IN PDEVICE_OBJECT DeviceObject,
62 IN INTERFACE_TYPE InterfaceType,
64 IN PHYSICAL_ADDRESS PortAddress,
67 IN BOOLEAN *ConflictDetected)
69 ULONG sizeOfResourceList;
70 PCM_RESOURCE_LIST resourceList;
71 PCM_FULL_RESOURCE_DESCRIPTOR nextFrd;
72 PCM_PARTIAL_RESOURCE_DESCRIPTOR partial;
75 // The size of the resource list is going to be one full descriptor
76 // which already has one partial descriptor included, plus another
77 // partial descriptor. One partial descriptor will be for the
78 // interrupt, and the other for the port addresses.
81 sizeOfResourceList = sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
84 // The full resource descriptor already contains one
85 // partial. Make room for one more.
87 // It will hold the irq "prd", and the port "prd".
88 // ("prd" = partial resource descriptor)
91 sizeOfResourceList += sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
94 // Now we increment the length of the resource list by field offset
95 // of the first frd. This will give us the length of what preceeds
96 // the first frd in the resource list.
97 // (frd = full resource descriptor)
100 sizeOfResourceList += FIELD_OFFSET(CM_RESOURCE_LIST, List[0]);
102 resourceList = ExAllocatePool(PagedPool, sizeOfResourceList);
112 RtlZeroMemory(resourceList, sizeOfResourceList);
114 resourceList->Count = 1;
115 nextFrd = &resourceList->List[0];
117 nextFrd->InterfaceType = InterfaceType;
118 nextFrd->BusNumber = BusNumber;
121 // We are going to report port addresses and interrupt
124 nextFrd->PartialResourceList.Count = 2;
127 // Now fill in the port data. We don't wish to share
128 // this port range with anyone.
130 // Note: the port address we pass in is the one we got
131 // back from HalTranslateBusAddress.
133 // CmResourceShareDriverExclusive
134 // CmResourceShareDeviceExclusive
135 // CmResourceShareShared
137 partial = &nextFrd->PartialResourceList.PartialDescriptors[0];
139 partial->Type = CmResourceTypePort;
140 partial->ShareDisposition = CmResourceShareDeviceExclusive;
141 partial->Flags = CM_RESOURCE_PORT_IO;
142 partial->u.Port.Start = PortAddress;
143 partial->u.Port.Length = PortRange;
148 // Now fill in the irq stuff.
150 // Note: for IoReportResourceUsage, the Interrupt.Level and
151 // Interrupt.Vector are bus-specific level and vector, just
152 // as we passed in to HalGetInterruptVector, not the mapped
153 // system vector we got back from HalGetInterruptVector.
156 partial->Type = CmResourceTypeInterrupt;
157 partial->u.Interrupt.Level = IRQLine;
158 partial->u.Interrupt.Vector = IRQLine;
159 partial->ShareDisposition = InterfaceType==Isa?
160 CmResourceShareDeviceExclusive:
161 CmResourceShareShared;
162 partial->Flags = InterfaceType==Isa?
163 CM_RESOURCE_INTERRUPT_LATCHED:
164 CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
166 /* Claim resources for Driver */
167 /*IoReportResourceUsage(
178 /* Claim resources for individual DeviceObject */
179 IoReportResourceUsage(
191 // The above routine sets the BOOLEAN parameter ConflictDetected
192 // to TRUE if a conflict was detected.
195 ExFreePool(resourceList);
197 return (*ConflictDetected);
201 //-------------------------------------------------------------------
202 // DriverEntry for WinNT style KMD
205 // NT device Driver Entry point
208 // DriverObject - Pointer to this device's driver object
209 // RegistryPath - Pointer to the Unicode regsitry path name
214 NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
216 PDEVICE_OBJECT deviceObject = NULL;
217 NTSTATUS status, ioConnectStatus;
218 UNICODE_STRING uniNtNameString;
219 UNICODE_STRING uniWin32NameString;
220 UNICODE_STRING uniRegPath;
221 INTERFACE_TYPE InterfaceType;
223 PCI_SLOT_NUMBER SlotNumber;
236 ULONG MappedVector=0, AddressSpace = 1;
237 PULAN_DEVICE_EXTENSION extension;
238 BOOLEAN ResourceConflict;
239 PHYSICAL_ADDRESS InPortAddr, OutPortAddr;
242 ULD_LARGE_INTEGER_0=RtlConvertLongToLargeInteger(0);
244 uLan_DbgPrint("uLan v" UL_DRV_VERSION " Enter the driver!\n");
245 uLan_DbgPrint("uLan: " __DATE__ " " __TIME__ "\n");
248 // Create counted string version of our device name.
251 RtlInitUnicodeString(&uniNtNameString, NT_DEVICE_NAME);
254 // Default configuration
260 InPortAddr.LowPart = DEF_PORT_ADDRESS;
261 InPortAddr.HighPart = 0;
262 PortRange = DEF_PORT_RANGE;
263 IRQLine = DEF_IRQ_LINE;
264 BaudRate = DEF_BAUD_RATE;
267 MyAddr = DEF_MY_ADDR;
270 // Get the configuration information from the Registry
273 /* RtlInitUnicodeString(&uniRegPath,RegistryPath->Buffer); */
274 /* RtlCopyUnicodeString(&uniRegPath,RegistryPath); */
276 status=STATUS_SUCCESS;
277 RtlInitUnicodeString(&uniRegPath, NULL);
278 uniRegPath.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters")+1;
279 uniRegPath.Buffer = ExAllocatePool(PagedPool, uniRegPath.MaximumLength*sizeof(WCHAR));
281 if (!uniRegPath.Buffer) {
282 uLan_DbgPrint("uLan: ExAllocatePool failed for Path in DriverEntry\n");
283 status = STATUS_UNSUCCESSFUL;
287 RtlZeroMemory(uniRegPath.Buffer,uniRegPath.MaximumLength*sizeof(WCHAR));
288 RtlAppendUnicodeStringToString(&uniRegPath, RegistryPath);
289 RtlAppendUnicodeToString(&uniRegPath, L"\\Parameters");
292 if (NT_SUCCESS(status))
293 status=ulan_GetRegistryDword(uniRegPath.Buffer,L"ScanForPCI",&ScanForPCI);
294 if (NT_SUCCESS(status))
295 status=ulan_GetRegistryDword(uniRegPath.Buffer,L"Port Address",&InPortAddr.LowPart);
296 if (NT_SUCCESS(status))
297 status=ulan_GetRegistryDword(uniRegPath.Buffer,L"Port Range",&PortRange);
299 if (NT_SUCCESS(status))
300 status=ulan_GetRegistryDword(uniRegPath.Buffer,L"IRQ Line",&TmpLong);
301 IRQLine=(KIRQL)TmpLong;
302 IRQLevel=(KIRQL)TmpLong;
303 if (NT_SUCCESS(status))
304 status=ulan_GetRegistryDword(uniRegPath.Buffer,L"Baud Rate",&BaudRate);
305 if (NT_SUCCESS(status))
306 status=ulan_GetRegistryDword(uniRegPath.Buffer,L"Baud Base",&BaudBase);
307 if (NT_SUCCESS(status))
308 status=ulan_GetRegistryDword(uniRegPath.Buffer,L"My Addr",&MyAddr);
309 if (NT_SUCCESS(status))
310 status=ulan_GetRegistryDword(uniRegPath.Buffer,L"Buffer Size",&BufferSize);
311 TmpLong=uld_debug_flg;
312 if (NT_SUCCESS(status))
313 status=ulan_GetRegistryDword(uniRegPath.Buffer,L"Debug",&TmpLong);
314 uld_debug_flg=TmpLong;
315 if(uniRegPath.Buffer)
316 ExFreePool(uniRegPath.Buffer);
317 if (!NT_SUCCESS(status)) {
318 uLan_DbgPrint("uLan: GetConfiguration failed\n");
324 pci_device_id_t *device_id;
325 uLan_DbgPrint("uLan: Calling ScanForPCICard\n");
326 if(ScanForPCICard(&BusNumber,&SlotNumber,TRUE,&device_id)){
327 /*PCI_COMMON_CONFIG PCIConfig;*/
328 /*HalGetBusData(PCIConfiguration,BusNumber,SlotNumber.u.AsULONG,
329 PCIConfig,sizeof(PCIConfig));*/
330 uLan_DbgPrint("uLan: ScanForPCICard found slot %02X:%02X.%1X\n",
331 (int)BusNumber,(int)SlotNumber.u.bits.DeviceNumber,
332 (int)SlotNumber.u.bits.FunctionNumber);
333 InterfaceType=PCIBus;
334 ChipOptions=device_id->driver_data; /*0x16954000*/
337 #endif /*UL_WITH_PCI*/
340 // Create the device object, multi-thread access (FALSE)
343 status = IoCreateDevice(DriverObject, sizeof(ULAN_DEVICE_EXTENSION),
344 &uniNtNameString, FILE_DEVICE_UNKNOWN, 0,
345 /* TRUE */ FALSE, &deviceObject);
347 if (!NT_SUCCESS (status) ) {
348 uLan_DbgPrint("uLan: IoCreateDevice failed\n");
353 // Set the FLAGS field
356 deviceObject->Flags |= DO_BUFFERED_IO;
358 extension = (PULAN_DEVICE_EXTENSION) deviceObject->DeviceExtension;
359 extension->flag_CHIPOK=0;
362 // Claim PnP busses resources
366 if(InterfaceType!=Isa){
367 PCM_RESOURCE_LIST AllocatedResources;
368 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
370 InPortAddr.LowPart=IRQLine=0;
371 status = HalAssignSlotResources(RegistryPath,NULL,DriverObject,
372 deviceObject,InterfaceType,BusNumber,
373 SlotNumber.u.AsULONG,&AllocatedResources);
375 if(!AllocatedResources->Count)
376 status = STATUS_INSUFFICIENT_RESOURCES;
377 if(NT_SUCCESS(status)){
378 PartialCount=AllocatedResources->List[0].PartialResourceList.Count;
379 PartialDescriptor=AllocatedResources->List[0].PartialResourceList.PartialDescriptors;
380 for(i=0;i<PartialCount;i++){
381 if((PartialDescriptor[i].Type==CmResourceTypePort)&&
382 (!InPortAddr.LowPart)){
383 InPortAddr=PartialDescriptor[i].u.Port.Start;
384 PortRange=PartialDescriptor[i].u.Port.Length;
386 if((PartialDescriptor[i].Type==CmResourceTypeInterrupt)&&
388 IRQLevel=(KIRQL)PartialDescriptor[i].u.Interrupt.Level;
389 IRQLine=(KIRQL)PartialDescriptor[i].u.Interrupt.Vector;
393 if(!NT_SUCCESS(status)){
394 uLan_DbgPrint("uLan: HalAssignSlotResources error %X\n",status);
395 ExFreePool(AllocatedResources);
396 IoDeleteDevice(deviceObject);
399 if(!InPortAddr.LowPart || !IRQLine)
400 status = STATUS_INSUFFICIENT_RESOURCES;
401 uLan_DbgPrint("uLan: Found PCI resources Port=%04X IRQLevel=%02X IRQVector=%02X\n",
402 InPortAddr.LowPart,IRQLevel,IRQLine);
403 ExFreePool(AllocatedResources);
405 #endif /*UL_WITH_PCI*/
408 // This call will map our IRQ to a system vector. It will also fill
409 // in the IRQL (the kernel-defined level at which our ISR will run),
410 // and affinity mask (which processors our ISR can run on).
412 // We need to do this so that when we connect to the interrupt, we
413 // can supply the kernel with this information.
418 MappedVector = HalGetInterruptVector(
419 InterfaceType, // Interface type
420 BusNumber, // Bus number
421 IRQLevel, // BusInterruptLevel
422 IRQLine, // BusInterruptVector
424 &Affinity // Affinity mask
429 // A little known Windows NT fact,
430 // If MappedVector==0, then HalGetInterruptVector failed.
434 if (MappedVector == 0) {
435 uLan_DbgPrint("uLan: HalGetInterruptVector failed\n");
436 IoDeleteDevice(deviceObject);
437 return (STATUS_INVALID_PARAMETER);
444 extension->Irql = irql;
447 uLan_DbgPrint("uLan: driver mappedvector=%d irql=%d, dispatch irql=%d\n",
448 MappedVector,irql,DISPATCH_LEVEL);
449 if(uL_SpinLock_Irql<irql)
450 uL_SpinLock_Irql=irql;
451 uLan_DbgPrint("uLan: spin lock irql=%d\n",uL_SpinLock_Irql);
454 // Translate the base port address to a system mapped address.
455 // This will be saved in the device extension after IoCreateDevice,
456 // because we use the translated port address to access the ports.
459 if (!HalTranslateBusAddress(InterfaceType, BusNumber, InPortAddr,
460 &AddressSpace, &OutPortAddr)) {
461 uLan_DbgPrint("uLan: HalTranslateBusAddress failed\n");
462 return STATUS_SOME_NOT_MAPPED;
466 if ( NT_SUCCESS(status) ) {
469 // Create dispatch points for create/open, close, unload, and ioctl
472 DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchRoutine;
473 DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchRoutine;
474 DriverObject->MajorFunction[IRP_MJ_READ] = DispatchRoutine;
475 DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchRoutine;
476 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchRoutine;
477 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = DispatchRoutine;
478 DriverObject->DriverUnload = UnloadDriver;
481 // check if resources (ports and interrupt) are available
486 if(InterfaceType==Isa)
487 #endif /*UL_WITH_PCI*/
489 ReportUsage(DriverObject,deviceObject,InterfaceType,BusNumber,
490 InPortAddr,PortRange,IRQLine,&ResourceConflict);
492 if (ResourceConflict) {
493 uLan_DbgPrint("uLan: Couldn't get resources\n");
494 IoDeleteDevice(deviceObject);
495 return STATUS_INSUFFICIENT_RESOURCES;
501 // fill in the device extension
503 extension = (PULAN_DEVICE_EXTENSION) deviceObject->DeviceExtension;
504 extension->DeviceObject = deviceObject;
505 extension->port = OutPortAddr.LowPart;
508 status=ul_drv_init_ext(extension,OutPortAddr.LowPart,IRQLine,BaudRate,
509 BaudBase,ChipOptions,BufferSize,MyAddr);
511 if ( !NT_SUCCESS (status) ) {
512 uLan_DbgPrint("uLan: Initialization failed\n");
513 IoDeleteDevice(deviceObject);
518 KeInitializeDpc(&extension->bottom_dpc,ulan_bottom_dpc,extension);
519 KeInitializeDpc(&extension->wd_timer_dpc,ulan_wd_dpc,extension);
520 KeInitializeTimer(&extension->wd_timer);
523 // connect the device driver to the IRQ
525 ioConnectStatus = IoConnectInterrupt(&extension->InterruptObject,
526 uld_irq_handler, // ServiceRoutine
527 extension, // ServiceContext
529 MappedVector, // Vector
531 irql, // SynchronizeIrql
532 InterfaceType==Isa? Latched:
533 LevelSensitive, // InterruptMode
534 InterfaceType==Isa? FALSE:
536 Affinity, // ProcessorEnableMask
537 FALSE); // FloatingSave
539 if ( !NT_SUCCESS (ioConnectStatus) ) {
540 uLan_DbgPrint("uLan: Couldn't connect interrupt\n");
541 IoDeleteDevice(deviceObject);
542 return ioConnectStatus;
546 uLan_DbgPrint("uLan: just about ready!\n");
549 // Create counted string version of our Win32 device name.
552 RtlInitUnicodeString( &uniWin32NameString, DOS_DEVICE_NAME);
555 // Create a link from our device name to a name in the Win32 namespace.
558 /* IoDeleteSymbolicLink (&uniWin32NameString); */
559 status = IoCreateSymbolicLink( &uniWin32NameString, &uniNtNameString );
561 if (!NT_SUCCESS(status)) {
562 uLan_DbgPrint("uLan: Couldn't create the symbolic link\n");
563 IoDeleteDevice (DriverObject->DeviceObject);
567 // Setup the Dpc for ISR routine
571 IoInitializeDpcRequest (DriverObject->DeviceObject, uLan_Dpc_Routine);
574 // Initialize the device (enable IRQ's, hit the hardware)
577 Initialize_uLan (extension);
580 uLan_DbgPrint("uLan: All initialized!\n");
583 geninfoblk(extension);
584 printudrvbll(extension);
585 extension->flag_NACTIV=1;
586 KeRaiseIrql(DISPATCH_LEVEL,&OldIrql);
587 uld_timeout(extension);
588 KeLowerIrql(OldIrql);
589 #endif /* UL_INT_TST */
594 uLan_DbgPrint("uLan: Couldn't create the device\n");
602 //---------------------------------------------------------------------------
606 // Free all the allocated resources, etc.
609 // DriverObject - pointer to a driver object
614 VOID UnloadDriver (IN PDRIVER_OBJECT DriverObject)
616 WCHAR deviceLinkBuffer[] = DOS_DEVICE_NAME;
617 UNICODE_STRING deviceLinkUnicodeString;
618 PULAN_DEVICE_EXTENSION extension;
620 extension = DriverObject->DeviceObject->DeviceExtension;
623 if(extension->flag_CHIPOK);
624 printudrvbll(extension);
625 #endif /* UL_INT_TST */
631 ul_drv_done_ext(extension);
634 // Disconnect IRQ and DPC sources
637 IoDisconnectInterrupt (extension->InterruptObject);
639 KeCancelTimer(&extension->wd_timer);
640 KeRemoveQueueDpc(&extension->wd_timer_dpc);
641 KeRemoveQueueDpc(&extension->bottom_dpc);
644 // Delete the symbolic link
648 RtlInitUnicodeString (&deviceLinkUnicodeString, deviceLinkBuffer);
650 IoDeleteSymbolicLink (&deviceLinkUnicodeString);
653 // Delete the device object
656 IoDeleteDevice (DriverObject->DeviceObject);
658 #ifdef ENABLE_UL_MEM_CHECK
659 UL_PRINTF("MEM_CHECK: malloc-free=%d\n",
660 (int)atomic_read(&ul_mem_check_counter));
661 #endif /* ENABLE_UL_MEM_CHECK */
662 uLan_DbgPrint ("uLan: Unloaded\n");