> I.Information() = dwBytesRead;
> I.Status() = status;
> //Обработать следующий IRP-пакет.
> PnpNextIrp(I);
>}
Метод SerialWrite работает практически так же, только он записывает данные в память устройства, а не считывает их.
>void XDSPdrvDevice::SerialWrite(KIrp I) {
> t << "Entering XDSPdrvDevice::SerialWrite, " << I << EOL;
> NTSTATUS status = STATUS_SUCCESS;
> KMemory Mem(I.Mdl());
> PUCHAR pBuffer = (PUCHAR) Mem.MapToSystemSpace();
> ULONG dwTotalSize = I.WriteSize(CURRENT);
> ULONG dwBytesSent = dwTotalSize;
> m_MainMem.outd(0,(ULONG*)pBuffer,dwTotalSize);
> I.Information() = dwBytesSent;
> I.Status() = status;
> PnpNextIrp(I);
>}
Как мы упоминали ранее, для большинства драйверов устройств недостаточно функций чтения и записи. Мало-мальски сложное устройство требует еще и множества других операций: получить состояние, получить информацию об устройстве, как-то отконфигурировать его. Для выполнения этих задач служат функции управления вводом-выводом, IO Control; сокращенно — IOCTL. IOCTL предоставляет программисту возможность разработать практически неограниченное количество различных функций управления устройством.
И драйвер, и приложение пользователя различают, какую функцию управления устройством вызвать, при помощи IOCTL-кодов. Такой код представляет собой обыкновенное 32-разрядное число. Для удобства ему директивой #define задают какое-то понятное имя. Например, в нашем случае зададим IOCTL-код, при получении которого драйвер будет возвращать количество памяти "на борту" PCI-устройства.
>#define XDSPDRV_IOCTL_GETMEMSIZE 0x800
Если при чтении драйверу посылается IRP-пакет со старшим кодом функции IRP_MJ_READ, при записи — IRP_MJ_WRITE, то при вызове функции DeviceIOControl для нашего устройства драйвер получает пакет со старшим кодом IRP_MJ_IOCONTROL и младшим — код самой IOCTL-функции. Метод DeviceControl вызывается при получении драйвером IRP со старшим кодом IRP_MJ_DEVICE_CONTROL. Она действует подобно методу StartIo. В зависимости от кода IOCTL производится вызов соответствующей функции.
>NTSTATUS XDSPdrvDevice::DeviceControl(KIrp I) {
> NTSTATUS status;
> t << "Entering XDSPdrvDevice::Device Control, " << I << EOL;
> switch (I.IoctlCode()) {
> case XDSPDRV_IOCTL_GETMEMSIZE:
> //Получен определенный нами IOCTL-код XDSPDRV_IOCTL_GETMEMSIZE.
> //Вызвать соответствующий обработчик.
> status = XDSPDRV_IOCTL_GETMEMSIZE_Handler(I);
> break;
> default:
> //Этот код не определен.
> status = STATUS_INVALID_PARAMETER;