~ubuntu-branches/ubuntu/trusty/virtualbox-lts-xenial/trusty-updates

« back to all changes in this revision

Viewing changes to src/VBox/Devices/EFI/Firmware/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyCtrl.c

  • Committer: Package Import Robot
  • Author(s): Gianfranco Costamagna
  • Date: 2016-02-23 14:28:26 UTC
  • Revision ID: package-import@ubuntu.com-20160223142826-bdu69el2z6wa2a44
Tags: upstream-4.3.36-dfsg
ImportĀ upstreamĀ versionĀ 4.3.36-dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** @file
 
2
  Internal floppy disk controller programming functions for the floppy driver.
 
3
  
 
4
Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
 
5
This program and the accompanying materials
 
6
are licensed and made available under the terms and conditions of the BSD License
 
7
which accompanies this distribution.  The full text of the license may be found at
 
8
http://opensource.org/licenses/bsd-license.php
 
9
 
 
10
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 
11
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 
12
 
 
13
**/
 
14
 
 
15
#include "IsaFloppy.h"
 
16
 
 
17
/**
 
18
  Detect whether a floppy drive is present or not.
 
19
 
 
20
  @param[in] FdcDev  A pointer to the FDC_BLK_IO_DEV
 
21
 
 
22
  @retval EFI_SUCCESS    The floppy disk drive is present
 
23
  @retval EFI_NOT_FOUND  The floppy disk drive is not present
 
24
**/
 
25
EFI_STATUS
 
26
DiscoverFddDevice (
 
27
  IN FDC_BLK_IO_DEV  *FdcDev
 
28
  )
 
29
{
 
30
  EFI_STATUS  Status;
 
31
 
 
32
  FdcDev->BlkIo.Media = &FdcDev->BlkMedia;
 
33
 
 
34
  Status = FddIdentify (FdcDev);
 
35
  if (EFI_ERROR (Status)) {
 
36
    return EFI_NOT_FOUND;
 
37
  }
 
38
 
 
39
  FdcDev->BlkIo.Reset               = FdcReset;
 
40
  FdcDev->BlkIo.FlushBlocks         = FddFlushBlocks;
 
41
  FdcDev->BlkIo.ReadBlocks          = FddReadBlocks;
 
42
  FdcDev->BlkIo.WriteBlocks         = FddWriteBlocks;
 
43
  FdcDev->BlkMedia.LogicalPartition = FALSE;
 
44
  FdcDev->BlkMedia.WriteCaching     = FALSE;
 
45
 
 
46
  return EFI_SUCCESS;
 
47
}
 
48
 
 
49
/**
 
50
  Do recalibrate and check if the drive is present or not
 
51
  and set the media parameters if the driver is present.
 
52
  
 
53
  @param[in] FdcDev  A pointer to the FDC_BLK_IO_DEV
 
54
 
 
55
  @retval EFI_SUCCESS       The floppy disk drive is present
 
56
  @retval EFI_DEVICE_ERROR  The floppy disk drive is not present
 
57
**/
 
58
EFI_STATUS
 
59
FddIdentify (
 
60
  IN FDC_BLK_IO_DEV  *FdcDev
 
61
  )
 
62
{
 
63
  EFI_STATUS  Status;
 
64
 
 
65
  //
 
66
  // Set Floppy Disk Controller's motor on
 
67
  //
 
68
  Status = MotorOn (FdcDev);
 
69
  if (EFI_ERROR (Status)) {
 
70
    return EFI_DEVICE_ERROR;
 
71
  }
 
72
 
 
73
  Status = Recalibrate (FdcDev);
 
74
 
 
75
  if (EFI_ERROR (Status)) {
 
76
    MotorOff (FdcDev);
 
77
    FdcDev->ControllerState->NeedRecalibrate = TRUE;
 
78
    return EFI_DEVICE_ERROR;
 
79
  }
 
80
  //
 
81
  // Set Media Parameter
 
82
  //
 
83
  FdcDev->BlkIo.Media->RemovableMedia = TRUE;
 
84
  FdcDev->BlkIo.Media->MediaPresent   = TRUE;
 
85
  FdcDev->BlkIo.Media->MediaId = 0;
 
86
 
 
87
  //
 
88
  // Check Media
 
89
  //
 
90
  Status = DisketChanged (FdcDev);
 
91
 
 
92
  if (Status == EFI_NO_MEDIA) {
 
93
    FdcDev->BlkIo.Media->MediaPresent = FALSE;
 
94
  } else if ((Status != EFI_MEDIA_CHANGED) &&
 
95
             (Status != EFI_SUCCESS)) {
 
96
    MotorOff (FdcDev);
 
97
    return Status;
 
98
  }
 
99
 
 
100
  //
 
101
  // Check Disk Write Protected
 
102
  //
 
103
  Status = SenseDrvStatus (FdcDev, 0);
 
104
 
 
105
  if (Status == EFI_WRITE_PROTECTED) {
 
106
    FdcDev->BlkIo.Media->ReadOnly = TRUE;
 
107
  } else if (Status == EFI_SUCCESS) {
 
108
    FdcDev->BlkIo.Media->ReadOnly = FALSE;
 
109
  } else {
 
110
    return EFI_DEVICE_ERROR;
 
111
  }
 
112
 
 
113
  MotorOff (FdcDev);
 
114
 
 
115
  //
 
116
  // Set Media Default Type
 
117
  //
 
118
  FdcDev->BlkIo.Media->BlockSize  = DISK_1440K_BYTEPERSECTOR;
 
119
  FdcDev->BlkIo.Media->LastBlock  = DISK_1440K_EOT * 2 * (DISK_1440K_MAXTRACKNUM + 1) - 1;
 
120
 
 
121
  return EFI_SUCCESS;
 
122
}
 
123
 
 
124
/**
 
125
  Reset the Floppy Logic Drive.
 
126
  
 
127
  @param  FdcDev FDC_BLK_IO_DEV * : A pointer to the FDC_BLK_IO_DEV
 
128
  
 
129
  @retval EFI_SUCCESS:    The Floppy Logic Drive is reset
 
130
  @retval EFI_DEVICE_ERROR: The Floppy Logic Drive is not functioning correctly and
 
131
                      can not be reset
 
132
 
 
133
**/
 
134
EFI_STATUS
 
135
FddReset (
 
136
  IN FDC_BLK_IO_DEV  *FdcDev
 
137
  )
 
138
{
 
139
  UINT8 Data;
 
140
  UINT8 StatusRegister0;
 
141
  UINT8 PresentCylinderNumber;
 
142
  UINTN Index;
 
143
 
 
144
  //
 
145
  // Report reset progress code
 
146
  //
 
147
  REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 
148
    EFI_PROGRESS_CODE,
 
149
    EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_RESET,
 
150
    FdcDev->DevicePath
 
151
    );
 
152
 
 
153
  //
 
154
  // Reset specified Floppy Logic Drive according to FdcDev -> Disk
 
155
  // Set Digital Output Register(DOR) to do reset work
 
156
  //   bit0 & bit1 of DOR : Drive Select
 
157
  //   bit2 : Reset bit
 
158
  //   bit3 : DMA and Int bit
 
159
  // Reset : a "0" written to bit2 resets the FDC, this reset will remain
 
160
  //         active until
 
161
  //         a "1" is written to this bit.
 
162
  // Reset step 1:
 
163
  //         use bit0 & bit1 to  select the logic drive
 
164
  //         write "0" to bit2
 
165
  //
 
166
  Data = 0x0;
 
167
  Data = (UINT8) (Data | (SELECT_DRV & FdcDev->Disk));
 
168
  FdcWritePort (FdcDev, FDC_REGISTER_DOR, Data);
 
169
 
 
170
  //
 
171
  // wait some time,at least 120us
 
172
  //
 
173
  MicroSecondDelay (500);
 
174
 
 
175
  //
 
176
  // Reset step 2:
 
177
  //   write "1" to bit2
 
178
  //   write "1" to bit3 : enable DMA
 
179
  //
 
180
  Data |= 0x0C;
 
181
  FdcWritePort (FdcDev, FDC_REGISTER_DOR, Data);
 
182
 
 
183
  //
 
184
  // Experience value
 
185
  //
 
186
  MicroSecondDelay (2000);
 
187
 
 
188
  //
 
189
  // wait specified floppy logic drive is not busy
 
190
  //
 
191
  if (EFI_ERROR (FddWaitForBSYClear (FdcDev, 1))) {
 
192
    return EFI_DEVICE_ERROR;
 
193
  }
 
194
  //
 
195
  // Set the Transfer Data Rate
 
196
  //
 
197
  FdcWritePort (FdcDev, FDC_REGISTER_CCR, 0x0);
 
198
 
 
199
  //
 
200
  // Experience value
 
201
  //
 
202
  MicroSecondDelay (100);
 
203
 
 
204
  //
 
205
  // Issue Sense interrupt command for each drive (total 4 drives)
 
206
  //
 
207
  for (Index = 0; Index < 4; Index++) {
 
208
    if (EFI_ERROR (SenseIntStatus (FdcDev, &StatusRegister0, &PresentCylinderNumber))) {
 
209
      return EFI_DEVICE_ERROR;
 
210
    }
 
211
  }
 
212
  //
 
213
  // issue Specify command
 
214
  //
 
215
  if (EFI_ERROR (Specify (FdcDev))) {
 
216
    return EFI_DEVICE_ERROR;
 
217
  }
 
218
 
 
219
  return EFI_SUCCESS;
 
220
}
 
221
 
 
222
/**
 
223
  Turn the floppy disk drive's motor on.
 
224
  The drive's motor must be on before any command can be executed.
 
225
  
 
226
  @param[in] FdcDev  A pointer to the FDC_BLK_IO_DEV
 
227
  
 
228
  @retval  EFI_SUCCESS            The drive's motor was turned on successfully
 
229
  @retval  EFI_DEVICE_ERROR       The drive is busy, so can not turn motor on
 
230
**/
 
231
EFI_STATUS
 
232
MotorOn (
 
233
  IN FDC_BLK_IO_DEV  *FdcDev
 
234
  )
 
235
{
 
236
  EFI_STATUS  Status;
 
237
  UINT8       DorData;
 
238
 
 
239
  //
 
240
  // Control of the floppy drive motors is a big pain. If motor is off, you have
 
241
  // to turn it on first. But you can not leave the motor on all the time, since
 
242
  // that would wear out the disk. On the other hand, if you turn the motor off
 
243
  // after each operation, the system performance will be awful. The compromise
 
244
  // used in this driver is to leave the motor on for 2 seconds after
 
245
  // each operation. If a new operation is started in that interval(2s),
 
246
  // the motor need not be turned on again. If no new operation is started,
 
247
  // a timer goes off and the motor is turned off
 
248
  //
 
249
  //
 
250
  // Cancel the timer
 
251
  //
 
252
  Status = gBS->SetTimer (FdcDev->Event, TimerCancel, 0);
 
253
  ASSERT_EFI_ERROR (Status);
 
254
 
 
255
  //
 
256
  // Get the motor status
 
257
  //
 
258
  DorData = FdcReadPort (FdcDev, FDC_REGISTER_DOR);
 
259
 
 
260
  if (((FdcDev->Disk == FdcDisk0) && ((DorData & 0x10) == 0x10)) ||
 
261
      ((FdcDev->Disk == FdcDisk1) && ((DorData & 0x21) == 0x21))
 
262
      ) {
 
263
    return EFI_SUCCESS;
 
264
  }
 
265
  //
 
266
  // The drive's motor is off, so need turn it on
 
267
  // first look at command and drive are busy or not
 
268
  //
 
269
  if (EFI_ERROR (FddWaitForBSYClear (FdcDev, 1))) {
 
270
    return EFI_DEVICE_ERROR;
 
271
  }
 
272
  //
 
273
  // for drive A: 1CH, drive B: 2DH
 
274
  //
 
275
  DorData = 0x0C;
 
276
  DorData = (UINT8) (DorData | (SELECT_DRV & FdcDev->Disk));
 
277
  if (FdcDev->Disk == FdcDisk0) {
 
278
    //
 
279
    // drive A
 
280
    //
 
281
    DorData |= DRVA_MOTOR_ON;
 
282
  } else {
 
283
    //
 
284
    // drive B
 
285
    //
 
286
    DorData |= DRVB_MOTOR_ON;
 
287
  }
 
288
 
 
289
  FdcWritePort (FdcDev, FDC_REGISTER_DOR, DorData);
 
290
 
 
291
  //
 
292
  // Experience value
 
293
  //
 
294
  MicroSecondDelay (4000);
 
295
 
 
296
  return EFI_SUCCESS;
 
297
}
 
298
 
 
299
/**
 
300
  Set a Timer and when Timer goes off, turn the motor off.
 
301
  
 
302
  @param[in] FdcDev  A pointer to the FDC_BLK_IO_DEV
 
303
  
 
304
  @retval  EFI_SUCCESS            Set the Timer successfully
 
305
  @retval  EFI_INVALID_PARAMETER  Fail to Set the timer
 
306
**/
 
307
EFI_STATUS
 
308
MotorOff (
 
309
  IN FDC_BLK_IO_DEV  *FdcDev
 
310
  )
 
311
{
 
312
  //
 
313
  // Set the timer : 2s
 
314
  //
 
315
  return gBS->SetTimer (FdcDev->Event, TimerRelative, 20000000);
 
316
}
 
317
 
 
318
/**
 
319
  Detect whether the disk in the drive is changed or not.
 
320
  
 
321
  @param[in] FdcDev  A pointer to FDC_BLK_IO_DEV
 
322
  
 
323
  @retval  EFI_SUCCESS        No disk media change
 
324
  @retval  EFI_DEVICE_ERROR   Fail to do the recalibrate or seek operation
 
325
  @retval  EFI_NO_MEDIA       No disk in the drive
 
326
  @retval  EFI_MEDIA_CHANGED  There is a new disk in the drive
 
327
**/
 
328
EFI_STATUS
 
329
DisketChanged (
 
330
  IN FDC_BLK_IO_DEV  *FdcDev
 
331
  )
 
332
{
 
333
  EFI_STATUS  Status;
 
334
  UINT8       Data;
 
335
 
 
336
  //
 
337
  // Check change line
 
338
  //
 
339
  Data = FdcReadPort (FdcDev, FDC_REGISTER_DIR);
 
340
 
 
341
  //
 
342
  // Io delay
 
343
  //
 
344
  MicroSecondDelay (50);
 
345
 
 
346
  if ((Data & DIR_DCL) == 0x80) {
 
347
    //
 
348
    // disk change line is active
 
349
    //
 
350
    if (FdcDev->PresentCylinderNumber != 0) {
 
351
      Status = Recalibrate (FdcDev);
 
352
    } else {
 
353
      Status = Seek (FdcDev, 0x30);
 
354
    }
 
355
 
 
356
    if (EFI_ERROR (Status)) {
 
357
      FdcDev->ControllerState->NeedRecalibrate = TRUE;
 
358
      return EFI_DEVICE_ERROR;
 
359
      //
 
360
      // Fail to do the seek or recalibrate operation
 
361
      //
 
362
    }
 
363
 
 
364
    Data = FdcReadPort (FdcDev, FDC_REGISTER_DIR);
 
365
 
 
366
    //
 
367
    // Io delay
 
368
    //
 
369
    MicroSecondDelay (50);
 
370
 
 
371
    if ((Data & DIR_DCL) == 0x80) {
 
372
      return EFI_NO_MEDIA;
 
373
    }
 
374
 
 
375
    return EFI_MEDIA_CHANGED;
 
376
  }
 
377
 
 
378
  return EFI_SUCCESS;
 
379
}
 
380
 
 
381
/**
 
382
  Do the Specify command, this command sets DMA operation
 
383
  and the initial values for each of the three internal
 
384
  times: HUT, SRT and HLT.
 
385
  
 
386
  @param[in] FdcDev  Pointer to instance of FDC_BLK_IO_DEV
 
387
  
 
388
  @retval EFI_SUCCESS       Execute the Specify command successfully
 
389
  @retval EFI_DEVICE_ERROR  Fail to execute the command
 
390
**/
 
391
EFI_STATUS
 
392
Specify (
 
393
  IN FDC_BLK_IO_DEV  *FdcDev
 
394
  )
 
395
{
 
396
  FDD_SPECIFY_CMD Command;
 
397
  UINTN           Index;
 
398
  UINT8           *CommandPointer;
 
399
 
 
400
  ZeroMem (&Command, sizeof (FDD_SPECIFY_CMD));
 
401
  Command.CommandCode = SPECIFY_CMD;
 
402
  //
 
403
  // set SRT, HUT
 
404
  //
 
405
  Command.SrtHut = 0xdf;
 
406
  //
 
407
  // 0xdf;
 
408
  //
 
409
  // set HLT and DMA
 
410
  //
 
411
  Command.HltNd   = 0x02;
 
412
 
 
413
  CommandPointer  = (UINT8 *) (&Command);
 
414
  for (Index = 0; Index < sizeof (FDD_SPECIFY_CMD); Index++) {
 
415
    if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) {
 
416
      return EFI_DEVICE_ERROR;
 
417
    }
 
418
  }
 
419
 
 
420
  return EFI_SUCCESS;
 
421
}
 
422
 
 
423
/**
 
424
  Set the head of floppy drive to track 0.
 
425
 
 
426
  @param  FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV
 
427
  @retval EFI_SUCCESS:    Execute the Recalibrate operation successfully
 
428
  @retval EFI_DEVICE_ERROR: Fail to execute the Recalibrate operation
 
429
 
 
430
**/
 
431
EFI_STATUS
 
432
Recalibrate (
 
433
  IN FDC_BLK_IO_DEV  *FdcDev
 
434
  )
 
435
{
 
436
  FDD_COMMAND_PACKET2 Command;
 
437
  UINTN               Index;
 
438
  UINT8               StatusRegister0;
 
439
  UINT8               PresentCylinderNumber;
 
440
  UINT8               *CommandPointer;
 
441
  UINT8               Count;
 
442
 
 
443
  Count = 2;
 
444
 
 
445
  while (Count > 0) {
 
446
    ZeroMem (&Command, sizeof (FDD_COMMAND_PACKET2));
 
447
    Command.CommandCode = RECALIBRATE_CMD;
 
448
    //
 
449
    // drive select
 
450
    //
 
451
    if (FdcDev->Disk == FdcDisk0) {
 
452
      Command.DiskHeadSel = 0;
 
453
      //
 
454
      // 0
 
455
      //
 
456
    } else {
 
457
      Command.DiskHeadSel = 1;
 
458
      //
 
459
      // 1
 
460
      //
 
461
    }
 
462
 
 
463
    CommandPointer = (UINT8 *) (&Command);
 
464
    for (Index = 0; Index < sizeof (FDD_COMMAND_PACKET2); Index++) {
 
465
      if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) {
 
466
        return EFI_DEVICE_ERROR;
 
467
      }
 
468
    }
 
469
    //
 
470
    // Experience value
 
471
    //
 
472
    MicroSecondDelay (250000);
 
473
    //
 
474
    // need modify according to 1.44M or 2.88M
 
475
    //
 
476
    if (EFI_ERROR (SenseIntStatus (FdcDev, &StatusRegister0, &PresentCylinderNumber))) {
 
477
      return EFI_DEVICE_ERROR;
 
478
    }
 
479
 
 
480
    if ((StatusRegister0 & 0xf0) == 0x20 && PresentCylinderNumber == 0) {
 
481
      FdcDev->PresentCylinderNumber             = 0;
 
482
      FdcDev->ControllerState->NeedRecalibrate  = FALSE;
 
483
      return EFI_SUCCESS;
 
484
    } else {
 
485
      Count--;
 
486
      if (Count == 0) {
 
487
        return EFI_DEVICE_ERROR;
 
488
      }
 
489
    }
 
490
  }
 
491
  //
 
492
  // end while
 
493
  //
 
494
  return EFI_SUCCESS;
 
495
}
 
496
 
 
497
/**
 
498
  Set the head of floppy drive to the new cylinder.
 
499
  
 
500
  @param  FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV
 
501
  @param  Lba EFI_LBA     : The logic block address want to seek
 
502
  
 
503
  @retval  EFI_SUCCESS:    Execute the Seek operation successfully
 
504
  @retval  EFI_DEVICE_ERROR: Fail to execute the Seek operation
 
505
 
 
506
**/
 
507
EFI_STATUS
 
508
Seek (
 
509
  IN FDC_BLK_IO_DEV  *FdcDev,
 
510
  IN EFI_LBA         Lba
 
511
  )
 
512
{
 
513
  FDD_SEEK_CMD  Command;
 
514
  UINT8         EndOfTrack;
 
515
  UINT8         Head;
 
516
  UINT8         Cylinder;
 
517
  UINT8         StatusRegister0;
 
518
  UINT8         *CommandPointer;
 
519
  UINT8         PresentCylinderNumber;
 
520
  UINTN         Index;
 
521
  UINT8         DelayTime;
 
522
 
 
523
  if (FdcDev->ControllerState->NeedRecalibrate) {
 
524
    if (EFI_ERROR (Recalibrate (FdcDev))) {
 
525
      FdcDev->ControllerState->NeedRecalibrate = TRUE;
 
526
      return EFI_DEVICE_ERROR;
 
527
    }
 
528
  }
 
529
 
 
530
  EndOfTrack = DISK_1440K_EOT;
 
531
  //
 
532
  // Calculate cylinder based on Lba and EOT
 
533
  //
 
534
  Cylinder = (UINT8) ((UINTN) Lba / EndOfTrack / 2);
 
535
 
 
536
  //
 
537
  // if the destination cylinder is the present cylinder, unnecessary to do the
 
538
  // seek operation
 
539
  //
 
540
  if (FdcDev->PresentCylinderNumber == Cylinder) {
 
541
    return EFI_SUCCESS;
 
542
  }
 
543
  //
 
544
  // Calculate the head : 0 or 1
 
545
  //
 
546
  Head = (UINT8) ((UINTN) Lba / EndOfTrack % 2);
 
547
 
 
548
  ZeroMem (&Command, sizeof (FDD_SEEK_CMD));
 
549
  Command.CommandCode = SEEK_CMD;
 
550
  if (FdcDev->Disk == FdcDisk0) {
 
551
    Command.DiskHeadSel = 0;
 
552
    //
 
553
    // 0
 
554
    //
 
555
  } else {
 
556
    Command.DiskHeadSel = 1;
 
557
    //
 
558
    // 1
 
559
    //
 
560
  }
 
561
 
 
562
  Command.DiskHeadSel = (UINT8) (Command.DiskHeadSel | (Head << 2));
 
563
  Command.NewCylinder = Cylinder;
 
564
 
 
565
  CommandPointer      = (UINT8 *) (&Command);
 
566
  for (Index = 0; Index < sizeof (FDD_SEEK_CMD); Index++) {
 
567
    if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) {
 
568
      return EFI_DEVICE_ERROR;
 
569
    }
 
570
  }
 
571
  //
 
572
  // Io delay
 
573
  //
 
574
  MicroSecondDelay (100);
 
575
 
 
576
  //
 
577
  // Calculate waiting time
 
578
  //
 
579
  if (FdcDev->PresentCylinderNumber > Cylinder) {
 
580
    DelayTime = (UINT8) (FdcDev->PresentCylinderNumber - Cylinder);
 
581
  } else {
 
582
    DelayTime = (UINT8) (Cylinder - FdcDev->PresentCylinderNumber);
 
583
  }
 
584
 
 
585
  MicroSecondDelay ((DelayTime + 1) * 4000);
 
586
 
 
587
  if (EFI_ERROR (SenseIntStatus (FdcDev, &StatusRegister0, &PresentCylinderNumber))) {
 
588
    return EFI_DEVICE_ERROR;
 
589
  }
 
590
 
 
591
  if ((StatusRegister0 & 0xf0) == 0x20) {
 
592
    FdcDev->PresentCylinderNumber = Command.NewCylinder;
 
593
    return EFI_SUCCESS;
 
594
  } else {
 
595
    FdcDev->ControllerState->NeedRecalibrate = TRUE;
 
596
    return EFI_DEVICE_ERROR;
 
597
  }
 
598
}
 
599
 
 
600
/**
 
601
  Do the Sense Interrupt Status command, this command
 
602
  resets the interrupt signal.
 
603
  
 
604
  @param  FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV
 
605
  @param  StatusRegister0 UINT8 *: Be used to save Status Register 0 read from FDC
 
606
  @param  PresentCylinderNumber  UINT8 *: Be used to save present cylinder number
 
607
                                    read from FDC
 
608
  
 
609
  @retval  EFI_SUCCESS:    Execute the Sense Interrupt Status command successfully
 
610
  @retval  EFI_DEVICE_ERROR: Fail to execute the command
 
611
 
 
612
**/
 
613
EFI_STATUS
 
614
SenseIntStatus (
 
615
  IN     FDC_BLK_IO_DEV  *FdcDev,
 
616
  IN OUT UINT8           *StatusRegister0,
 
617
  IN OUT UINT8           *PresentCylinderNumber
 
618
  )
 
619
{
 
620
  UINT8 Command;
 
621
 
 
622
  Command = SENSE_INT_STATUS_CMD;
 
623
  if (EFI_ERROR (DataOutByte (FdcDev, &Command))) {
 
624
    return EFI_DEVICE_ERROR;
 
625
  }
 
626
 
 
627
  if (EFI_ERROR (DataInByte (FdcDev, StatusRegister0))) {
 
628
    return EFI_DEVICE_ERROR;
 
629
  }
 
630
 
 
631
  if (EFI_ERROR (DataInByte (FdcDev, PresentCylinderNumber))) {
 
632
    return EFI_DEVICE_ERROR;
 
633
  }
 
634
 
 
635
  return EFI_SUCCESS;
 
636
}
 
637
 
 
638
/**
 
639
  Do the Sense Drive Status command.
 
640
  
 
641
  @param  FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV
 
642
  @param  Lba EFI_LBA     : Logic block address
 
643
  
 
644
  @retval  EFI_SUCCESS:    Execute the Sense Drive Status command successfully
 
645
  @retval  EFI_DEVICE_ERROR: Fail to execute the command
 
646
  @retval  EFI_WRITE_PROTECTED:The disk is write protected
 
647
 
 
648
**/
 
649
EFI_STATUS
 
650
SenseDrvStatus (
 
651
  IN FDC_BLK_IO_DEV  *FdcDev,
 
652
  IN EFI_LBA         Lba
 
653
  )
 
654
{
 
655
  FDD_COMMAND_PACKET2 Command;
 
656
  UINT8               Head;
 
657
  UINT8               EndOfTrack;
 
658
  UINTN               Index;
 
659
  UINT8               StatusRegister3;
 
660
  UINT8               *CommandPointer;
 
661
 
 
662
  //
 
663
  // Sense Drive Status command obtains drive status information,
 
664
  // it has not execution phase and goes directly to the result phase from the
 
665
  // command phase, Status Register 3 contains the drive status information
 
666
  //
 
667
  ZeroMem (&Command, sizeof (FDD_COMMAND_PACKET2));
 
668
  Command.CommandCode = SENSE_DRV_STATUS_CMD;
 
669
 
 
670
  if (FdcDev->Disk == FdcDisk0) {
 
671
    Command.DiskHeadSel = 0;
 
672
  } else {
 
673
    Command.DiskHeadSel = 1;
 
674
  }
 
675
 
 
676
  EndOfTrack  = DISK_1440K_EOT;
 
677
  Head        = (UINT8) ((UINTN) Lba / EndOfTrack % 2);
 
678
  Command.DiskHeadSel = (UINT8) (Command.DiskHeadSel | (Head << 2));
 
679
 
 
680
  CommandPointer = (UINT8 *) (&Command);
 
681
  for (Index = 0; Index < sizeof (FDD_COMMAND_PACKET2); Index++) {
 
682
    if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) {
 
683
      return EFI_DEVICE_ERROR;
 
684
    }
 
685
  }
 
686
 
 
687
  if (EFI_ERROR (DataInByte (FdcDev, &StatusRegister3))) {
 
688
    return EFI_DEVICE_ERROR;
 
689
  }
 
690
  //
 
691
  // Io delay
 
692
  //
 
693
  MicroSecondDelay (50);
 
694
 
 
695
  //
 
696
  // Check Status Register 3 to get drive status information
 
697
  //
 
698
  return CheckStatus3 (StatusRegister3);
 
699
}
 
700
 
 
701
/**
 
702
  Update the disk media properties and if necessary reinstall Block I/O interface.
 
703
 
 
704
  @param  FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV
 
705
  
 
706
  @retval  EFI_SUCCESS:    Do the operation successfully
 
707
  @retval  EFI_DEVICE_ERROR: Fail to the operation
 
708
 
 
709
**/
 
710
EFI_STATUS
 
711
DetectMedia (
 
712
  IN FDC_BLK_IO_DEV  *FdcDev
 
713
  )
 
714
{
 
715
  EFI_STATUS  Status;
 
716
  BOOLEAN     Reset;
 
717
  BOOLEAN     ReadOnlyLastTime;
 
718
  BOOLEAN     MediaPresentLastTime;
 
719
 
 
720
  Reset                = FALSE;
 
721
  ReadOnlyLastTime     = FdcDev->BlkIo.Media->ReadOnly;
 
722
  MediaPresentLastTime = FdcDev->BlkIo.Media->MediaPresent;
 
723
 
 
724
  //
 
725
  // Check disk change
 
726
  //
 
727
  Status = DisketChanged (FdcDev);
 
728
 
 
729
  if (Status == EFI_MEDIA_CHANGED) {
 
730
    FdcDev->BlkIo.Media->MediaId++;
 
731
    FdcDev->BlkIo.Media->MediaPresent = TRUE;
 
732
    Reset = TRUE;
 
733
  } else if (Status == EFI_NO_MEDIA) {
 
734
    FdcDev->BlkIo.Media->MediaPresent = FALSE;
 
735
  } else if (Status != EFI_SUCCESS) {
 
736
    MotorOff (FdcDev);
 
737
    return Status;
 
738
    //
 
739
    // EFI_DEVICE_ERROR
 
740
    //
 
741
  }
 
742
 
 
743
  if (FdcDev->BlkIo.Media->MediaPresent) {
 
744
    //
 
745
    // Check disk write protected
 
746
    //
 
747
    Status = SenseDrvStatus (FdcDev, 0);
 
748
    if (Status == EFI_WRITE_PROTECTED) {
 
749
      FdcDev->BlkIo.Media->ReadOnly = TRUE;
 
750
    } else {
 
751
      FdcDev->BlkIo.Media->ReadOnly = FALSE;
 
752
    }
 
753
  }
 
754
 
 
755
  if (FdcDev->BlkIo.Media->MediaPresent && (ReadOnlyLastTime != FdcDev->BlkIo.Media->ReadOnly)) {
 
756
    Reset = TRUE;
 
757
  }
 
758
 
 
759
  if (MediaPresentLastTime != FdcDev->BlkIo.Media->MediaPresent) {
 
760
    Reset = TRUE;
 
761
  }
 
762
 
 
763
  if (Reset) {
 
764
    Status = gBS->ReinstallProtocolInterface (
 
765
                    FdcDev->Handle,
 
766
                    &gEfiBlockIoProtocolGuid,
 
767
                    &FdcDev->BlkIo,
 
768
                    &FdcDev->BlkIo
 
769
                    );
 
770
 
 
771
    if (EFI_ERROR (Status)) {
 
772
      return Status;
 
773
    }
 
774
  }
 
775
 
 
776
  return EFI_SUCCESS;
 
777
}
 
778
 
 
779
/**
 
780
  Set the data rate and so on.
 
781
 
 
782
  @param  FdcDev  A pointer to FDC_BLK_IO_DEV
 
783
 
 
784
  @retval EFI_SUCCESS success to set the data rate
 
785
**/
 
786
EFI_STATUS
 
787
Setup (
 
788
  IN FDC_BLK_IO_DEV  *FdcDev
 
789
  )
 
790
{
 
791
  EFI_STATUS  Status;
 
792
 
 
793
  //
 
794
  // Set data rate 500kbs
 
795
  //
 
796
  FdcWritePort (FdcDev, FDC_REGISTER_CCR, 0x0);
 
797
 
 
798
  //
 
799
  // Io delay
 
800
  //
 
801
  MicroSecondDelay (50);
 
802
 
 
803
  Status = Specify (FdcDev);
 
804
 
 
805
  if (EFI_ERROR (Status)) {
 
806
    return EFI_DEVICE_ERROR;
 
807
  }
 
808
 
 
809
  return EFI_SUCCESS;
 
810
}
 
811
 
 
812
/**
 
813
  Read or Write a number of blocks in the same cylinder.
 
814
 
 
815
  @param  FdcDev      A pointer to FDC_BLK_IO_DEV
 
816
  @param  HostAddress device address 
 
817
  @param  Lba         The starting logic block address to read from on the device
 
818
  @param  NumberOfBlocks The number of block wanted to be read or write
 
819
  @param  Read        Operation type: read or write
 
820
  
 
821
  @retval EFI_SUCCESS Success operate
 
822
 
 
823
**/
 
824
EFI_STATUS
 
825
ReadWriteDataSector (
 
826
  IN  FDC_BLK_IO_DEV  *FdcDev,
 
827
  IN  VOID            *HostAddress,
 
828
  IN  EFI_LBA         Lba,
 
829
  IN  UINTN           NumberOfBlocks,
 
830
  IN  BOOLEAN         Read
 
831
  )
 
832
{
 
833
  EFI_STATUS                                    Status;
 
834
  FDD_COMMAND_PACKET1                           Command;
 
835
  FDD_RESULT_PACKET                             Result;
 
836
  UINTN                                         Index;
 
837
  UINTN                                         Times;
 
838
  UINT8                                         *CommandPointer;
 
839
 
 
840
  EFI_PHYSICAL_ADDRESS                          DeviceAddress;
 
841
  EFI_ISA_IO_PROTOCOL                           *IsaIo;
 
842
  UINTN                                         NumberofBytes;
 
843
  VOID                                          *Mapping;
 
844
  EFI_ISA_IO_PROTOCOL_OPERATION                 Operation;
 
845
  EFI_STATUS                                    Status1;
 
846
  UINT8                                         Channel;
 
847
  EFI_ISA_ACPI_RESOURCE                         *ResourceItem;
 
848
  UINT32                                        Attribute;
 
849
 
 
850
  Status = Seek (FdcDev, Lba);
 
851
  if (EFI_ERROR (Status)) {
 
852
    return EFI_DEVICE_ERROR;
 
853
  }
 
854
  //
 
855
  // Map Dma
 
856
  //
 
857
  IsaIo         = FdcDev->IsaIo;
 
858
  NumberofBytes = NumberOfBlocks * 512;
 
859
  if (Read == READ) {
 
860
    Operation = EfiIsaIoOperationSlaveWrite;
 
861
  } else {
 
862
    Operation = EfiIsaIoOperationSlaveRead;
 
863
  }
 
864
 
 
865
  ResourceItem  = IsaIo->ResourceList->ResourceItem;
 
866
  Index         = 0;
 
867
  while (ResourceItem[Index].Type != EfiIsaAcpiResourceEndOfList) {
 
868
    if (ResourceItem[Index].Type == EfiIsaAcpiResourceDma) {
 
869
      break;
 
870
    }
 
871
 
 
872
    Index++;
 
873
  }
 
874
 
 
875
  if (ResourceItem[Index].Type == EfiIsaAcpiResourceEndOfList) {
 
876
    return EFI_DEVICE_ERROR;
 
877
  }
 
878
 
 
879
  Channel   = (UINT8) IsaIo->ResourceList->ResourceItem[Index].StartRange;
 
880
  Attribute = IsaIo->ResourceList->ResourceItem[Index].Attribute;
 
881
 
 
882
  Status1 = IsaIo->Map (
 
883
                    IsaIo,
 
884
                    Operation,
 
885
                    Channel,
 
886
                    Attribute,
 
887
                    HostAddress,
 
888
                    &NumberofBytes,
 
889
                    &DeviceAddress,
 
890
                    &Mapping
 
891
                    );
 
892
  if (EFI_ERROR (Status1)) {
 
893
    return Status1;
 
894
  }
 
895
 
 
896
  //
 
897
  // Allocate Read or Write command packet
 
898
  //
 
899
  ZeroMem (&Command, sizeof (FDD_COMMAND_PACKET1));
 
900
  if (Read == READ) {
 
901
    Command.CommandCode = READ_DATA_CMD | CMD_MT | CMD_MFM | CMD_SK;
 
902
  } else {
 
903
    Command.CommandCode = WRITE_DATA_CMD | CMD_MT | CMD_MFM;
 
904
  }
 
905
 
 
906
  FillPara (FdcDev, Lba, &Command);
 
907
 
 
908
  //
 
909
  // Write command bytes to FDC
 
910
  //
 
911
  CommandPointer = (UINT8 *) (&Command);
 
912
  for (Index = 0; Index < sizeof (FDD_COMMAND_PACKET1); Index++) {
 
913
    if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) {
 
914
      return EFI_DEVICE_ERROR;
 
915
    }
 
916
  }
 
917
  //
 
918
  // wait for some time
 
919
  //
 
920
  Times = (STALL_1_SECOND / 50) + 1;
 
921
  do {
 
922
    if ((FdcReadPort (FdcDev, FDC_REGISTER_MSR) & 0xc0) == 0xc0) {
 
923
      break;
 
924
    }
 
925
 
 
926
    MicroSecondDelay (50);
 
927
    Times = Times - 1;
 
928
  } while (Times > 0);
 
929
 
 
930
  if (Times == 0) {
 
931
    return EFI_TIMEOUT;
 
932
  }
 
933
  //
 
934
  // Read result bytes from FDC
 
935
  //
 
936
  CommandPointer = (UINT8 *) (&Result);
 
937
  for (Index = 0; Index < sizeof (FDD_RESULT_PACKET); Index++) {
 
938
    if (EFI_ERROR (DataInByte (FdcDev, CommandPointer++))) {
 
939
      return EFI_DEVICE_ERROR;
 
940
    }
 
941
  }
 
942
  //
 
943
  // Flush before Unmap
 
944
  //
 
945
  if (Read == READ) {
 
946
    Status1 = IsaIo->Flush (IsaIo);
 
947
    if (EFI_ERROR (Status1)) {
 
948
      return Status1;
 
949
    }
 
950
  }
 
951
  //
 
952
  // Unmap Dma
 
953
  //
 
954
  Status1 = IsaIo->Unmap (IsaIo, Mapping);
 
955
  if (EFI_ERROR (Status1)) {
 
956
    return Status1;
 
957
  }
 
958
 
 
959
  return CheckResult (&Result, FdcDev);
 
960
}
 
961
 
 
962
/**
 
963
  Fill in FDD command's parameter.
 
964
  
 
965
  @param FdcDev   Pointer to instance of FDC_BLK_IO_DEV
 
966
  @param Lba      The starting logic block address to read from on the device
 
967
  @param Command  FDD command
 
968
 
 
969
**/
 
970
VOID
 
971
FillPara (
 
972
  IN  FDC_BLK_IO_DEV       *FdcDev,
 
973
  IN  EFI_LBA              Lba,
 
974
  IN  FDD_COMMAND_PACKET1  *Command
 
975
  )
 
976
{
 
977
  UINT8 EndOfTrack;
 
978
 
 
979
  //
 
980
  // Get EndOfTrack from the Para table
 
981
  //
 
982
  EndOfTrack = DISK_1440K_EOT;
 
983
 
 
984
  //
 
985
  // Fill the command parameter
 
986
  //
 
987
  if (FdcDev->Disk == FdcDisk0) {
 
988
    Command->DiskHeadSel = 0;
 
989
  } else {
 
990
    Command->DiskHeadSel = 1;
 
991
  }
 
992
 
 
993
  Command->Cylinder = (UINT8) ((UINTN) Lba / EndOfTrack / 2);
 
994
  Command->Head     = (UINT8) ((UINTN) Lba / EndOfTrack % 2);
 
995
  Command->Sector   = (UINT8) ((UINT8) ((UINTN) Lba % EndOfTrack) + 1);
 
996
  Command->DiskHeadSel = (UINT8) (Command->DiskHeadSel | (Command->Head << 2));
 
997
  Command->Number     = DISK_1440K_NUMBER;
 
998
  Command->EndOfTrack = DISK_1440K_EOT;
 
999
  Command->GapLength  = DISK_1440K_GPL;
 
1000
  Command->DataLength = DISK_1440K_DTL;
 
1001
}
 
1002
 
 
1003
/**
 
1004
  Read result byte from Data Register of FDC.
 
1005
  
 
1006
  @param FdcDev   Pointer to instance of FDC_BLK_IO_DEV
 
1007
  @param Pointer  Buffer to store the byte read from FDC
 
1008
  
 
1009
  @retval EFI_SUCCESS       Read result byte from FDC successfully
 
1010
  @retval EFI_DEVICE_ERROR  The FDC is not ready to be read
 
1011
 
 
1012
**/
 
1013
EFI_STATUS
 
1014
DataInByte (
 
1015
  IN  FDC_BLK_IO_DEV  *FdcDev,
 
1016
  OUT UINT8           *Pointer
 
1017
  )
 
1018
{
 
1019
  UINT8 Data;
 
1020
 
 
1021
  //
 
1022
  // wait for 1ms and detect the FDC is ready to be read
 
1023
  //
 
1024
  if (EFI_ERROR (FddDRQReady (FdcDev, DATA_IN, 1))) {
 
1025
    return EFI_DEVICE_ERROR;
 
1026
    //
 
1027
    // is not ready
 
1028
    //
 
1029
  }
 
1030
 
 
1031
  Data = FdcReadPort (FdcDev, FDC_REGISTER_DTR);
 
1032
 
 
1033
  //
 
1034
  // Io delay
 
1035
  //
 
1036
  MicroSecondDelay (50);
 
1037
 
 
1038
  *Pointer = Data;
 
1039
  return EFI_SUCCESS;
 
1040
}
 
1041
 
 
1042
/**
 
1043
  Write command byte to Data Register of FDC.
 
1044
  
 
1045
  @param FdcDev  Pointer to instance of FDC_BLK_IO_DEV
 
1046
  @param Pointer Be used to save command byte written to FDC
 
1047
  
 
1048
  @retval  EFI_SUCCESS:    Write command byte to FDC successfully
 
1049
  @retval  EFI_DEVICE_ERROR: The FDC is not ready to be written
 
1050
 
 
1051
**/
 
1052
EFI_STATUS
 
1053
DataOutByte (
 
1054
  IN FDC_BLK_IO_DEV  *FdcDev,
 
1055
  IN UINT8           *Pointer
 
1056
  )
 
1057
{
 
1058
  UINT8 Data;
 
1059
 
 
1060
  //
 
1061
  // wait for 1ms and detect the FDC is ready to be written
 
1062
  //
 
1063
  if (EFI_ERROR (FddDRQReady (FdcDev, DATA_OUT, 1))) {
 
1064
    //
 
1065
    // Not ready
 
1066
    //
 
1067
    return EFI_DEVICE_ERROR;
 
1068
  }
 
1069
 
 
1070
  Data = *Pointer;
 
1071
 
 
1072
  FdcWritePort (FdcDev, FDC_REGISTER_DTR, Data);
 
1073
 
 
1074
  //
 
1075
  // Io delay
 
1076
  //
 
1077
  MicroSecondDelay (50);
 
1078
 
 
1079
  return EFI_SUCCESS;
 
1080
}
 
1081
 
 
1082
/**
 
1083
  Detect the specified floppy logic drive is busy or not within a period of time.
 
1084
  
 
1085
  @param FdcDev           Indicate it is drive A or drive B
 
1086
  @param TimeoutInSeconds the time period for waiting
 
1087
  
 
1088
  @retval EFI_SUCCESS:  The drive and command are not busy
 
1089
  @retval EFI_TIMEOUT:  The drive or command is still busy after a period time that
 
1090
                        set by TimeoutInSeconds
 
1091
 
 
1092
**/
 
1093
EFI_STATUS
 
1094
FddWaitForBSYClear (
 
1095
  IN FDC_BLK_IO_DEV  *FdcDev,
 
1096
  IN UINTN           TimeoutInSeconds
 
1097
  )
 
1098
{
 
1099
  UINTN Delay;
 
1100
  UINT8 StatusRegister;
 
1101
  UINT8 Mask;
 
1102
 
 
1103
  //
 
1104
  // How to determine drive and command are busy or not: by the bits of
 
1105
  // Main Status Register
 
1106
  // bit0: Drive 0 busy (drive A)
 
1107
  // bit1: Drive 1 busy (drive B)
 
1108
  // bit4: Command busy
 
1109
  //
 
1110
  //
 
1111
  // set mask: for drive A set bit0 & bit4; for drive B set bit1 & bit4
 
1112
  //
 
1113
  Mask  = (UINT8) ((FdcDev->Disk == FdcDisk0 ? MSR_DAB : MSR_DBB) | MSR_CB);
 
1114
 
 
1115
  Delay = ((TimeoutInSeconds * STALL_1_MSECOND) / 50) + 1;
 
1116
  do {
 
1117
    StatusRegister = FdcReadPort (FdcDev, FDC_REGISTER_MSR);
 
1118
    if ((StatusRegister & Mask) == 0x00) {
 
1119
      break;
 
1120
      //
 
1121
      // not busy
 
1122
      //
 
1123
    }
 
1124
 
 
1125
    MicroSecondDelay (50);
 
1126
    Delay = Delay - 1;
 
1127
  } while (Delay > 0);
 
1128
 
 
1129
  if (Delay == 0) {
 
1130
    return EFI_TIMEOUT;
 
1131
  }
 
1132
 
 
1133
  return EFI_SUCCESS;
 
1134
}
 
1135
 
 
1136
/**
 
1137
 
 
1138
  Routine Description:  Determine whether FDC is ready to write or read.
 
1139
  
 
1140
  @param  FdcDev Pointer to instance of FDC_BLK_IO_DEV
 
1141
  @param  Dio BOOLEAN:      Indicate the FDC is waiting to write or read
 
1142
  @param  TimeoutInSeconds UINTN: The time period for waiting
 
1143
  
 
1144
  @retval EFI_SUCCESS:  FDC is ready to write or read
 
1145
  @retval EFI_NOT_READY:  FDC is not ready within the specified time period
 
1146
 
 
1147
**/
 
1148
EFI_STATUS
 
1149
FddDRQReady (
 
1150
  IN FDC_BLK_IO_DEV  *FdcDev,
 
1151
  IN BOOLEAN         Dio,
 
1152
  IN  UINTN          TimeoutInSeconds
 
1153
  )
 
1154
{
 
1155
  UINTN Delay;
 
1156
  UINT8 StatusRegister;
 
1157
  UINT8 DataInOut;
 
1158
 
 
1159
  //
 
1160
  // Before writing to FDC or reading from FDC, the Host must examine
 
1161
  // the bit7(RQM) and bit6(DIO) of the Main Status Register.
 
1162
  // That is to say:
 
1163
  //  command bytes can not be written to Data Register
 
1164
  //  unless RQM is 1 and DIO is 0
 
1165
  //  result bytes can not be read from Data Register
 
1166
  //  unless RQM is 1 and DIO is 1
 
1167
  //
 
1168
  DataInOut = (UINT8) (Dio << 6);
 
1169
  //
 
1170
  // in order to compare bit6
 
1171
  //
 
1172
  Delay = ((TimeoutInSeconds * STALL_1_MSECOND) / 50) + 1;
 
1173
  do {
 
1174
    StatusRegister = FdcReadPort (FdcDev, FDC_REGISTER_MSR);
 
1175
    if ((StatusRegister & MSR_RQM) == MSR_RQM && (StatusRegister & MSR_DIO) == DataInOut) {
 
1176
      break;
 
1177
      //
 
1178
      // FDC is ready
 
1179
      //
 
1180
    }
 
1181
 
 
1182
    MicroSecondDelay (50);
 
1183
    //
 
1184
    // Stall for 50 us
 
1185
    //
 
1186
    Delay = Delay - 1;
 
1187
  } while (Delay > 0);
 
1188
 
 
1189
  if (Delay == 0) {
 
1190
    return EFI_NOT_READY;
 
1191
    //
 
1192
    // FDC is not ready within the specified time period
 
1193
    //
 
1194
  }
 
1195
 
 
1196
  return EFI_SUCCESS;
 
1197
}
 
1198
 
 
1199
/**
 
1200
  Set FDC control structure's attribute according to result. 
 
1201
 
 
1202
  @param Result  Point to result structure
 
1203
  @param FdcDev  FDC control structure
 
1204
 
 
1205
  @retval EFI_DEVICE_ERROR - GC_TODO: Add description for return value
 
1206
  @retval EFI_DEVICE_ERROR - GC_TODO: Add description for return value
 
1207
  @retval EFI_DEVICE_ERROR - GC_TODO: Add description for return value
 
1208
  @retval EFI_SUCCESS - GC_TODO: Add description for return value
 
1209
 
 
1210
**/
 
1211
EFI_STATUS
 
1212
CheckResult (
 
1213
  IN     FDD_RESULT_PACKET  *Result,
 
1214
  IN OUT FDC_BLK_IO_DEV     *FdcDev
 
1215
  )
 
1216
{
 
1217
  //
 
1218
  // Check Status Register0
 
1219
  //
 
1220
  if ((Result->Status0 & STS0_IC) != IC_NT) {
 
1221
    if ((Result->Status0 & STS0_SE) == 0x20) {
 
1222
      //
 
1223
      // seek error
 
1224
      //
 
1225
      FdcDev->ControllerState->NeedRecalibrate = TRUE;
 
1226
    }
 
1227
 
 
1228
    FdcDev->ControllerState->NeedRecalibrate = TRUE;
 
1229
    return EFI_DEVICE_ERROR;
 
1230
  }
 
1231
  //
 
1232
  // Check Status Register1
 
1233
  //
 
1234
  if ((Result->Status1 & (STS1_EN | STS1_DE | STS1_OR | STS1_ND | STS1_NW | STS1_MA)) != 0) {
 
1235
    FdcDev->ControllerState->NeedRecalibrate = TRUE;
 
1236
    return EFI_DEVICE_ERROR;
 
1237
  }
 
1238
  //
 
1239
  // Check Status Register2
 
1240
  //
 
1241
  if ((Result->Status2 & (STS2_CM | STS2_DD | STS2_WC | STS2_BC | STS2_MD)) != 0) {
 
1242
    FdcDev->ControllerState->NeedRecalibrate = TRUE;
 
1243
    return EFI_DEVICE_ERROR;
 
1244
  }
 
1245
 
 
1246
  return EFI_SUCCESS;
 
1247
}
 
1248
 
 
1249
/**
 
1250
  Check the drive status information.
 
1251
  
 
1252
  @param StatusRegister3  the value of Status Register 3
 
1253
  
 
1254
  @retval EFI_SUCCESS           The disk is not write protected
 
1255
  @retval EFI_WRITE_PROTECTED:  The disk is write protected
 
1256
 
 
1257
**/
 
1258
EFI_STATUS
 
1259
CheckStatus3 (
 
1260
  IN UINT8 StatusRegister3
 
1261
  )
 
1262
{
 
1263
  if ((StatusRegister3 & STS3_WP) != 0) {
 
1264
    return EFI_WRITE_PROTECTED;
 
1265
  }
 
1266
 
 
1267
  return EFI_SUCCESS;
 
1268
}
 
1269
 
 
1270
/**
 
1271
  Calculate the number of block in the same cylinder according to LBA.
 
1272
  
 
1273
  @param FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV
 
1274
  @param LBA EFI_LBA:      The starting logic block address
 
1275
  @param NumberOfBlocks UINTN: The number of blocks
 
1276
  
 
1277
  @return The number of blocks in the same cylinder which the starting
 
1278
        logic block address is LBA
 
1279
 
 
1280
**/
 
1281
UINTN
 
1282
GetTransferBlockCount (
 
1283
  IN  FDC_BLK_IO_DEV  *FdcDev,
 
1284
  IN  EFI_LBA         LBA,
 
1285
  IN  UINTN           NumberOfBlocks
 
1286
  )
 
1287
{
 
1288
  UINT8 EndOfTrack;
 
1289
  UINT8 Head;
 
1290
  UINT8 SectorsInTrack;
 
1291
 
 
1292
  //
 
1293
  // Calculate the number of block in the same cylinder
 
1294
  //
 
1295
  EndOfTrack      = DISK_1440K_EOT;
 
1296
  Head            = (UINT8) ((UINTN) LBA / EndOfTrack % 2);
 
1297
 
 
1298
  SectorsInTrack  = (UINT8) (EndOfTrack * (2 - Head) - (UINT8) ((UINTN) LBA % EndOfTrack));
 
1299
  if (SectorsInTrack < NumberOfBlocks) {
 
1300
    return SectorsInTrack;
 
1301
  } else {
 
1302
    return NumberOfBlocks;
 
1303
  }
 
1304
}
 
1305
 
 
1306
/**
 
1307
  When the Timer(2s) off, turn the drive's motor off.
 
1308
  
 
1309
  @param Event EFI_EVENT: Event(the timer) whose notification function is being
 
1310
                     invoked
 
1311
  @param Context VOID *:  Pointer to the notification function's context
 
1312
 
 
1313
**/
 
1314
VOID
 
1315
EFIAPI
 
1316
FddTimerProc (
 
1317
  IN EFI_EVENT  Event,
 
1318
  IN VOID       *Context
 
1319
  )
 
1320
{
 
1321
  FDC_BLK_IO_DEV  *FdcDev;
 
1322
  UINT8           Data;
 
1323
 
 
1324
  FdcDev = (FDC_BLK_IO_DEV *) Context;
 
1325
 
 
1326
  //
 
1327
  // Get the motor status
 
1328
  //
 
1329
  Data = FdcReadPort (FdcDev, FDC_REGISTER_DOR);
 
1330
 
 
1331
  if (((FdcDev->Disk == FdcDisk0) && ((Data & 0x10) != 0x10)) ||
 
1332
      ((FdcDev->Disk == FdcDisk1) && ((Data & 0x21) != 0x21))
 
1333
      ) {
 
1334
    return ;
 
1335
  }
 
1336
  //
 
1337
  // the motor is on, so need motor off
 
1338
  //
 
1339
  Data = 0x0C;
 
1340
  Data = (UINT8) (Data | (SELECT_DRV & FdcDev->Disk));
 
1341
  FdcWritePort (FdcDev, FDC_REGISTER_DOR, Data);
 
1342
  MicroSecondDelay (500);
 
1343
}
 
1344
 
 
1345
/**
 
1346
  Read an I/O port of FDC.
 
1347
 
 
1348
  @param[in] FdcDev  A pointer to FDC_BLK_IO_DEV.
 
1349
  @param[in] Offset  The address offset of the I/O port.
 
1350
 
 
1351
  @retval  8-bit data read from the I/O port.
 
1352
**/
 
1353
UINT8
 
1354
FdcReadPort (
 
1355
  IN FDC_BLK_IO_DEV  *FdcDev,
 
1356
  IN UINT32          Offset
 
1357
  )
 
1358
{
 
1359
  EFI_STATUS  Status;
 
1360
  UINT8       Data;
 
1361
 
 
1362
  Status = FdcDev->IsaIo->Io.Read (
 
1363
                            FdcDev->IsaIo,
 
1364
                            EfiIsaIoWidthUint8,
 
1365
                            FdcDev->BaseAddress + Offset,
 
1366
                            1,
 
1367
                            &Data
 
1368
                            );
 
1369
  ASSERT_EFI_ERROR (Status);
 
1370
 
 
1371
  return Data;
 
1372
}
 
1373
 
 
1374
/**
 
1375
  Write an I/O port of FDC.
 
1376
 
 
1377
  @param[in] FdcDev  A pointer to FDC_BLK_IO_DEV
 
1378
  @param[in] Offset  The address offset of the I/O port
 
1379
  @param[in] Data    8-bit Value written to the I/O port
 
1380
**/
 
1381
VOID
 
1382
FdcWritePort (
 
1383
  IN FDC_BLK_IO_DEV  *FdcDev,
 
1384
  IN UINT32          Offset,
 
1385
  IN UINT8           Data
 
1386
  )
 
1387
{
 
1388
  EFI_STATUS  Status;
 
1389
 
 
1390
  Status = FdcDev->IsaIo->Io.Write (
 
1391
                            FdcDev->IsaIo,
 
1392
                            EfiIsaIoWidthUint8,
 
1393
                            FdcDev->BaseAddress + Offset,
 
1394
                            1,
 
1395
                            &Data
 
1396
                            );
 
1397
  ASSERT_EFI_ERROR (Status);
 
1398
}
 
1399