1 /** @file
2   ISA Floppy Disk UEFI Driver conforming to the UEFI driver model
3 
4   1. Support two types diskette drive
5      1.44M drive and 2.88M drive (and now only support 1.44M)
6   2. Support two diskette drives per floppy disk controller
7   3. Use DMA channel 2 to transfer data
8   4. Do not use interrupt
9   5. Support diskette change line signal and write protect
10 
11 Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
12 This program and the accompanying materials
13 are licensed and made available under the terms and conditions of the BSD License
14 which accompanies this distribution.  The full text of the license may be found at
15 http://opensource.org/licenses/bsd-license.php
16 
17 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
18 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 
20 **/
21 
22 #include "IsaFloppy.h"
23 
24 LIST_ENTRY  mControllerHead = INITIALIZE_LIST_HEAD_VARIABLE (mControllerHead);
25 
26 //
27 // ISA Floppy Driver Binding Protocol
28 //
29 EFI_DRIVER_BINDING_PROTOCOL gFdcControllerDriver = {
30   FdcControllerDriverSupported,
31   FdcControllerDriverStart,
32   FdcControllerDriverStop,
33   0xa,
34   NULL,
35   NULL
36 };
37 
38 
39 /**
40   The main Entry Point for this driver.
41 
42   @param[in] ImageHandle  The firmware allocated handle for the EFI image.
43   @param[in] SystemTable  A pointer to the EFI System Table.
44 
45   @retval EFI_SUCCESS     The entry point is executed successfully.
46   @retval other           Some error occurs when executing this entry point.
47 **/
48 EFI_STATUS
49 EFIAPI
InitializeIsaFloppy(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)50 InitializeIsaFloppy(
51   IN EFI_HANDLE           ImageHandle,
52   IN EFI_SYSTEM_TABLE     *SystemTable
53   )
54 {
55   EFI_STATUS  Status;
56 
57   //
58   // Install driver model protocol(s).
59   //
60   Status = EfiLibInstallDriverBindingComponentName2 (
61              ImageHandle,
62              SystemTable,
63              &gFdcControllerDriver,
64              ImageHandle,
65              &gIsaFloppyComponentName,
66              &gIsaFloppyComponentName2
67              );
68   ASSERT_EFI_ERROR (Status);
69 
70   return Status;
71 }
72 
73 /**
74   Test if the controller is a floppy disk drive device
75 
76   @param[in] This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
77   @param[in] Controller           The handle of the controller to test.
78   @param[in] RemainingDevicePath  A pointer to the remaining portion of a device path.
79 
80   @retval EFI_SUCCESS             The device is supported by this driver.
81   @retval EFI_ALREADY_STARTED     The device is already being managed by this driver.
82   @retval EFI_ACCESS_DENIED       The device is already being managed by a different driver
83                                   or an application that requires exclusive access.
84   @retval EFI_UNSUPPORTED         The device is is not supported by this driver.
85 **/
86 EFI_STATUS
87 EFIAPI
FdcControllerDriverSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)88 FdcControllerDriverSupported (
89   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
90   IN EFI_HANDLE                   Controller,
91   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
92   )
93 {
94   EFI_STATUS                Status;
95   EFI_ISA_IO_PROTOCOL       *IsaIo;
96   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
97 
98   //
99   // Ignore the parameter RemainingDevicePath because this is a device driver.
100   //
101 
102   //
103   // Open the device path protocol
104   //
105   Status = gBS->OpenProtocol (
106                   Controller,
107                   &gEfiDevicePathProtocolGuid,
108                   (VOID **) &ParentDevicePath,
109                   This->DriverBindingHandle,
110                   Controller,
111                   EFI_OPEN_PROTOCOL_BY_DRIVER
112                   );
113   if (EFI_ERROR (Status)) {
114     return Status;
115   }
116 
117   gBS->CloseProtocol (
118          Controller,
119          &gEfiDevicePathProtocolGuid,
120          This->DriverBindingHandle,
121          Controller
122          );
123 
124   //
125   // Open the ISA I/O Protocol
126   //
127   Status = gBS->OpenProtocol (
128                   Controller,
129                   &gEfiIsaIoProtocolGuid,
130                   (VOID **) &IsaIo,
131                   This->DriverBindingHandle,
132                   Controller,
133                   EFI_OPEN_PROTOCOL_BY_DRIVER
134                   );
135   if (EFI_ERROR (Status)) {
136     return Status;
137   }
138   //
139   // Use the ISA I/O Protocol to see if Controller is a floppy disk drive device
140   //
141   Status = EFI_SUCCESS;
142   if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x604)) {
143     Status = EFI_UNSUPPORTED;
144   }
145   //
146   // Close the ISA I/O Protocol
147   //
148   gBS->CloseProtocol (
149          Controller,
150          &gEfiIsaIoProtocolGuid,
151          This->DriverBindingHandle,
152          Controller
153          );
154 
155   return Status;
156 }
157 
158 /**
159   Start this driver on Controller.
160 
161   @param[in] This                  A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
162   @param[in] ControllerHandle      The handle of the controller to start. This handle
163                                    must support a protocol interface that supplies
164                                    an I/O abstraction to the driver.
165   @param[in] RemainingDevicePath   A pointer to the remaining portion of a device path.
166                                    This parameter is ignored by device drivers, and is optional for bus drivers.
167 
168   @retval EFI_SUCCESS              The device was started.
169   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.
170                                    Currently not implemented.
171   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
172   @retval Others                   The driver failded to start the device.
173 **/
174 EFI_STATUS
175 EFIAPI
FdcControllerDriverStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)176 FdcControllerDriverStart (
177   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
178   IN EFI_HANDLE                   Controller,
179   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
180   )
181 {
182   EFI_STATUS                Status;
183   FDC_BLK_IO_DEV            *FdcDev;
184   EFI_ISA_IO_PROTOCOL       *IsaIo;
185   UINTN                     Index;
186   LIST_ENTRY                *List;
187   BOOLEAN                   Found;
188   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
189 
190   FdcDev  = NULL;
191   IsaIo   = NULL;
192 
193   //
194   // Open the device path protocol
195   //
196   Status = gBS->OpenProtocol (
197                   Controller,
198                   &gEfiDevicePathProtocolGuid,
199                   (VOID **) &ParentDevicePath,
200                   This->DriverBindingHandle,
201                   Controller,
202                   EFI_OPEN_PROTOCOL_BY_DRIVER
203                   );
204   if (EFI_ERROR (Status)) {
205     return Status;
206   }
207   //
208   // Report enable progress code
209   //
210   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
211     EFI_PROGRESS_CODE,
212     EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_ENABLE,
213     ParentDevicePath
214     );
215 
216   //
217   // Open the ISA I/O Protocol
218   //
219   Status = gBS->OpenProtocol (
220                   Controller,
221                   &gEfiIsaIoProtocolGuid,
222                   (VOID **) &IsaIo,
223                   This->DriverBindingHandle,
224                   Controller,
225                   EFI_OPEN_PROTOCOL_BY_DRIVER
226                   );
227   if (EFI_ERROR (Status)) {
228     goto Done;
229   }
230   //
231   // Allocate the floppy device's Device structure
232   //
233   FdcDev = AllocateZeroPool (sizeof (FDC_BLK_IO_DEV));
234   if (FdcDev == NULL) {
235     goto Done;
236   }
237   //
238   // Initialize the floppy device's device structure
239   //
240   FdcDev->Signature       = FDC_BLK_IO_DEV_SIGNATURE;
241   FdcDev->Handle          = Controller;
242   FdcDev->IsaIo           = IsaIo;
243   FdcDev->Disk            = (EFI_FDC_DISK) IsaIo->ResourceList->Device.UID;
244   FdcDev->Cache           = NULL;
245   FdcDev->Event           = NULL;
246   FdcDev->ControllerState = NULL;
247   FdcDev->DevicePath      = ParentDevicePath;
248 
249   FdcDev->ControllerNameTable = NULL;
250   AddName (FdcDev);
251 
252   //
253   // Look up the base address of the Floppy Disk Controller which controls this floppy device
254   //
255   for (Index = 0; FdcDev->IsaIo->ResourceList->ResourceItem[Index].Type != EfiIsaAcpiResourceEndOfList; Index++) {
256     if (FdcDev->IsaIo->ResourceList->ResourceItem[Index].Type == EfiIsaAcpiResourceIo) {
257       FdcDev->BaseAddress = (UINT16) FdcDev->IsaIo->ResourceList->ResourceItem[Index].StartRange;
258     }
259   }
260   //
261   // Maintain the list of floppy disk controllers
262   //
263   Found = FALSE;
264   List  = mControllerHead.ForwardLink;
265   while (List != &mControllerHead) {
266     FdcDev->ControllerState = FLOPPY_CONTROLLER_FROM_LIST_ENTRY (List);
267     if (FdcDev->BaseAddress == FdcDev->ControllerState->BaseAddress) {
268       Found = TRUE;
269       break;
270     }
271 
272     List = List->ForwardLink;
273   }
274 
275   if (!Found) {
276     //
277     // A new floppy disk controller controlling this floppy disk drive is found
278     //
279     FdcDev->ControllerState = AllocatePool (sizeof (FLOPPY_CONTROLLER_CONTEXT));
280     if (FdcDev->ControllerState == NULL) {
281       goto Done;
282     }
283 
284     FdcDev->ControllerState->Signature          = FLOPPY_CONTROLLER_CONTEXT_SIGNATURE;
285     FdcDev->ControllerState->FddResetPerformed  = FALSE;
286     FdcDev->ControllerState->NeedRecalibrate    = FALSE;
287     FdcDev->ControllerState->BaseAddress        = FdcDev->BaseAddress;
288     FdcDev->ControllerState->NumberOfDrive      = 0;
289 
290     InsertTailList (&mControllerHead, &FdcDev->ControllerState->Link);
291   }
292   //
293   // Create a timer event for each floppy disk drive device.
294   // This timer event is used to control the motor on and off
295   //
296   Status = gBS->CreateEvent (
297                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
298                   TPL_NOTIFY,
299                   FddTimerProc,
300                   FdcDev,
301                   &FdcDev->Event
302                   );
303   if (EFI_ERROR (Status)) {
304     goto Done;
305   }
306   //
307   // Reset the Floppy Disk Controller
308   //
309   if (!FdcDev->ControllerState->FddResetPerformed) {
310     FdcDev->ControllerState->FddResetPerformed  = TRUE;
311     FdcDev->ControllerState->FddResetStatus     = FddReset (FdcDev);
312   }
313 
314   if (EFI_ERROR (FdcDev->ControllerState->FddResetStatus)) {
315     Status = EFI_DEVICE_ERROR;
316     goto Done;
317   }
318 
319   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
320     EFI_PROGRESS_CODE,
321     EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_PRESENCE_DETECT,
322     ParentDevicePath
323     );
324 
325   //
326   // Discover the Floppy Drive
327   //
328   Status = DiscoverFddDevice (FdcDev);
329   if (EFI_ERROR (Status)) {
330     Status = EFI_DEVICE_ERROR;
331     goto Done;
332   }
333   //
334   // Install protocol interfaces for the serial device.
335   //
336   Status = gBS->InstallMultipleProtocolInterfaces (
337                   &Controller,
338                   &gEfiBlockIoProtocolGuid,
339                   &FdcDev->BlkIo,
340                   NULL
341                   );
342   if (!EFI_ERROR (Status)) {
343     FdcDev->ControllerState->NumberOfDrive++;
344   }
345 
346 Done:
347   if (EFI_ERROR (Status)) {
348 
349     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
350       EFI_ERROR_CODE | EFI_ERROR_MINOR,
351       EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_EC_CONTROLLER_ERROR,
352       ParentDevicePath
353       );
354 
355     //
356     // If a floppy drive device structure was allocated, then free it
357     //
358     if (FdcDev != NULL) {
359       if (FdcDev->Event != NULL) {
360         //
361         // Close the event for turning the motor off
362         //
363         gBS->CloseEvent (FdcDev->Event);
364       }
365 
366       FreeUnicodeStringTable (FdcDev->ControllerNameTable);
367       FreePool (FdcDev);
368     }
369 
370     //
371     // Close the ISA I/O Protocol
372     //
373     if (IsaIo != NULL) {
374       gBS->CloseProtocol (
375              Controller,
376              &gEfiIsaIoProtocolGuid,
377              This->DriverBindingHandle,
378              Controller
379              );
380     }
381 
382     //
383     // Close the device path protocol
384     //
385     gBS->CloseProtocol (
386            Controller,
387            &gEfiDevicePathProtocolGuid,
388            This->DriverBindingHandle,
389            Controller
390            );
391   }
392 
393   return Status;
394 }
395 
396 /**
397   Stop this driver on ControllerHandle.
398 
399   @param[in] This               A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
400   @param[in] ControllerHandle   A handle to the device being stopped. The handle must
401                                 support a bus specific I/O protocol for the driver
402                                 to use to stop the device.
403   @param[in] NumberOfChildren   The number of child device handles in ChildHandleBuffer.
404   @param[in] ChildHandleBuffer  An array of child handles to be freed. May be NULL
405                                 if NumberOfChildren is 0.
406 
407   @retval EFI_SUCCESS           The device was stopped.
408   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
409 **/
410 EFI_STATUS
411 EFIAPI
FdcControllerDriverStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)412 FdcControllerDriverStop (
413   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
414   IN  EFI_HANDLE                   Controller,
415   IN  UINTN                        NumberOfChildren,
416   IN  EFI_HANDLE                   *ChildHandleBuffer
417   )
418 {
419   EFI_STATUS            Status;
420   EFI_BLOCK_IO_PROTOCOL *BlkIo;
421   FDC_BLK_IO_DEV        *FdcDev;
422 
423   //
424   // Ignore NumberOfChildren since this is a device driver
425   //
426 
427   //
428   // Get the Block I/O Protocol on Controller
429   //
430   Status = gBS->OpenProtocol (
431                   Controller,
432                   &gEfiBlockIoProtocolGuid,
433                   (VOID **) &BlkIo,
434                   This->DriverBindingHandle,
435                   Controller,
436                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
437                   );
438   if (EFI_ERROR (Status)) {
439     return Status;
440   }
441   //
442   // Get the floppy drive device's Device structure
443   //
444   FdcDev = FDD_BLK_IO_FROM_THIS (BlkIo);
445 
446   //
447   // Report disable progress code
448   //
449   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
450     EFI_PROGRESS_CODE,
451     EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_DISABLE,
452     FdcDev->DevicePath
453     );
454 
455   //
456   // Uninstall the Block I/O Protocol
457   //
458   Status = gBS->UninstallProtocolInterface (
459                   Controller,
460                   &gEfiBlockIoProtocolGuid,
461                   &FdcDev->BlkIo
462                   );
463   if (EFI_ERROR (Status)) {
464     return Status;
465   }
466 
467   //
468   // Close the event for turning the motor off
469   //
470   gBS->CloseEvent (FdcDev->Event);
471 
472   //
473   // Turn the motor off on the floppy drive device
474   //
475   FddTimerProc (FdcDev->Event, FdcDev);
476 
477   //
478   // Close the device path protocol
479   //
480   gBS->CloseProtocol (
481          Controller,
482          &gEfiDevicePathProtocolGuid,
483          This->DriverBindingHandle,
484          Controller
485          );
486 
487   //
488   // Close the ISA I/O Protocol
489   //
490   gBS->CloseProtocol (
491          Controller,
492          &gEfiIsaIoProtocolGuid,
493          This->DriverBindingHandle,
494          Controller
495          );
496 
497   //
498   // Free the controller list if needed
499   //
500   FdcDev->ControllerState->NumberOfDrive--;
501 
502   //
503   // Free the cache if one was allocated
504   //
505   FdcFreeCache (FdcDev);
506 
507   //
508   // Free the floppy drive device's device structure
509   //
510   FreeUnicodeStringTable (FdcDev->ControllerNameTable);
511   FreePool (FdcDev);
512 
513   return EFI_SUCCESS;
514 }
515 
516