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