f3ef6e02b0ae8b77f534af6748835da0b9aeda7a
[reactos.git] / reactos / drivers / storage / floppy / ioctl.c
1 /*
2 * ReactOS Floppy Driver
3 * Copyright (C) 2004, Vizzini (vizzini@plasmic.com)
4 *
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.
9 *
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.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 * PROJECT: ReactOS Floppy Driver
20 * FILE: ioctl.c
21 * PURPOSE: IOCTL Routines
22 * PROGRAMMER: Vizzini (vizzini@plasmic.com)
23 * REVISIONS:
24 * 15-Feb-2004 vizzini - Created
25 * NOTES:
26 * - All IOCTL documentation taken from the DDK
27 * - This driver tries to support all of the IOCTLs that the DDK floppy
28 * sample does
29 *
30 * TODO: Add support to GET_MEDIA_TYPES for non-1.44 disks
31 * TODO: Implement format
32 */
33
34 #define NDEBUG
35 #include <debug.h>
36 #include <ntddk.h>
37
38 #include "floppy.h"
39 #include "hardware.h"
40 #include "csqrtns.h"
41 #include "ioctl.h"
42
43 \f
44 NTSTATUS NTAPI DeviceIoctl(PDEVICE_OBJECT DeviceObject,
45 PIRP Irp)
46 /*
47 * FUNCTION: Queue IOCTL IRPs
48 * ARGUMENTS:
49 * DeviceObject: DeviceObject that is the target of the IRP
50 * Irp: IRP to process
51 * RETURNS:
52 * STATUS_SUCCESS in all cases, so far
53 * NOTES:
54 * - We can't just service these immediately because, even though some
55 * are able to run at DISPATCH, they'll get out of sync with other
56 * read/write or ioctl irps.
57 */
58 {
59 ASSERT(DeviceObject);
60 ASSERT(Irp);
61
62 Irp->Tail.Overlay.DriverContext[0] = DeviceObject;
63 IoCsqInsertIrp(&Csq, Irp, NULL);
64
65 return STATUS_PENDING;
66 }
67
68 \f
69 VOID NTAPI DeviceIoctlPassive(PDRIVE_INFO DriveInfo,
70 PIRP Irp)
71 /*
72 * FUNCTION: Handlees IOCTL requests at PASSIVE_LEVEL
73 * ARGUMENTS:
74 * DriveInfo: Drive that the IOCTL is directed at
75 * Irp: IRP with the request in it
76 */
77 {
78 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
79 ULONG OutputLength = Stack->Parameters.DeviceIoControl.OutputBufferLength;
80 PVOID OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
81 ULONG Code = Stack->Parameters.DeviceIoControl.IoControlCode;
82 BOOLEAN DiskChanged;
83
84 DPRINT(("floppy: DeviceIoctl called\n"));
85 Irp->IoStatus.Status = STATUS_SUCCESS;
86 Irp->IoStatus.Information = 0;
87
88 /*
89 * First the non-change-sensitive ioctls
90 */
91 if(Code == IOCTL_DISK_GET_MEDIA_TYPES)
92 {
93 PDISK_GEOMETRY Geometry = OutputBuffer;
94 DPRINT(("floppy: IOCTL_DISK_GET_MEDIA_TYPES Called\n"));
95
96 if(OutputLength < sizeof(DISK_GEOMETRY))
97 {
98 DPRINT(("floppy: IOCTL_DISK_GET_MEDIA_TYPES: insufficient buffer; returning STATUS_INVALID_PARAMETER\n"));
99 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
100 IoCompleteRequest(Irp, IO_NO_INCREMENT);
101 return;
102 }
103
104 /*
105 * for now, this driver only supports 3.5" HD media
106 */
107 Geometry->MediaType = F3_1Pt44_512;
108 Geometry->Cylinders.QuadPart = 80;
109 Geometry->TracksPerCylinder = 2 * 18;
110 Geometry->SectorsPerTrack = 18;
111 Geometry->BytesPerSector = 512;
112
113 Irp->IoStatus.Status = STATUS_SUCCESS;
114 Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
115 DPRINT(("floppy: Ioctl: completing with STATUS_SUCCESS\n"));
116 IoCompleteRequest(Irp, IO_NO_INCREMENT);
117
118 return;
119 }
120
121 /*
122 * Now, check to see if the volume needs to be verified. If so,
123 * return STATUS_VERIFY_REQUIRED.
124 *
125 * NOTE: This code, which is outside of the switch and if/else blocks,
126 * will implicity catch and correctly service IOCTL_DISK_CHECK_VERIFY.
127 * Therefore if we see one below in the switch, we can return STATUS_SUCCESS
128 * immediately.
129 */
130 if(DriveInfo->DeviceObject->Flags & DO_VERIFY_VOLUME && !(DriveInfo->DeviceObject->Flags & SL_OVERRIDE_VERIFY_VOLUME))
131 {
132 DPRINT(("floppy: DeviceIoctl(): completing with STATUS_VERIFY_REQUIRED\n"));
133 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
134 Irp->IoStatus.Information = 0;
135 IoCompleteRequest(Irp, IO_NO_INCREMENT);
136 return;
137 }
138
139 /*
140 * Start the drive to see if the disk has changed
141 */
142 StartMotor(DriveInfo);
143
144 /*
145 * Check the change line, and if it's set, return
146 */
147 if(HwDiskChanged(DriveInfo, &DiskChanged) != STATUS_SUCCESS)
148 {
149 DPRINT(("floppy: DeviceIoctl(): unable to sense disk change; completing with STATUS_UNSUCCESSFUL\n"));
150 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
151 Irp->IoStatus.Information = 0;
152 IoCompleteRequest(Irp, IO_NO_INCREMENT);
153 StopMotor(DriveInfo->ControllerInfo);
154 return;
155 }
156
157 if(DiskChanged)
158 {
159 DPRINT(("floppy: DeviceIoctl(): detected disk changed; signalling media change and completing\n"));
160 SignalMediaChanged(DriveInfo->DeviceObject, Irp);
161
162 /*
163 * Just guessing here - I have a choice of returning NO_MEDIA or VERIFY_REQUIRED. If there's
164 * really no disk in the drive, I'm thinking I can save time by just reporting that fact, rather
165 * than forcing windows to ask me twice. If this doesn't work, we'll need to split this up and
166 * handle the CHECK_VERIFY IOCTL separately.
167 */
168 if(ResetChangeFlag(DriveInfo) == STATUS_NO_MEDIA_IN_DEVICE)
169 Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;
170
171 IoCompleteRequest(Irp, IO_NO_INCREMENT);
172 StopMotor(DriveInfo->ControllerInfo);
173 return;
174 }
175
176 switch(Code)
177 {
178 case IOCTL_DISK_IS_WRITABLE:
179 {
180 UCHAR Status;
181
182 DPRINT(("floppy: IOCTL_DISK_IS_WRITABLE Called\n"));
183
184 /* This IRP always has 0 information */
185 Irp->IoStatus.Information = 0;
186
187 if(HwSenseDriveStatus(DriveInfo) != STATUS_SUCCESS)
188 {
189 DPRINT(("floppy: IoctlDiskIsWritable(): unable to sense drive status\n"));
190 Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
191 break;
192 }
193
194 /* Now, read the drive's status back */
195 if(HwSenseDriveStatusResult(DriveInfo->ControllerInfo, &Status) != STATUS_SUCCESS)
196 {
197 DPRINT(("floppy: IoctlDiskIsWritable(): unable to read drive status result\n"));
198 Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
199 break;
200 }
201
202 /* Check to see if the write flag is set. */
203 if(Status & SR3_WRITE_PROTECT_STATUS_SIGNAL)
204 {
205 DPRINT(("floppy: IOCTL_DISK_IS_WRITABLE: disk is write protected\n"));
206 Irp->IoStatus.Status = STATUS_MEDIA_WRITE_PROTECTED;
207 }
208 else
209 Irp->IoStatus.Status = STATUS_SUCCESS;
210 }
211 break;
212
213 case IOCTL_DISK_CHECK_VERIFY:
214 DPRINT(("floppy: IOCTL_DISK_CHECK_VERIFY called\n"));
215 if (OutputLength != 0)
216 {
217 if (OutputLength < sizeof(ULONG))
218 {
219 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
220 Irp->IoStatus.Information = 0;
221 }
222 else
223 {
224 *((PULONG)OutputBuffer) = DriveInfo->DiskChangeCount;
225 Irp->IoStatus.Status = STATUS_SUCCESS;
226 Irp->IoStatus.Information = sizeof(ULONG);
227 }
228 }
229 else
230 {
231 Irp->IoStatus.Status = STATUS_SUCCESS;
232 Irp->IoStatus.Information = 0;
233 }
234 break;
235
236 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
237 {
238 DPRINT(("floppy: IOCTL_DISK_GET_DRIVE_GEOMETRY Called\n"));
239 if(OutputLength < sizeof(DISK_GEOMETRY))
240 {
241 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
242 break;
243 }
244
245 /* This still works right even if DriveInfo->DiskGeometry->MediaType = Unknown */
246 memcpy(OutputBuffer, &DriveInfo->DiskGeometry, sizeof(DISK_GEOMETRY));
247 Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
248 break;
249 }
250
251 case IOCTL_DISK_FORMAT_TRACKS:
252 case IOCTL_DISK_FORMAT_TRACKS_EX:
253 DPRINT(("floppy: Format called; not supported yet\n"));
254 break;
255
256 case IOCTL_DISK_GET_PARTITION_INFO:
257 DPRINT(("floppy: IOCTL_DISK_GET_PARTITION_INFO Called; not supported\n"));
258 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
259 Irp->IoStatus.Information = 0;
260 break;
261
262 default:
263 DPRINT(("floppy: UNKNOWN IOCTL CODE: 0x%x\n", Code));
264 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
265 Irp->IoStatus.Information = 0;
266 break;
267 }
268
269 DPRINT(("floppy: ioctl: completing with status 0x%x\n", Irp->IoStatus.Status));
270 IoCompleteRequest(Irp, IO_NO_INCREMENT);
271
272 StopMotor(DriveInfo->ControllerInfo);
273 return;
274 }
275