保护模式下操作软盘驱动器

修改自某CSDN网友的博客,但是他也是转载,所以无法确定原作者

软盘控制器
通过以下几个控制寄存器操作FDC
I/O address    Read or Write    Register
0x3f2          Write            DOR: Digital Output Register
0x3f4          Read             FDC Status: Floppy Disk Status Register
0x3f5          Read/Write       FDC Data: Floppy Disk Data Register
0x3f7          Read             DIR: Digital Input Register
               Write            DCR: Disk Control Register

DOR:DOR是一个8位寄存器,它控制软盘驱动器马达的开启、驱动器选择、启动/复位FDC以及允许/禁止DMA请求

位    Name    Description
7    MOT_EN3    Driver D motor:1-start;0-stop
6    MOT_EN2    Driver C motor:1-start;0-stop
5    MOT_EN1    Driver B motor:1-start;0-stop
4    MOT_EN0    Driver A motor:1-start;0-stop
3    DMA_INT    DMA interrupt; 1 enable; 0-disable
2    RESET    FDC Reset
1    DRV_SEL1  Select driver 1/0
0    DRV_SEL0

FDC status:FDC状态寄存器

FDC status用于反映软盘驱动器FDC的基本状态。通常,在CPU想FDC发送命令或从FDC获取结果前,都要读取FDC的状态为,以判断当前的FDC data寄存器是否就需,以及确定数据传输方向。

位    Name    Description
7    RQM    Data ready: FDD ready
6    DIO    Direction: 1 - FDD to CPU; 0 – CPU to FDD
5    NDM    DMA set: 1-not DMA; 0-DMA
4    CB    Controller busy
3    DDB    Driver D busy
2    DCB    Driver C busy
1    DBB    Driver B busy
0    DAB    Driver A busy

FDC Data:FDC数据寄存器

FDC Data寄存器用于向FDC发送控制命令或从FDC读取状态,实现数据读写等。FDC的使用比较复杂,可支持多种命令。每个命令都通过一个命令序列实现:命令阶段、执行阶段和结果阶段。

1)  重新校正命令(FD_RECALIBRATE)
软盘启动时调用
阶段    序    D7  D6  D5  D4  D3  D2  D1  D0  说明  
cmd      0    0   0   0   0   0   1   1   1   0x07
         1    0   0   0   0   0   0   US1 US2 Drive no.
执行                                        磁头移动到track0
结果    无                                    无

2)  磁头寻道命令(FD_SEEK)
把磁头定位到制定位置,在读写前执行
阶段    序  D7  D6  D5  D4  D3  D2  D1  D0  说明
cmd      0   0   0   0   0   0   1   1   1   0x0F
         1   0   0   0   0   0   HD  US1 US2 磁头号、驱动器号
         2   C                               磁道号
执行                                        磁头移动到制定磁道
结果    无                                  无

3)  读扇区数据命令(FD_READ)
阶段    序  D7  D6  D5  D4  D3  D2  D1  D0  说明
cmd     0   MT  MF  SK  0   0   1   1   0   0xE6(MT=MF=SK=1)
        1   0   0   0   0   0   0   US1 US2 驱动器号
        2   C                               磁道号track
        3   H                               磁头号head
        4   R                               起始扇区号start sector
        5   N                               扇区字节数
        6   EOT                             磁道最大扇区号
        7   GPL                             扇区建间隔长度(3)
        8   DTL                             N=0时,制定扇区字节书
执行                                        从软盘读取扇区
结果    1    ST0    状态字节0
        2    ST1    状态字节1
        3    ST2    状态字节2
        4    C    磁道号track
        5    H    磁头号head
        6    R    起始扇区号
        7    N    扇区字节数
注:
MT:多磁道操作。MT=1表示允许多磁道操作
MF:记录方式。MF=1表示选用MFM记录方式,否则是FM记录方式d
SK:是否跳过有删除标志的扇区。SK=1表示跳过。

返回的返回的状态ST0、ST1和ST2的含义如下:
ST0:
位    名称        说明
7-6    ST0_INTR    中断原因。00-正常结束;01-异常结束;10-命令无效;11-软盘驱动器状态改变
5    ST0_SE        寻道操作或重新校正操作结束(seek end)
4    ST0_ECE       设备检查错误(0磁道校正错误)(Equip. Check Error)
3    ST0_NR        软盘未就绪(Not Ready)
2    ST0_HA        磁头地址。中断时磁头地址(Head Address)
     1-0  ST0_DS   驱动器号(Driver Select)

ST1:
位    名称    说明
7    ST1_EOC    范文超过磁道最大扇区号(End of Cylinder)
6    Reserve
5    ST1_CRC    CRC校验出错
4    ST1_OR    数据传输超时(Over Run)
3    Reserve
2    ST1_ND    未找到制定扇区(No Data)
1    ST1_WP    写保护(Write Protect)
0    ST1_MAM    未找到扇区地址标志ID(Miss Address Mask)

ST2:
位    名称    说明
7    Reserve    
6    ST2_CM    SK=0时,读数据遇到删除标志(Control Mark)
5    ST2_CRC    CRC校验出错
4    ST2_WC    扇区ID信息的磁道号C不不符(Wrong Cylinder)
3    ST2_SEH    检索条件满足(Scan Equal Hit)
2    ST2_SNS    检索条件不满足(Scan Not Satisfied)
1    ST2_BC    磁道坏(Bad Cylinder)
0    ST2_MAM    未找到扇区地址标志ID(Miss Address Mask)

4)  写扇区数据命令(FD_WRITE)
阶段  序  D7  D6  D5  D4  D3  D2  D1  D0  说明
cmd   0   MT  MF  0   0   0   1   0   1   0xC5(MT=MF=1)
      1   0   0   0   0   0   0   US1 US2 磁头号、驱动器号
      2   C                               磁道号track
      3   H                               磁头号head
      4   R                               起始扇区号start sector
      5   N                               扇区字节数
      6   EOT                             磁道最大扇区号
      7   GPL                             扇区建间隔长度(3)
      8   DTL                             N=0时,制定扇区字节书
执行                                      向软盘写入扇区
结果  1  ST0   状态字节0
      2  ST1   状态字节1
      3  ST2   状态字节2

5)  检测中断状态命令(FD_SENSEI)
阶段  序  D7  D6  D5  D4  D3  D2  D1  D0  说明
cmd   0   0   0   0   0   0   1   1   1   0x08
执行
结果  1    ST0  状态字节0
      2 磁头所在磁道号

6)  设定驱动器参数命令(FD_SPECIFY)
阶段  序  D7  D6  D5  D4  D3  D2  D1  D0  说明
cmd   0   0   0   0   0   0   1   1   1   0x03
      1   4-7:SRT单位2ms,0-3:HUT单位32ms  马达速度、磁头卸载时间
      2   1-7:HLT单位4ms,0:ND             磁头加载时间,非DMA模式
执行                                      设置控制器
结果      无                              无
 
DIR:数字输入寄存器
DIR寄存器只有D7位有效,用于表示软盘更换状态,其余用于硬盘控制器。

DCR:磁盘控制寄存器
DCR仅是用户D0与D1位,用于表示数据传输率。
00-500kpbs, 01-300kpbs, 10-250kpbs。

1)复位-Reset

  1. outb(FLOPPY_REG_DOR, 0x08);// 重启

  2. for (i=0; i<100 ; i++)

  3. __asm__("nop");// 延时,保证重启完成

  4. outb(FLOPPY_REG_DOR, 0xc);// 选择DMA模式,选择软驱A

1)  设置磁盘数据传输速度

outb(FD_DCR, 0); // 500kpbs

2)  Output_byte函数用于FDC命令的输出,FDC的每条命令需要确保上条命令已经完成

  1. static void output_byte(char byte)

  2. {

  3.      int counter;

  4.      unsigned char status;



  5.      for(counter= 0 ; counter< 10000 ; counter++){

  6.             status = inb(FD_STATUS)& (STATUS_READY| STATUS_DIR);

  7.             if (status == STATUS_READY){

  8.                    outb(FD_DATA, byte);

  9.                    return;

  10.             }

  11.      }

  12.      printf("Unable to send byte to FDC\r");

  13. }

3)  设置驱动器参数

  1. output_byte(FD_SPECIFY);

  2. output_byte(0xCF);/* 马达步进速度、磁头卸载时间=32ms*/

  3. output_byte(6);/* Head loadtime =6ms, DMA*/

 

读扇区
  1. typedef struct {

  2.        unsigned int size, sect, head, track, stretch;

  3.        unsigned char gap,rate,spec1;

  4. }floppy_struct;
  5. static floppy_struct floppy_type =
  6.     {2880,18,2,80,0,0x1B,0x00,0xCF}; /* 1.44MB diskette*/
  7. static u32 current_dev = 0;
  8. /* (2 * 18 * 80* 512) */
  9. void FloppyReadSector(u32 sectNo, u8*buf)
  10. {    u32 head, track, block, sector, seek_track;
  11.     if (NULL== buf)
  12.     {        printf("FloppyReadSector para error.\r");
  13.         return;
  14.     }
  15.     if (sectNo>= (floppy_type.head * floppy_type.track * floppy_type.sect))
  16.     {
  17.         printf("FloppyReadSector sectNo error: %x.\r", sectNo);
  18.         return;
  19.     }
  20.     /* 计算参数*/
  21.     sector = sectNo % floppy_type.sect + 1;
  22.     block = sectNo / floppy_type.sect;
  23.     track = block / floppy_type.head;
  24.     head = block % floppy_type.head;
  25.     seek_track = track << floppy_type.stretch; 

  26.     /* 软盘重新校正*/
  27.     output_byte(FD_RECALIBRATE);
  28.     output_byte(current_dev);  

  29.     /* 寻找磁道*/
  30.     output_byte(FD_SEEK);
  31.     output_byte(current_dev);
  32.     output_byte(seek_track); 

  33.     /* 设置DMA,准备传送数据*/
  34.     SetDMA(buf, FD_READ);
  35.     /* 发送读扇区命令*/
  36.     output_byte(FD_READ);/* command */
  37.     output_byte(current_dev);/* driver no.*/
  38.     output_byte(track);/* track no.*/
  39.     output_byte(head);/* head */
  40.     output_byte(sector);/* start sector*/
  41.     output_byte(2);/* sector size= 512 */
  42.     output_byte(floppy_type.sect);/* Max sector*/
  43.     output_byte(floppy_type.gap);/* sector gap*/
  44.     output_byte(0xFF);/* sector size(0xff when n!=0 ?)*/
  45. }

 程序很清楚,不再多说,写命令于此类似。

唯一不清楚的是SetDMA函数。

我们在设置DOR时设置的DMA工作方式为enable,也就是说数据会通过DMA方式传送,因此必须设置DMA控制器。

 1.1.2.3          DMA传输

  1. /* DMA commands*/

  2. #define DMA_READ 0x46

  3. #define DMA_WRITE 0x4A
  4. #define immoutb_p(val,port)\
  5. __asm__("outb %0,%1\n\tjmp 1f\n1:\tjmp 1f\n1:"::"a"((char)(val)),"i"(port))
  6. void SetDMA(u8 *buf, u8 cmd)
  7. {
  8.     long addr = (long)buf;
  9.     Cli();
  10.     /* mask DMA 2*/
  11.     immoutb_p(4|2,10);
  12.     /* output command byte. I don't know why, but everyone(minix, */
  13.     /* sanches& canton) output this twice, firstto 12 then to 11 */

  14.     __asm__("outb %%al,$12\n\tjmp 1f\n1:\tjmp 1f\n1:\t"
  15.     "outb %%al,$11\n\tjmp 1f\n1:\tjmp 1f\n1:"::
  16.     "a" ((char)((cmd == FD_READ)?DMA_READ:DMA_WRITE)));

  17.     /* 8 low bits of addr*/
  18.     immoutb_p(addr,4);
  19.     addr >>= 8;
  20.     /* bits 8-15 of addr*/
  21.     immoutb_p(addr,4);
  22.     addr >>= 8;
  23.     /* bits 16-19 of addr*/
  24.     immoutb_p(addr,0x81);
  25.     /* low 8 bits of count-1(1024-1=0x3ff)*/
  26.     immoutb_p(0xff,5);
  27.     /* high 8 bits of count-1*/
  28.     immoutb_p(3,5);
  29.     /* activate DMA 2*/
  30.     immoutb_p(0|2,10);
  31.     Sti();
  32. }

该函数由linux0.11移植而来,可参照DMA控制器手册进行设置。不看也可以,注释写得很清楚,拿过来用就是了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值