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