before. This creates the phddo device object and its associated device extension. The IoCreateDevice Exclusive parameter is TRUE indicating that only one Win32 application can open this device at a time.

All the appropriate fields are set up in the device extension, including the phddo field. The device timer is initialized with IoInitializeTimer and the device Deferred Procedure Call is initialized with IoInitializeDpcRequest. Finally, an explicit symbolic link is set up using IoCreateSymbolicLink. Device interfaces are not used.

Listing 18.1 NT style device creation

PDEVICE_OBJECT phddo = NULL;

#define NT_DEVICE_NAME L'\Device\PHDIo'

#define SYM_LINK_NAME L'\DosDevices\PHDIo'

NTSTATUS PHDIoCreateDevice(IN PDRIVER_OBJECT DriverObject {

 NTSTATUS status = STATUS_SUCCESS;

 // Initialise NT and Symbolic link names

 UNICODE_STRING deviceName, linkName;

 RtlInitUnicodeString(&deviceName, NT_DEVICE_NAME);

 RtlInitUnicodeString(&linkName, SYM_LINK_NAME);

 // Create our device

 DebugPrint('Creating device %T',&deviceName);

 status = IoCreateDevice(

  DriverObject,

  sizeof(PHDIO_DEVICE_EXTENSION),

  &deviceName,

  FILE_DEVICE_UNKNOWN,

  0,

  TRUE, // Exclusive

  &phddo);

 if (!NT_SUCCESS(status)) {

  DebugPrintMsg('Could not create device');

  return status;

 }

 phddo->Flags |= DO_BUFFEREO_IO;

 // Initialise device extension

 PPHDIO_DEVICE_EXTENSION dx = (PPHDIO_DEVICE_EXTENSION)phddo->DeviceExtension;

 dx->phddo = phddo;

 dx->UsageCount = 1;

 KeInitializeEvent(&dx->StoppingEvent, NotificationEvent, FALSE);

 dx->Stopping = false;

 dx->GotPortOrMemory = false;

 dx->GotInterrupt = false;

 dx->ConnectedToInterrupt = false;

 dx->SetTimeout = 10;

 dx->Timeout = –1;

 dx->StopTimer = false;

 dx->WriteCmds = NULL;

 dx->ReadCmds = NULL;

 dx->StartReadCmds = NULL;

 // Initialise timer for this device (but do not start)

 status = IoInitializeTimer(phddo, (PIO_TIMER_ROUTINE)Timeout1s, dx);

 if (!NT_SUCCESS(status)) {

  DebugPrintMsg('Could not initialise timer');

  IoDeleteDevice(phddo);

  return status;

 }

 // Create a symbolic link so our device is visible to Win32…

 DebugPrint('Creating symbolic link %T', &linkName);

 status = IoCreateSymbolicLink(&linkName, &deviceName);

 if (!NT_SUCCESS(status)) {

  DebugPrintMsg('Could not create symbolic link');

  IoDeleteDevice(phddo);

  return status;

 }

 // Initialise our DPC for IRQ completion processing

 IoInitializeDpcRequest(phddo, PHDIoDpcForIsr);

 return status;

}

When PHDIo is unloaded, its PHDIoUnload routine is called. This runs PHDIoDeleteDevice to stop the PHDIo device, remove its symbolic link, and delete its device object.

If a driver makes a variable number of devices, the unload routine could use the following technique to find all the devices to remove. The kernel sets the driver object DeviceObject field to point to the first device that belongs to the driver. The NextDevice field in each device object points to the next device. It is, therefore, a simple task to traverse this chain of device objects and delete them. The only catch is that you still have to generate the correct symbolic link name for each device so the symbolic link can be removed.

Claiming Resources

This section looks at how to allocate resources. The crucial kernel function is IoReportResourceUsage. This checks to see if any other devices are using the resources. If the resources are free, they are reserved so no other device can use them.

The PHDIo driver only finds out which resources are needed when the user calls CreateFile, passing the resource description in the filename string. The Create IRP arrives in the PHDIoCreate routine. All the previous Create IRP handlers have not done very much. However, PHDIoCreate has these jobs to do.

1. Get the resource details from the filename.

2. Check for resource conflicts and reserve the resources.

3. Translate and map the resources.

Getting the resource details is handled by the GetResourcesFromFilename routine. I will not go into the details of this code here, apart from saying that it uses three support routines that work with the UNICODE_STRING structure: usStrCmpN, usGetHex, and usGetDec. In the end, the GotPortOrMemory device extension field is true if an I/O port specifier has been found, GotInterrupt is true if an interrupt has been found and ResourceOverride is true if the override specifier was used.

PHDIoCreate checks that an I/O port was specified. It then calls ClaimResources to check for resource conflicts and reserve the resources. Finally, TranslateAndMapResources is used to translate resource information and map memory. PHDIoCreate carefully ensures that all the resource bool fields are reset to false at the fail label if any error occurs.

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату
×