2 * ReactOS Floppy Driver
3 * Copyright (C) 2004, Vizzini (vizzini@plasmic.com)
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 * PROJECT: ReactOS Floppy Driver
21 * PURPOSE: IOCTL Routines
22 * PROGRAMMER: Vizzini (vizzini@plasmic.com)
24 * 15-Feb-2004 vizzini - Created
26 * - All IOCTL documentation taken from the DDK
27 * - This driver tries to support all of the IOCTLs that the DDK floppy
30 * TODO: Add support to GET_MEDIA_TYPES for non-1.44 disks
31 * TODO: Implement format
39 DeviceIoctl(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
41 * FUNCTION: Queue IOCTL IRPs
43 * DeviceObject: DeviceObject that is the target of the IRP
46 * STATUS_SUCCESS in all cases, so far
48 * - We can't just service these immediately because, even though some
49 * are able to run at DISPATCH, they'll get out of sync with other
50 * read/write or ioctl irps.
56 Irp
->Tail
.Overlay
.DriverContext
[0] = DeviceObject
;
57 IoCsqInsertIrp(&Csq
, Irp
, NULL
);
59 return STATUS_PENDING
;
64 DeviceIoctlPassive(PDRIVE_INFO DriveInfo
, PIRP Irp
)
66 * FUNCTION: Handles IOCTL requests at PASSIVE_LEVEL
68 * DriveInfo: Drive that the IOCTL is directed at
69 * Irp: IRP with the request in it
72 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
73 ULONG OutputLength
= Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
74 PVOID OutputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
75 ULONG Code
= Stack
->Parameters
.DeviceIoControl
.IoControlCode
;
78 PMOUNTDEV_UNIQUE_ID UniqueId
;
80 TRACE_(FLOPPY
, "DeviceIoctl called\n");
81 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
82 Irp
->IoStatus
.Information
= 0;
85 * First the non-change-sensitive ioctls
87 if(Code
== IOCTL_DISK_GET_MEDIA_TYPES
)
89 PDISK_GEOMETRY Geometry
= OutputBuffer
;
90 INFO_(FLOPPY
, "IOCTL_DISK_GET_MEDIA_TYPES Called\n");
92 if(OutputLength
< sizeof(DISK_GEOMETRY
))
94 INFO_(FLOPPY
, "IOCTL_DISK_GET_MEDIA_TYPES: insufficient buffer; returning STATUS_INVALID_PARAMETER\n");
95 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
96 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
101 * for now, this driver only supports 3.5" HD media
103 Geometry
->MediaType
= F3_1Pt44_512
;
104 Geometry
->Cylinders
.QuadPart
= 80;
105 Geometry
->TracksPerCylinder
= 2 * 18;
106 Geometry
->SectorsPerTrack
= 18;
107 Geometry
->BytesPerSector
= 512;
109 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
110 Irp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
111 INFO_(FLOPPY
, "Ioctl: completing with STATUS_SUCCESS\n");
112 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
118 * Now, check to see if the volume needs to be verified. If so,
119 * return STATUS_VERIFY_REQUIRED.
121 * NOTE: This code, which is outside of the switch and if/else blocks,
122 * will implicity catch and correctly service IOCTL_DISK_CHECK_VERIFY.
123 * Therefore if we see one below in the switch, we can return STATUS_SUCCESS
126 if(DriveInfo
->DeviceObject
->Flags
& DO_VERIFY_VOLUME
&& !(Stack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
))
128 INFO_(FLOPPY
, "DeviceIoctl(): completing with STATUS_VERIFY_REQUIRED\n");
129 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
130 Irp
->IoStatus
.Information
= 0;
131 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
136 * Start the drive to see if the disk has changed
138 StartMotor(DriveInfo
);
141 * Check the change line, and if it's set, return
143 if(HwDiskChanged(DriveInfo
, &DiskChanged
) != STATUS_SUCCESS
)
145 WARN_(FLOPPY
, "DeviceIoctl(): unable to sense disk change; completing with STATUS_UNSUCCESSFUL\n");
146 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
147 Irp
->IoStatus
.Information
= 0;
148 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
149 StopMotor(DriveInfo
->ControllerInfo
);
155 INFO_(FLOPPY
, "DeviceIoctl(): detected disk changed; signalling media change and completing\n");
156 SignalMediaChanged(DriveInfo
->DeviceObject
, Irp
);
159 * Just guessing here - I have a choice of returning NO_MEDIA or VERIFY_REQUIRED. If there's
160 * really no disk in the drive, I'm thinking I can save time by just reporting that fact, rather
161 * than forcing windows to ask me twice. If this doesn't work, we'll need to split this up and
162 * handle the CHECK_VERIFY IOCTL separately.
164 if(ResetChangeFlag(DriveInfo
) == STATUS_NO_MEDIA_IN_DEVICE
)
165 Irp
->IoStatus
.Status
= STATUS_NO_MEDIA_IN_DEVICE
;
167 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
168 StopMotor(DriveInfo
->ControllerInfo
);
174 case IOCTL_DISK_IS_WRITABLE
:
178 INFO_(FLOPPY
, "IOCTL_DISK_IS_WRITABLE Called\n");
180 /* This IRP always has 0 information */
181 Irp
->IoStatus
.Information
= 0;
183 if(HwSenseDriveStatus(DriveInfo
) != STATUS_SUCCESS
)
185 WARN_(FLOPPY
, "IoctlDiskIsWritable(): unable to sense drive status\n");
186 Irp
->IoStatus
.Status
= STATUS_IO_DEVICE_ERROR
;
190 /* Now, read the drive's status back */
191 if(HwSenseDriveStatusResult(DriveInfo
->ControllerInfo
, &Status
) != STATUS_SUCCESS
)
193 WARN_(FLOPPY
, "IoctlDiskIsWritable(): unable to read drive status result\n");
194 Irp
->IoStatus
.Status
= STATUS_IO_DEVICE_ERROR
;
198 /* Check to see if the write flag is set. */
199 if(Status
& SR3_WRITE_PROTECT_STATUS_SIGNAL
)
201 INFO_(FLOPPY
, "IOCTL_DISK_IS_WRITABLE: disk is write protected\n");
202 Irp
->IoStatus
.Status
= STATUS_MEDIA_WRITE_PROTECTED
;
205 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
209 case IOCTL_DISK_CHECK_VERIFY
:
210 INFO_(FLOPPY
, "IOCTL_DISK_CHECK_VERIFY called\n");
211 if (OutputLength
!= 0)
213 if (OutputLength
< sizeof(ULONG
))
215 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
216 Irp
->IoStatus
.Information
= 0;
220 *((PULONG
)OutputBuffer
) = DriveInfo
->DiskChangeCount
;
221 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
222 Irp
->IoStatus
.Information
= sizeof(ULONG
);
227 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
228 Irp
->IoStatus
.Information
= 0;
232 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
234 INFO_(FLOPPY
, "IOCTL_DISK_GET_DRIVE_GEOMETRY Called\n");
235 if(OutputLength
< sizeof(DISK_GEOMETRY
))
237 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
241 /* This still works right even if DriveInfo->DiskGeometry->MediaType = Unknown */
242 memcpy(OutputBuffer
, &DriveInfo
->DiskGeometry
, sizeof(DISK_GEOMETRY
));
243 Irp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
247 case IOCTL_DISK_FORMAT_TRACKS
:
248 case IOCTL_DISK_FORMAT_TRACKS_EX
:
249 ERR_(FLOPPY
, "Format called; not supported yet\n");
250 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
251 Irp
->IoStatus
.Information
= 0;
254 case IOCTL_DISK_GET_PARTITION_INFO
:
255 INFO_(FLOPPY
, "IOCTL_DISK_GET_PARTITION_INFO Called; not supported by a floppy driver\n");
256 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
257 Irp
->IoStatus
.Information
= 0;
260 case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
:
261 if(OutputLength
< sizeof(MOUNTDEV_UNIQUE_ID
))
263 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
264 Irp
->IoStatus
.Information
= 0;
268 UniqueId
= Irp
->AssociatedIrp
.SystemBuffer
;
269 UniqueId
->UniqueIdLength
= (USHORT
)wcslen(&DriveInfo
->DeviceNameBuffer
[0]) * sizeof(WCHAR
);
271 if(OutputLength
< FIELD_OFFSET(MOUNTDEV_UNIQUE_ID
, UniqueId
) + UniqueId
->UniqueIdLength
)
273 Irp
->IoStatus
.Status
= STATUS_BUFFER_OVERFLOW
;
274 Irp
->IoStatus
.Information
= sizeof(MOUNTDEV_UNIQUE_ID
);
278 RtlCopyMemory(UniqueId
->UniqueId
, &DriveInfo
->DeviceNameBuffer
[0],
279 UniqueId
->UniqueIdLength
);
281 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
282 Irp
->IoStatus
.Information
= FIELD_OFFSET(MOUNTDEV_UNIQUE_ID
, UniqueId
) + UniqueId
->UniqueIdLength
;
285 case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
:
286 if(OutputLength
< sizeof(MOUNTDEV_NAME
))
288 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
289 Irp
->IoStatus
.Information
= 0;
293 Name
= Irp
->AssociatedIrp
.SystemBuffer
;
294 Name
->NameLength
= (USHORT
)wcslen(&DriveInfo
->DeviceNameBuffer
[0]) * sizeof(WCHAR
);
296 if(OutputLength
< FIELD_OFFSET(MOUNTDEV_NAME
, Name
) + Name
->NameLength
)
298 Irp
->IoStatus
.Status
= STATUS_BUFFER_OVERFLOW
;
299 Irp
->IoStatus
.Information
= sizeof(MOUNTDEV_NAME
);
303 RtlCopyMemory(Name
->Name
, &DriveInfo
->DeviceNameBuffer
[0],
306 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
307 Irp
->IoStatus
.Information
= FIELD_OFFSET(MOUNTDEV_NAME
, Name
) + Name
->NameLength
;
311 ERR_(FLOPPY
, "UNKNOWN IOCTL CODE: 0x%x\n", Code
);
312 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
313 Irp
->IoStatus
.Information
= 0;
317 INFO_(FLOPPY
, "ioctl: completing with status 0x%x\n", Irp
->IoStatus
.Status
);
318 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
320 StopMotor(DriveInfo
->ControllerInfo
);