����9-5 linux/kernel/blk_drv/floppy.c
1 /*
2 * linux/kernel/floppy.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7 /*
8 * 02.12.91 - Changed to static variables to indicate need for reset
9 * and recalibrate. This makes some things easier (output_byte reset
10 * checking etc), and means less interrupt jumping in case of errors,
11 * so the code is hopefully easier to understand.
12 */
/*
* 02.12.91 - �ijɾ�̬����������Ӧ��λ������У����������ʹ��ijЩ����
* ��������Ϊ���㣨output_byte ��λ���ȣ���������ζ���ڳ���ʱ�ж���ת
* Ҫ��һЩ������Ҳϣ�������ܸ����ױ����⡣
*/
13
14 /*
15 * This file is certainly a mess. I've tried my best to get it working,
16 * but I don't like programming floppies, and I have only one anyway.
17 * Urgel. I should check for more errors, and do more graceful error
18 * recovery. Seems there are problems with several drives. I've tried to
19 * correct them. No promises.
20 */
/*
* ����ļ���Ȼ�Ƚϻ��ҡ����Ѿ���������ʹ���ܹ����������Ҳ�ϲ��������̣�
* ������Ҳֻ��һ�����������⣬��Ӧ��������IJ���������Լ���������Ĵ���
* ����ijЩ�����������������������һЩ���⡣���Ѿ������Ž��о����ˣ�
* �����ܱ�֤��������ʧ��
*/
21
22 /*
23 * As with hd.c, all routines within this file can (and will) be called
24 * by interrupts, so extreme caution is needed. A hardware interrupt
25 * handler may not sleep, or a kernel panic will happen. Thus I cannot
26 * call "floppy-on" directly, but have to set a special timer interrupt
27 * etc.
28 *
29 * Also, I'm not certain this works on more than 1 floppy. Bugs may
30 * abund.
31 */
/*
* ��ͬhd.c�ļ�һ�������ļ��е������ӳ����ܹ����жϵ��ã�������Ҫ�ر�
* ��С�ġ�Ӳ���жϴ��������Dz���˯�ߵģ������ں˾ͻ�ɵ��(����)J����˲���
* ֱ�ӵ���"floppy-on"����ֻ������һ������Ķ�ʱ�жϵȡ�
*
* ���⣬�Ҳ��ܱ�֤�ó������ڶ���1��������ϵͳ�Ϲ������п��ܴ��ڴ���
*/
32
33 #include <linux/sched.h> // ���ȳ���ͷ�ļ�������������ṹtask_struct������0���ݵȡ�
34 #include <linux/fs.h> // �ļ�ϵͳͷ�ļ������ļ����ṹ��file��m_inode���ȡ�
35 #include <linux/kernel.h> // �ں�ͷ�ļ�������һЩ�ں˳��ú�����ԭ�ζ��塣
36 #include <linux/fdreg.h> // ����ͷ�ļ����������̿�����������һЩ���塣
37 #include <asm/system.h> // ϵͳͷ�ļ������������û���������/�ж��ŵȵ�Ƕ����ꡣ
38 #include <asm/io.h> // ioͷ�ļ�������Ӳ���˿�����/���������䡣
39 #include <asm/segment.h> // �β���ͷ�ļ����������йضμĴ���������Ƕ��ʽ��ຯ����
40
// �����������豸�ŷ��ų����������������У����豸�ű����ڰ���blk.h�ļ�֮ǰ�����塣
// ��Ϊblk.h�ļ���Ҫ�õ�������ų���ֵ��ȷ��һЩ��������ط��ų����ͺꡣ
41 #define MAJOR_NR 2 // ���������豸����2��
42 #include "blk.h" // ���豸ͷ�ļ�����������ṹ�����豸�ṹ�ͺ꺯������Ϣ��
43
44 static int recalibrate = 0; // ��־��1��ʾ��Ҫ����У����ͷλ�ã���ͷ���������
45 static int reset = 0; // ��־��1��ʾ��Ҫ���и�λ������
46 static int seek = 0; // ��־��1��ʾ��Ҫִ��Ѱ��������
47
// ��ǰ��������Ĵ���DOR��Digital Output Register����������kernel/sched.c��223�С�
// �ñ����������������е���Ҫ��־������ѡ�����������Ƶ��������������λ���̿�������
// ������/��ֹDMA���ж�������μ������б����DOR�Ĵ�����˵����
48 extern unsigned char current_DOR;
49
// �ֽ�ֱ���������Ƕ����꣩����ֵval�����port�˿ڡ�
50 #define immoutb_p(val,port) \
51 __asm__("outb %0,%1\n\tjmp 1f\n1:\tjmp 1f\n1:"::"a" ((char) (val)),"i" (port))
52
// �������궨�����ڼ����������豸�š�
// ����x�Ǵ��豸�š����豸�� = TYPE*4 + DRIVE�����㷽���μ��б���
53 #define TYPE(x) ((x)>>2) // �������ͣ�2--1.2Mb��7--1.44Mb����
54 #define DRIVE(x) ((x)&0x03) // ������ţ�0--3��ӦA--D����
55 /*
56 * Note that MAX_ERRORS=8 doesn't imply that we retry every bad read
57 * max 8 times - some types of errors increase the errorcount by 2,
58 * so we might actually retry only 5-6 times before giving up.
59 */
/*
* ע�⣬���涨��MAX_ERRORS=8������ʾ��ÿ�ζ����������8�� - ��Щ����
* �Ĵ����ѳ�������ֵ��2����������ʵ�����ڷ�������֮ǰֻ�賢��5-6�鼴�ɡ�
*/
60 #define MAX_ERRORS 8
61
62 /*
63 * globals used by 'result()'
64 */
/* �����Ǻ���'result()'ʹ�õ�ȫ�ֱ��� */
// ��Щ״̬�ֽ��и�����λ�ĺ�����μ�include/linux/fdreg.hͷ�ļ������μ��б���˵����
65 #define MAX_REPLIES 7 // FDC����7�ֽڵĽ����Ϣ��
66 static unsigned char reply_buffer[MAX_REPLIES]; // ���FDC���ص�Ӧ������Ϣ��
67 #define ST0 (reply_buffer[0]) // ���״̬�ֽ�0��
68 #define ST1 (reply_buffer[1]) // ���״̬�ֽ�1��
69 #define ST2 (reply_buffer[2]) // ���״̬�ֽ�2��
70 #define ST3 (reply_buffer[3]) // ���״̬�ֽ�3��
71
72 /*
73 * This struct defines the different floppy types. Unlike minix
74 * linux doesn't have a "search for right type"-type, as the code
75 * for that is convoluted and weird. I've got enough problems with
76 * this driver as it is.
77 *
78 * The 'stretch' tells if the tracks need to be boubled for some
79 * types (ie 360kB diskette in 1.2MB drive etc). Others should
80 * be self-explanatory.
81 */
/*
* ��������̽ṹ�����˲�ͬ���������͡���minix��ͬ���ǣ�Linuxû��
* "������ȷ������"-���ͣ���Ϊ���䴦���Ĵ������˷ѽ��ҹֵֹġ�������
* �Ѿ���������̫��������ˡ�
*
* ��ijЩ���͵����̣�������1.2MB�������е�360kB���̵ȣ���'stretch'
* ���ڼ��ŵ��Ƿ���Ҫ���������������Ӧ���������ġ�
*/
// �������̽ṹ�����̲����У�
// size ��С(������)��
// sect ÿ�ŵ���������
// head ��ͷ����
// track �ŵ�����
// stretch �Դŵ��Ƿ�Ҫ���������־����
// gap ������϶����(�ֽ���)��
// rate ���ݴ������ʣ�
// spec1 ��������4λ�������ʣ�����λ��ͷж��ʱ�䣩��
82 static struct floppy_struct {
83 unsigned int size, sect, head, track, stretch;
84 unsigned char gap,rate,spec1;
85 } floppy_type[] = {
86 { 0, 0,0, 0,0,0x00,0x00,0x00 }, /* no testing */
87 { 720, 9,2,40,0,0x2A,0x02,0xDF }, /* 360kB PC diskettes */
88 { 2400,15,2,80,0,0x1B,0x00,0xDF }, /* 1.2 MB AT-diskettes */
89 { 720, 9,2,40,1,0x2A,0x02,0xDF }, /* 360kB in 720kB drive */
90 { 1440, 9,2,80,0,0x2A,0x02,0xDF }, /* 3.5" 720kB diskette */
91 { 720, 9,2,40,1,0x23,0x01,0xDF }, /* 360kB in 1.2MB drive */
92 { 1440, 9,2,80,0,0x23,0x01,0xDF }, /* 720kB in 1.2MB drive */
93 { 2880,18,2,80,0,0x1B,0x00,0xCF }, /* 1.44MB diskette */
94 };
95
96 /*
97 * Rate is 0 for 500kb/s, 2 for 300kbps, 1 for 250kbps
98 * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
99 * H is head unload time (1=16ms, 2=32ms, etc)
100 *
101 * Spec2 is (HLD<<1 | ND), where HLD is head load time (1=2ms, 2=4 ms etc)
102 * and ND is set means no DMA. Hardcoded to 6 (HLD=6ms, use DMA).
103 */
/*
* ��������rate��0��ʾ500kbps��1��ʾ300kbps��2��ʾ250kbps��
* ����spec1��0xSH������S�Dz������ʣ�F-1ms��E-2ms��D=3ms�ȣ���
* H�Ǵ�ͷж��ʱ�䣨1=16ms��2=32ms�ȣ�
*
* spec2�ǣ�HLD<<1 | ND��������HLD�Ǵ�ͷ����ʱ�䣨1=2ms��2=4ms�ȣ�
* ND��λ��ʾ��ʹ��DMA��No DMA�����ڳ�����Ӳ�����6��HLD=6ms��ʹ��DMA����
*/
// ע�⣬������ͷ����ʱ�����дHLD���д�ɱ���HLT��Head Load Time����
104
// floppy_interrupt()��sys_call.s�����������жϴ������̱�š����ォ�����̳�ʼ��
// ����floppy_init()����469�У�ʹ������ʼ���ж���������������
105 extern void floppy_interrupt(void);
// ����boot/head.s��132�д��������ʱ���̻����������������Ļ����������ڴ�1MB
// ����ij���ط�������Ҫ��DMA������������ʱ����������Ϊ8237AоƬֻ����1MB��
// ַ��Χ��Ѱַ��
106 extern char tmp_floppy_area[1024];
107
108 /*
109 * These are global variables, as that's the easiest way to give
110 * information to interrupts. They are the data used for the current
111 * request.
112 */
/*
* ������һЩȫ�ֱ�������Ϊ���ǽ���Ϣ�����жϳ�����ķ�ʽ������
* ���ڵ�ǰ����������ݡ�
*/
// ��Щ��ν�ġ�ȫ�ֱ�������ָ�������жϴ��������е��õ�C����ʹ�õı�������Ȼ��Щ
// C�������ڱ������ڡ�
113 static int cur_spec1 = -1; // ��ǰ���̲���spec1��
114 static int cur_rate = -1; // ��ǰ����ת��rate��
115 static struct floppy_struct * floppy = floppy_type; // �������ͽṹ����ָ�롣
116 static unsigned char current_drive = 0; // ��ǰ�������š�
117 static unsigned char sector = 0; // ��ǰ�����š�
118 static unsigned char head = 0; // ��ǰ��ͷ�š�
119 static unsigned char track = 0; // ��ǰ�ŵ��š�
120 static unsigned char seek_track = 0; // Ѱ���ŵ��š�
121 static unsigned char current_track = 255; // ��ǰ��ͷ���ڴŵ��š�
122 static unsigned char command = 0; // ��/��
123 unsigned char selected = 0; // ������ѡ����־���ڴ���������֮ǰҪ����ѡ��������
124 struct task_struct * wait_on_floppy_select = NULL; // �ȴ�ѡ��������������С�
125
//// ȡ��ѡ��������
// �����������ָ��������nr��ǰ��û�б�ѡ��������ʾ������Ϣ��Ȼ��λ������ѡ����־
// selected�������ѵȴ�ѡ���������������������Ĵ���(DOR)�ĵ�2λ����ָ��ѡ�����
// ����0-3��ӦA-D����
126 void floppy_deselect(unsigned int nr)
127 {
128 if (nr != (current_DOR & 3))
129 printk("floppy_deselect: drive not selected\n\r");
130 selected = 0; // ��λ������ѡ����־��
131 wake_up(&wait_on_floppy_select); // ���ѵȴ�������
132 }
133
134 /*
135 * floppy-change is never called from an interrupt, so we can relax a bit
136 * here, sleep etc. Note that floppy-on tries to set current_DOR to point
137 * to the desired drive, but it will probably not survive the sleep if
138 * several floppies are used at the same time: thus the loop.
139 */
/*
* floppy-change()���Ǵ��жϳ����е��õģ������������ǿ�������һ�£�˯�ߵȡ�
* ע��floppy-on()�᳢������current_DORָ�������������������ͬʱʹ�ü���
* ����ʱ����˯�ߣ���˴�ʱֻ��ʹ��ѭ����ʽ��
*/
//// ���ָ�����������̸��������
// ����nr�������š�������̸�������1������0��
// �ú�������ѡ������ָ��������nr��Ȼ��������̿���������������Ĵ���DIR��ֵ������
// ���������е������Ƿ��������ú����ɳ���fs/buffer.c�е� check_disk_change()��
// �����ã���119�У���
140 int floppy_change(unsigned int nr)
141 {
// ����Ҫ��������������ת�������ﵽ��������ת�١�����Ҫ����һ��ʱ�䡣���õķ�������
// ��kernel/sched.c�����̶�ʱ����do_floppy_timer()����һ������ʱ������floppy_on()
// �����������ж���ʱ�Ƿ�mon_timer[nr]==0?������û�е����õ�ǰ���̼���˯�ߵȴ���
// ����ʱ����do_floppy_timer()�ỽ�ѵ�ǰ���̡�
142 repeat:
143 floppy_on(nr); // �������ȴ�ָ������nr��kernel/sched.c����251�У���
// ��������������ת��֮���������鿴һ�µ�ǰѡ��������Dz��Ǻ�������ָ��������nr��
// �����ǰѡ�����������ָ��������nr�������Ѿ�ѡ�����������������õ�ǰ��������
// �жϵȴ�״̬���Եȴ�����������ȡ��ѡ�����μ�����floppy_deselect()�� �����ǰû
// ��ѡ������������������������ȡ��ѡ����ʹ��ǰ������ʱ�� ��ǰ������Ȼ����ָ��
// ������nr������ת��������ʼ������ѭ���ȴ���
144 while ((current_DOR & 3) != nr && selected)
145 sleep_on(&wait_on_floppy_select);
146 if ((current_DOR & 3) != nr)
147 goto repeat;
// �������̿�������ѡ������ָ��������nr������ȡ��������Ĵ���DIR��ֵ����������
// λ��λ7����λ�����ʾ�����Ѹ�������ʱ���ɹر����ﲢ����1�˳��� ����ر����ﷵ
// ��0�˳�����ʾ����û�б�������
148 if (inb(FD_DIR) & 0x80) {
149 floppy_off(nr);
150 return 1;
151 }
152 floppy_off(nr);
153 return 0;
154 }
155
//// �����ڴ滺��飬��1024�ֽڡ�
// ���ڴ��ַfrom������1024�ֽ����ݵ���ַto����
156 #define copy_buffer(from,to) \
157 __asm__("cld ; rep ; movsl" \
158 ::"c" (BLOCK_SIZE/4),"S" ((long)(from)),"D" ((long)(to)) \
159 :"cx","di","si")
160
//// ���ã���ʼ��������DMAͨ����
// ���������ݶ�д������ʹ��DMA���еġ������ÿ�ν������ݴ���֮ǰ��Ҫ����DMAоƬ
// ��ר������������ͨ��2���й�DMA��̷�����μ������б������Ϣ��
161 static void setup_DMA(void)
162 {
163 long addr = (long) CURRENT->buffer; // ��ǰ��������������ڴ��ַ��
164
// ���ȼ��������Ļ���������λ�á���������������ڴ�1MB���ϵ�ij���ط�������Ҫ��
// DMA������������ʱ��������tmp_floppy_area��������Ϊ8237AоƬֻ����1MB��ַ��
// Χ��Ѱַ�������д���������Ҫ�����ݴ�������������Ƶ�����ʱ����
165 cli();
166 if (addr >= 0x100000) {
167 addr = (long) tmp_floppy_area;
168 if (command == FD_WRITE)
169 copy_buffer(CURRENT->buffer,tmp_floppy_area);
170 }
// ���������ǿ�ʼ����DMAͨ��2���ڿ�ʼ����֮ǰ��Ҫ�����θ�ͨ������ͨ�����μĴ���
// �˿�Ϊ0x0A��λ0-1ָ��DMAͨ��(0--3)��λ2��1��ʾ���Σ�0��ʾ�������� Ȼ����
// DMA�������˿�12��11д�뷽ʽ�֣�������0x46��д������0x4A���� ��д�봫��ʹ��
// ��������ַaddr����Ҫ������ֽ���0x3ff��0--1023�������λ��DMAͨ��2�����Σ�
// ����DMA2����DREQ�źš�
171 /* mask DMA 2 */ /* ����DMAͨ��2 */
172 immoutb_p(4|2,10);
173 /* output command byte. I don't know why, but everyone (minix, */
174 /* sanches & canton) output this twice, first to 12 then to 11 */
/* ��������ֽڡ����Dz�֪��Ϊʲô������ÿ���ˣ�minix��*/
/* sanches��canton����������Σ�������12�ڣ�Ȼ����11�� */
// ����Ƕ���������DMA�������ġ�����Ⱥ������˿�12�ͷ�ʽ�Ĵ����˿�11д��
// ��ʽ�֣�����ʱ��0x46��д����0x4A����
// ���ڸ�ͨ���ĵ�ַ�ͼ����Ĵ�������16λ�ģ��������������ʱ����Ҫ��2�ν��в�����
// һ�η��ʵ��ֽڣ���һ�η��ʸ��ֽڡ���ʵ����д�ĸ��ֽ������Ⱥ�����״̬������
// ��������Ϊ0ʱ������ʵ��ֽڣ����ֽڴ�����Ϊ1ʱ������ʸ��ֽڡ�ÿ����һ�Σ�
// �ô�������״̬�ͱ仯һ�Ρ���д�˿�12�Ϳ��Խ��������ó�0״̬���Ӷ���16λ�Ĵ�
// �������ôӵ��ֽڿ�ʼ��
175 __asm__("outb %%al,$12\n\tjmp 1f\n1:\tjmp 1f\n1:\t"
176 "outb %%al,$11\n\tjmp 1f\n1:\tjmp 1f\n1:"::
177 "a" ((char) ((command == FD_READ)?DMA_READ:DMA_WRITE)));
178 /* 8 low bits of addr */ /* ��ַ��0-7λ */
// ��DMAͨ��2д���/��ǰ��ַ�Ĵ������˿�4����
179 immoutb_p(addr,4);
180 addr >>= 8;
181 /* bits 8-15 of addr */ /* ��ַ��8-15λ */
182 immoutb_p(addr,4);
183 addr >>= 8;
184 /* bits 16-19 of addr */ /* ��ַ16-19λ */
// DMAֻ������1MB�ڴ�ռ���Ѱַ�����16-19λ��ַ�����ҳ��Ĵ���(�˿�0x81)��
185 immoutb_p(addr,0x81);
186 /* low 8 bits of count-1 (1024-1=0x3ff) */ /* ��������8λ(1024-1 = 0x3ff) */
// ��DMAͨ��2д���/��ǰ�ֽڼ�����ֵ���˿�5����
187 immoutb_p(0xff,5);
188 /* high 8 bits of count-1 */ /* ��������8λ */
// һ�ι�����1024�ֽڣ�������������
189 immoutb_p(3,5);
190 /* activate DMA 2 */ /* ����DMAͨ��2������ */
191 immoutb_p(0|2,10);
192 sti();
193 }
194
//// ���������������һ���ֽ�����������
// �������������һ���ֽ�֮ǰ����������Ҫ��������״̬���������ݴ��䷽���������
// �ɴ�CPU �� FDC����˺�����Ҫ���ȶ�ȡ������״̬��Ϣ������ʹ����ѭ����ѯ��ʽ����
// ���ʵ���ʱ����������������ø�λ��־reset��
195 static void output_byte(char byte)
196 {
197 int counter;
198 unsigned char status;
199
// ѭ����ȡ��״̬������FD_STATUS��0x3f4����״̬���������״̬�� STATUS_READY ����
// ����λSTATUS_DIR = 0��CPU��FDC�����������ݶ˿����ָ���ֽڡ�
200 if (reset)
201 return;
202 for(counter = 0 ; counter < 10000 ; counter++) {
203 status = inb_p(FD_STATUS) & (STATUS_READY | STATUS_DIR);
204 if (status == STATUS_READY) {
205 outb(byte,FD_DATA);
206 return;
207 }
208 }
// �����ѭ��1��ν��������ܷ��ͣ����ø�λ��־������ӡ������Ϣ��
209 reset = 1;
210 printk("Unable to send byte to FDC\n\r");
211 }
212
//// ��ȡFDCִ�еĽ����Ϣ��
// �����Ϣ���7���ֽڣ����������reply_buffer[]�С����ض���Ľ���ֽ�����������
// ֵ = -1�����ʾ��������������ʽ�����溯�����ơ�
213 static int result(void)
214 {
215 int i = 0, counter, status;
216
// ����λ��־����λ���������˳���ȥִ�к��������еĸ�λ����������ѭ����ȡ��״̬��
// ����FD_STATUS��0x3f4����״̬�������ȡ�Ŀ�����״̬��READY����ʾ�Ѿ�û�����ݿ�
// ȡ�����Ѷ�ȡ���ֽ���i�����������״̬�Ƿ����־��λ��CPUßFDC���������á�
// æ����ʾ�����ݿɶ�ȡ�� ���ǰѿ������еĽ�����ݶ��뵽Ӧ���������С� ����ȡ
// MAX_REPLIES��7�����ֽڡ�
217 if (reset)
218 return -1;
219 for (counter = 0 ; counter < 10000 ; counter++) {
220 status = inb_p(FD_STATUS)&(STATUS_DIR|STATUS_READY|STATUS_BUSY);
221 if (status == STATUS_READY)
222 return i;
223 if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) {
224 if (i >= MAX_REPLIES)
225 break;
226 reply_buffer[i++] = inb_p(FD_DATA);
227 }
228 }
// �����ѭ��1��ν��������ܷ��ͣ����ø�λ��־������ӡ������Ϣ��
229 reset = 1;
230 printk("Getstatus times out\n\r");
231 return -1;
232 }
233
//// ���̶�д��������������
// �ú����������̶�д����������ȷ����Ҫ��ȡ�Ľ�һ���ж��������ǰ���������������
// �������ڹ涨������������MAX_ERRORS��8�Σ������ٶԵ�ǰ����������һ���IJ���
// ���ԡ������/д���������Ѿ�����MAX_ERRORS/2������Ҫ����������λ��������������
// ��λ��־reset�������������������������ֵ��һ�룬��ֻ������У��һ�´�ͷλ�ã�
// ������������У����־recalibrate�������ĸ�λ������У���������ں����ij����н��С�
234 static void bad_flp_intr(void)
235 {
// ���Ȱѵ�ǰ���������������1�������ǰ������������������������������������ȡ
// ��ѡ����ǰ�����������������������������û�б����£���
236 CURRENT->errors++;
237 if (CURRENT->errors > MAX_ERRORS) {
238 floppy_deselect(current_drive);
239 end_request(0);
240 }
// �����ǰ����������������������������������һ�룬���ø�λ��־������������и�
// λ������Ȼ�����ԡ���������������У��һ�����ԡ�
241 if (CURRENT->errors > MAX_ERRORS/2)
242 reset = 1;
243 else
244 recalibrate = 1;
245 }
246
247 /*
248 * Ok, this interrupt is called after a DMA read/write has succeeded,
249 * so we check the results, and copy any buffers.
250 */
/*
* OK��������жϴ�����������DMA��/д�ɹ�����õģ��������ǾͿ��Լ��
* ִ�н���������ƻ������е����ݡ�
*/
//// ���̶�д�����жϵ��ú�����
// �ú��������������������������������жϴ��������б����á��������ȶ�ȡ�������״
// ̬��Ϣ���ݴ��жϲ����Ƿ�������Ⲣ����Ӧ������ �����/д�����ɹ�����ô��������
// �Ƕ����������仺�������ڴ�1MB����λ�ã�����Ҫ�����ݴ�������ʱ���������Ƶ�����
// ���������
251 static void rw_interrupt(void)
252 {
// ��ȡFDCִ�еĽ����Ϣ��������ؽ���ֽ���������7������״̬�ֽ�0��1��2�д���
// ������־����ô����д��������ʾ������Ϣ���ͷŵ�ǰ����������������ǰ���������
// ��ִ�г�������������Ȼ�����ִ���������������������״̬�ĺ���μ�fdreg.h�ļ���
// ( 0xf8 = ST0_INTR | ST0_SE | ST0_ECE | ST0_NR )
// ( 0xbf = ST1_EOC | ST1_CRC | ST1_OR | ST1_ND | ST1_WP | ST1_MAM��Ӧ����0xb7)
// ( 0x73 = ST2_CM | ST2_CRC | ST2_WC | ST2_BC | ST2_MAM )
253 if (result() != 7 || (ST0 & 0xf8) || (ST1 & 0xbf) || (ST2 & 0x73)) {
254 if (ST1 & 0x02) { // 0x02 = ST1_WP - Write Protected��
255 printk("Drive %d is write protected\n\r",current_drive);
256 floppy_deselect(current_drive);
257 end_request(0);
258 } else
259 bad_flp_intr();
260 do_fd_request();
261 return;
262 }
// �����ǰ������Ļ�����λ��1MB��ַ���ϣ���˵���˴����̶����������ݻ�������ʱ��
// �����ڣ���Ҫ���Ƶ���ǰ������Ļ������У���ΪDMAֻ����1MB��ַ��ΧѰַ�������
// �ͷŵ�ǰ������ȡ��ѡ������ִ�е�ǰ������������������ѵȴ���������Ľ��У�����
// �ȴ�����������Ľ��̣����еĻ������������豸������������ɾ����������ټ���ִ
// ���������������������
263 if (command == FD_READ && (unsigned long)(CURRENT->buffer) >= 0x100000)
264 copy_buffer(tmp_floppy_area,CURRENT->buffer);
265 floppy_deselect(current_drive);
266 end_request(1);
267 do_fd_request();
268 }
269
//// ����DMAͨ��2�������̿������������Ͳ��������1�ֽ����� + 0~7�ֽڲ�������
// ��reset��־û����λ����ô�ڸú����˳��������̿�����ִ������Ӧ��/д������ͻ�
// ����һ�������ж�������ʼִ�������жϴ�������
270 inline void setup_rw_floppy(void)
271 {
272 setup_DMA(); // ��ʼ������DMAͨ����
273 do_floppy = rw_interrupt; // �������жϵ��ú���ָ�롣
274 output_byte(command); // ���������ֽڡ�
275 output_byte(head<<2 | current_drive); // ��������ͷ��+�������š�
276 output_byte(track); // �������ŵ��š�
277 output_byte(head); // ��������ͷ�š�
278 output_byte(sector); // ��������ʼ�����š�
279 output_byte(2); /* sector size = 512 */ // ������(N=2)512�ֽڡ�
280 output_byte(floppy->sect); // ������ÿ�ŵ���������
281 output_byte(floppy->gap); // ����������������ȡ�
282 output_byte(0xFF); /* sector size (0xff when n!=0 ?) */
// ��������N=0ʱ������������ֽڳ��ȣ��������á�
// �������κ�һ��output_byte()����������������ø�λ��־reset����ʱ��������ȥִ��
// do_fd_request()�еĸ�λ�������롣
283 if (reset)
284 do_fd_request();
285 }
286
287 /*
288 * This is the routine called after every seek (or recalibrate) interrupt
289 * from the floppy controller. Note that the "unexpected interrupt" routine
290 * also does a recalibrate, but doesn't come here.
291 */
/*
* ���ӳ�������ÿ�����̿�����Ѱ����������У�����ж��б����õġ�ע��
* "unexpected interrupt"(�����ж�)�ӳ���Ҳ��ִ������У�������������ڴ˵ء�
*/
//// Ѱ�������������жϹ����е��õ�C������
// ���ȷ��ͼ���ж�״̬������״̬��ϢST0�ʹ�ͷ���ڴŵ���Ϣ����������ִ�д���
// ����������ȡ���������̲���������������״̬��Ϣ���õ�ǰ�ŵ�������Ȼ���
// �ú���setup_rw_floppy()����DMA��������̶�д����Ͳ�����
292 static void seek_interrupt(void)
293 {
// ���ȷ��ͼ���ж�״̬����Ի�ȡѰ������ִ�еĽ��������������������ؽ����
// Ϣ�������ֽڣ�ST0�ʹ�ͷ��ǰ�ŵ��š�Ȼ���ȡFDCִ�еĽ����Ϣ�� ������ؽ����
// ����������2������ST0��ΪѰ�����������ߴ�ͷ���ڴŵ���ST1���������趨�ŵ�����˵
// �������˴�������ִ�м��������������Ȼ�����ִ�������������ִ�и�λ������
294 /* sense drive status */ /* ���������״̬ */
295 output_byte(FD_SENSEI);
296 if (result() != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track) {
297 bad_flp_intr();
298 do_fd_request();
299 return;
300 }
// ��Ѱ�������ɹ��������ִ�е�ǰ����������̲������������̿�������������Ͳ�����
301 current_track = ST1; // ���õ�ǰ�ŵ���
302 setup_rw_floppy(); // ����DMA��������̲�������Ͳ�����
303 }
304
305 /*
306 * This routine is called when everything should be correctly set up
307 * for the transfer (ie floppy motor is on and the correct floppy is
308 * selected).
309 */
/*
* �ú������ڴ��������������Ϣ����ȷ���úú��õģ������������ѿ���
* ������ѡ������ȷ�����̣���������
*/
//// ��д���ݴ��亯����
310 static void transfer(void)
311 {
// ���ȼ�鵱ǰ�����������Ƿ����ָ���������IJ����������Ǿͷ���������������������
// ����Ӧ����������1����4λ�������ʣ�����λ��ͷж��ʱ�䣻����2����ͷ����ʱ�䣩��
// Ȼ���жϵ�ǰ���ݴ��������Ƿ���ָ����������һ�£������Ǿͷ���ָ������������ֵ��
// ���ݴ������ʿ��ƼĴ���(FD_DCR)��
312 if (cur_spec1 != floppy->spec1) { // ��ǰ������
313 cur_spec1 = floppy->spec1;
314 output_byte(FD_SPECIFY); // �������ô��̲������
315 output_byte(cur_spec1); /* hut etc */ // ���Ͳ�����
316 output_byte(6); /* Head load time =6ms, DMA */
317 }
318 if (cur_rate != floppy->rate) // ��ǰ���ʡ�
319 outb_p(cur_rate = floppy->rate,FD_DCR);
// �������κ�һ��output_byte()����ִ�г�������λ��־reset�ͻᱻ��λ���������
// ������Ҫ���һ��reset��־����reset��ı���λ�ˣ�������ȥִ��do_fd_request()
// �еĸ�λ�������롣
320 if (reset) {
321 do_fd_request();
322 return;
323 }
// �����ʱѰ����־Ϊ�㣨������ҪѰ������������DMA�������̿�����������Ӧ��������
// �Ͳ����ء������ִ��Ѱ�����������������������жϴ������ú���ΪѰ���жϺ�����
// �����ʼ�ŵ��Ų����������ʹ�ͷѰ������Ͳ�������ʹ�õIJ������ǵ�112--121��
// �����õ�ȫ�ֱ���ֵ�������ʼ�ŵ���seek_trackΪ0����ִ������У�������ô�ͷ����
// �
324 if (!seek) {
325 setup_rw_floppy(); // ������������顣
326 return;
327 }
328 do_floppy = seek_interrupt; // Ѱ���жϵ��õ�C������
329 if (seek_track) { // ��ʼ�ŵ��š�
330 output_byte(FD_SEEK); // ���ʹ�ͷѰ�����
331 output_byte(head<<2 | current_drive);// ���Ͳ�������ͷ��+��ǰ�����š�
332 output_byte(seek_track); // ���Ͳ������ŵ��š�
333 } else {
334 output_byte(FD_RECALIBRATE); // ��������У�������ͷ���㣩��
335 output_byte(head<<2 | current_drive);// ���Ͳ�������ͷ��+��ǰ�����š�
336 }
// ͬ���أ��������κ�һ��output_byte()����ִ�г�������λ��־reset�ͻᱻ��λ��
// ��reset��ı���λ�ˣ�������ȥִ��do_fd_request()�еĸ�λ�������롣
337 if (reset)
338 do_fd_request();
339 }
340
341 /*
342 * Special case - used after a unexpected interrupt (or reset)
343 */
/*
* ������� - ���������жϣ���λ��������
*/
//// ��������У���жϵ��ú�����
// ���ȷ��ͼ���ж�״̬�����������������ؽ���������������ø�λ��־����������
// У����־���㡣Ȼ���ٴ�ִ���������������������Ӧ������
344 static void recal_interrupt(void)
345 {
346 output_byte(FD_SENSEI); // ���ͼ���ж�״̬���
347 if (result()!=2 || (ST0 & 0xE0) == 0x60) // ������ؽ���ֽ���������2������
348 reset = 1; // �쳣���������ø�λ��־��
349 else
350 recalibrate = 0; // ����λ����У����־��
351 do_fd_request(); // ����Ӧ������
352 }
353
//// ���������ж����������������жϴ��������е��õĺ�����
// ���ȷ��ͼ���ж�״̬�����������������ؽ���������������ø�λ��־������������
// У����־��
354 void unexpected_floppy_interrupt(void)
355 {
356 output_byte(FD_SENSEI); // ���ͼ���ж�״̬���
357 if (result()!=2 || (ST0 & 0xE0) == 0x60) // ������ؽ���ֽ���������2������
358 reset = 1; // �쳣���������ø�λ��־��
359 else
360 recalibrate = 1; // ����������У����־��
361 }
362
//// ��������������������
// �����̿�����FDC��������У������Ͳ���������λ����У����־�������̿�����ִ����
// ����У������ͻ����������������ж��е���recal_interrupt()������
363 static void recalibrate_floppy(void)
364 {
365 recalibrate = 0; // ��λ����У����־��
366 current_track = 0; // ��ǰ�ŵ��Ź��㡣
367 do_floppy = recal_interrupt; // ָ������У���жϵ��õ�C������
368 output_byte(FD_RECALIBRATE); // �����������
369 output_byte(head<<2 | current_drive); // ��������ͷ�� + ��ǰ�������š�
// �������κ�һ��output_byte()����ִ�г�������λ��־reset�ͻᱻ��λ���������
// ������Ҫ���һ��reset��־����reset��ı���λ�ˣ�������ȥִ��do_fd_request()
// �еĸ�λ�������롣
370 if (reset)
371 do_fd_request();
372 }
373
//// ���̿�����FDC��λ�жϵ��ú�����
// �ú�������������������˸�λ��������������������жϴ��������б����á�
// ���ȷ��ͼ���ж�״̬�����������Ȼ��������صĽ���ֽڡ����ŷ����趨����
// �����������ز���������ٴε��������������do_fd_request() ȥִ������У��
// ������������ִ��output_byte() ��������ʱ��λ��־�ֻᱻ��λ�����Ҳ�����ٴ�ȥ
// ִ�и�λ������
374 static void reset_interrupt(void)
375 {
376 output_byte(FD_SENSEI); // ���ͼ���ж�״̬���
377 (void) result(); // ��ȡ����ִ�н���ֽڡ�
378 output_byte(FD_SPECIFY); // �����趨�����������
379 output_byte(cur_spec1); /* hut etc */ // ���Ͳ�����
380 output_byte(6); /* Head load time =6ms, DMA */
381 do_fd_request(); // ����ִ����������
382 }
383
384 /*
385 * reset is done by pulling bit 2 of DOR low for a while.
386 */
/* FDC��λ��ͨ������������Ĵ���(DOR)λ2��0һ���ʵ�ֵ� */
//// ��λ���̿�������
// �ú����������ò����ͱ�־���Ѹ�λ��־��0��Ȼ�����������cur_spec1��cur_rate
// ��Ϊ��Ч����Ϊ��λ��������������������Ҫ�������á�����������Ҫ����У����־��
// ������FDCִ�и�λ�����������������ж��е��õ�C����reset_interrupt()�����
// ��DOR�Ĵ���λ2��0һ����Զ�����ִ�и�λ��������ǰ��������Ĵ���DOR��λ2
// ������/������
387 static void reset_floppy(void)
388 {
389 int i;
390
391 reset = 0; // ��λ��־��0��
392 cur_spec1 = -1; // ʹ��Ч��
393 cur_rate = -1;
394 recalibrate = 1; // ����У����־��λ��
395 printk("Reset-floppy called\n\r"); // ��ʾִ�����̸�λ������Ϣ��
396 cli(); // ���жϡ�
397 do_floppy = reset_interrupt; // �������жϴ��������е��õĺ�����
398 outb_p(current_DOR & ~0x04,FD_DOR); // �����̿�����FDCִ�и�λ������
399 for (i=0 ; i<100 ; i++) // �ղ������ӳ١�
400 __asm__("nop");
401 outb(current_DOR,FD_DOR); // ���������̿�������
402 sti(); // ���жϡ�
403 }
404
//// ����������ʱ�жϵ��ú�����
// ��ִ��һ��������Ҫ��IJ���֮ǰ��Ϊ�˵ȴ�ָ������������ת�������������Ĺ���ת�٣�
// do_fd_request()����Ϊ���õĵ�ǰ������������һ����ʱ��ʱ�������������Ǹö�ʱ��
// ����ʱ���õĺ����������ȼ����������Ĵ���(DOR)��ʹ��ѡ��ǰָ������������Ȼ��
// ����ִ�����̶�д���亯��transfer()��
405 static void floppy_on_interrupt(void) // floppy_on() interrupt��
406 {
407 /* We cannot do a floppy-select, as that might sleep. We just force it */
/* ���Dz�����������ѡ�����������Ϊ����ܻ��������˯�ߡ�����ֻ����ʹ���Լ�ѡ�� */
// �����ǰ������������������Ĵ���DOR�еIJ�ͬ������Ҫ��������DORΪ��ǰ��������
// ������������Ĵ��������ǰDOR�Ժ�ʹ�ö�ʱ���ӳ�2���δ�ʱ�䣬��������õ�ִ
// �С�Ȼ��������̶�д���亯��transfer()������ǰ��������DOR�е��������ô�Ϳ���
// ֱ�ӵ������̶�д���亯����
408 selected = 1; // ����ѡ����ǰ��������־��
409 if (current_drive != (current_DOR & 3)) {
410 current_DOR &= 0xFC;
411 current_DOR |= current_drive;
412 outb(current_DOR,FD_DOR); // ����������Ĵ��������ǰDOR��
413 add_timer(2,&transfer); // ���Ӷ�ʱ����ִ�д��亯����
414 } else
415 transfer(); // ִ�����̶�д���亯����
416 }
417
//// ���̶�д�������������
// �ú�����������������������Ҫ�ĺ�������Ҫ�����ǣ��ٴ����и�λ��־������У����־��
// λ������������������е��豸�ż���ȡ��������ָ�������IJ����飻�������ںӶ�ʱ����
// �����̶�/д������
418 void do_fd_request(void)
419 {
420 unsigned int block;
421
// ���ȼ���Ƿ��и�λ��־������У����־��λ������������ִ����ر�־�Ĵ�������
// ��ͷ��ء������λ��־����λ����ִ�����̸�λ���������ء��������У����־����λ��
// ��ִ����������У�����������ء�
422 seek = 0; // ��Ѱ����־��
423 if (reset) { // ��λ��־����λ��
424 reset_floppy();
425 return;
426 }
427 if (recalibrate) { // ����У����־����λ��
428 recalibrate_floppy();
429 return;
430 }
// ���������������ܴ����↑ʼ����������blk.h�ļ��е�INIT_REQUEST��������������
// �Ϸ��ԣ������û�����������˳����μ�blk.h,127����Ȼ�������������е��豸��ȡ����
// ����ָ�������IJ����顣��������齫�����������������̲���ʹ�õ�ȫ�ֱ��������飨��
// ��112 - 122�У����������豸���е��������� (MINOR(CURRENT->dev)>>2) ������������
// ������floppy_type[]������ֵ��ȡ��ָ�������IJ����顣
431 INIT_REQUEST;
432 floppy = (MINOR(CURRENT->dev)>>2) + floppy_type;
// ���濪ʼ����112--122���ϵ�ȫ�ֱ���ֵ�������ǰ��������current_drive����������
// ��ָ�����������ţ����ñ�־seek����ʾ��ִ�ж�/д����֮ǰ��Ҫ����������ִ��Ѱ����
// ����Ȼ��ѵ�ǰ������������Ϊ��������ָ�����������š�
433 if (current_drive != CURRENT_DEV) // CURRENT_DEV����������ָ���������š�
434 seek = 1;
435 current_drive = CURRENT_DEV;
// ���ö�д��ʼ����block����Ϊÿ�ζ�д���Կ�Ϊ��λ��1��Ϊ2����������������ʼ����
// ��Ҫ����ȴ�����������С2������������˵����������������Ч�������ô�����������
// ȥִ����һ�������
436 block = CURRENT->sector; // ȡ��ǰ��������������ʼ�����š�
437 if (block+2 > floppy->size) { // ���block + 2���ڴ�������������
438 end_request(0); // ������������������
439 goto repeat;
440 }
// �����Ӧ�ڴŵ��ϵ������š���ͷ�š��ŵ��š���Ѱ�ŵ��ţ�������������ͬ��ʽ���̣���
441 sector = block % floppy->sect; // ��ʼ������ÿ�ŵ�������ȡģ���ôŵ��������š�
442 block /= floppy->sect; // ��ʼ������ÿ�ŵ�������ȡ��������ʼ�ŵ�����
443 head = block % floppy->head; // ��ʼ�ŵ����Դ�ͷ��ȡģ���ò����Ĵ�ͷ�š�
444 track = block / floppy->head; // ��ʼ�ŵ����Դ�ͷ��ȡ�����ò����Ĵŵ��š�
445 seek_track = track << floppy->stretch; // ��Ӧ�������������ͽ��е�������Ѱ���š�
// �ٿ����Ƿ���Ҫ����ִ��Ѱ�����������Ѱ�����뵱ǰ��ͷ���ڴŵ��Ų�ͬ������Ҫ����
// Ѱ����������������ҪѰ����־seek�������������ִ�е���������command��
446 if (seek_track != current_track)
447 seek = 1;
448 sector++; // ������ʵ�����������Ǵ�1����
449 if (CURRENT->cmd == READ) // ����������Ƕ����������ö������롣
450 command = FD_READ;
451 else if (CURRENT->cmd == WRITE) // �����������д����������д�����롣
452 command = FD_WRITE;
453 else
454 panic("do_fd_request: unknown command");
// ���������ú� 112--122��������ȫ�ֱ���ֵ֮�����ǿ��Կ�ʼִ������������ˡ��ò�
// �����ö�ʱ������������ΪΪ���ܶ��������ж�д��������Ҫ�����������������ﲢ�ﵽ��
// ����ת�ٶȡ�������Ҫһ����ʱ�䡣����������� ticks_to_floppy_on() ������������ʱ
// ʱ�䣬Ȼ��ʹ�ø���ʱ�趨һ����ʱ������ʱ�䵽ʱ�͵��ú���floppy_on_interrupt()��
455 add_timer(ticks_to_floppy_on(current_drive),&floppy_on_interrupt);
456 }
457
// ���������������̺��е����ݿ�������
458 static int floppy_sizes[] ={
459 0, 0, 0, 0,
460 360, 360 ,360, 360,
461 1200,1200,1200,1200,
462 360, 360, 360, 360,
463 720, 720, 720, 720,
464 360, 360, 360, 360,
465 720, 720, 720, 720,
466 1440,1440,1440,1440
467 };
468
//// ����ϵͳ��ʼ����
// �������̿��豸������Ĵ�������do_fd_request()�������������ж��ţ�int 0x26����Ӧ
// Ӳ���ж������ź�IRQ6���� Ȼ��ȡ���Ը��ж��źŵ����Σ����������̿�����FDC������
// �������źš��ж���������IDT�����������������ú�set_trap_gate()������ͷ�ļ�
// include/asm/system.h�С�
469 void floppy_init(void)
470 {
// ���������ж�����������floppy_interrupt��kernel/sys_call.s��267�У������жϴ���
// ���̡��жϺ�Ϊint 0x26��38������Ӧ8259AоƬ�ж������ź�IRQ6��
471 blk_size[MAJOR_NR] = floppy_sizes;
472 blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; // = do_fd_request()��
473 set_trap_gate(0x26,&floppy_interrupt); // ������������������
474 outb(inb_p(0x21)&~0x40,0x21); // ��λ�����ж���������λ��
475 }
476