1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  */
8 #include <rtthread.h>
9 #include <rtdevice.h>
10 #include <rthw.h>
11 
12 #include <bsp.h>
13 
14 typedef rt_uint8_t  u8;
15 typedef rt_uint16_t u16;
16 typedef rt_uint32_t u32;
17 
18 typedef rt_int8_t  s8;
19 typedef rt_int16_t s16;
20 typedef rt_int32_t s32;
21 
22 #define OUTB(v,p) outb(p,v)
23 
24 #include "floppy.h"
25 #include "dma.h"
26 
27 #define SECTOR_SIZE 512
28 #define panic(str,...) do { rt_kprintf("panic::" str,##__VA_ARGS__); while(1); } while(0)
29 
30 #define _local_irq_save(level) level = rt_hw_interrupt_disable()
31 #define _local_irq_restore(level) rt_hw_interrupt_enable(level)
32 
33 static u8 floppy_buffer[512];                       /* 软盘高速缓冲区地址指针 */
34 
35 #define MAX_REPLIES 7
36 static u8 floppy_reply_buffer[MAX_REPLIES];         /* 软驱回应缓冲区 */
37 #define ST0 (floppy_reply_buffer[0])                /* 软驱回应0号字节 */
38 #define ST1 (floppy_reply_buffer[1])                /* 软驱回应1号字节 */
39 #define ST2 (floppy_reply_buffer[2])                /* 软驱回应2号字节 */
40 #define ST3 (floppy_reply_buffer[3])                /* 软驱回应3号字节 */
41 
42 
43 static char *floppy_inc_name;                       /* 软驱型号名 */
44 static char *floppy_type;
45 static u32  floppy_motor=0;                         /* 软驱马达状态字节 */
46 static u32  floppy_size =0;
47 /**********************功能函数***************************/
48 static void floppy_result(void);                    /* 获得软驱响应状态  */
49 static u32  floppy_sendbyte(u32);                   /* 向软驱控制寄存器发送一个控制字节  */
50 static u32  floppy_getbyte(void);                   /* 从软驱数据寄存器得到一个数据字节  */
51 static u32  floppy_get_info(void);                  /* 得到软驱信息  */
52 static void floppy_motorOn(void);                   /* 打开软驱马达  */
53 static void floppy_motorOff(void);                  /* 关闭软驱马达  */
54 static void floppy_setmode(void);                   /* 软驱模式设置  */
55 static void block_to_hts(u32, u32*, u32*, u32*);    /* 逻辑块转为磁盘头、磁道号和扇区号  */
56 static void floppy_setupDMA(void);                  /* 设置软驱DMA通道  */
57 static void floppy_read_cmd(u32 blk);               /* 从软盘上读取指定的逻辑块到缓冲区  */
58 
59 
floppy_result(void)60 void floppy_result(void)
61 {
62     u8 stat, i,count;
63     i=0;
64     for(count=0; count<0xFF; count++)
65     {
66         stat = inb( FD_STATUS ) & (STATUS_READY|STATUS_DIR|STATUS_BUSY); //读取状态寄存器
67         if (stat == STATUS_READY)
68             return;
69         if (stat == (STATUS_READY|STATUS_DIR|STATUS_BUSY))
70         {
71             if(i>7) break;
72             floppy_reply_buffer[i++]=inb_p(FD_DATA);
73         }
74     }
75 
76     panic("Get floppy status times out !\n");
77 }
78 
floppy_sendbyte(u32 value)79 u32 floppy_sendbyte( u32 value )
80 {
81     u8 stat, i;
82 
83     for ( i = 0; i < 128; i++ ) {
84         stat = inb( FD_STATUS ) & (STATUS_READY|STATUS_DIR);    //读取状态寄存器
85         if  ( stat  == STATUS_READY )
86         {
87             OUTB( value ,FD_DATA);                              //将参数写入数据寄存器
88             return 1;
89         }
90         io_delay();                                             // 作一些延迟
91     }
92     return 0;
93 }
94 
95 
floppy_getbyte(void)96 u32 floppy_getbyte(void)
97 {
98     u8 stat, i;
99 
100     for ( i = 0; i < 128; i++ ) {
101         stat = inb( FD_STATUS ) & (STATUS_READY|STATUS_DIR|STATUS_BUSY); //读取状态寄存器
102         if (stat == STATUS_READY)
103             return -1;
104         if ( stat  == 0xD0 )
105             return inb(FD_DATA);
106         io_delay();
107     }
108     return 0;
109 }
110 
111 
floppy_get_info(void)112 u32 floppy_get_info(void)
113 {
114     u32 i;
115     u8 CmType, FdType;
116 
117     floppy_sendbyte(0x10);
118     i = floppy_getbyte();
119 
120     switch (i)
121     {
122         case 0x80:   floppy_inc_name = "NEC765A controller"; break;
123         case 0x90:   floppy_inc_name = "NEC765B controller"; break;
124         default:     floppy_inc_name = "Enhanced controller"; break;
125     }
126 
127     CmType = readcmos(0x10);        //read floppy type from cmos
128     FdType   = (CmType>>4) & 0x07;
129 
130     if ( FdType == 0 )
131         panic("Floppy driver not found!");
132 
133     switch( FdType )
134     {
135     case 0x02: // 1.2MB
136         floppy_type = "1.2MB";
137         floppy_size = 2458*512;
138     break;
139 
140     case 0x04: // 1.44MB       标准软盘
141         floppy_type = "1.44MB";
142         floppy_size = 2880*512;
143         break;
144 
145     case 0x05: // 2.88MB
146         floppy_type = "2.88MB";
147         floppy_size = 2*2880*512;
148         break;
149     }
150     return 1;
151 }
152 
153 
floppy_motorOn(void)154 void floppy_motorOn( void )
155 {
156     u32 eflags;
157     if (!floppy_motor)
158     {
159         _local_irq_save(eflags);
160         OUTB(28,FD_DOR);
161         floppy_motor = 1;
162         _local_irq_restore(eflags);
163     }
164     return;
165 }
166 
167 
floppy_motorOff(void)168 void floppy_motorOff( void )
169 {
170     u32 eflags;
171     if (floppy_motor)
172     {
173         _local_irq_save(eflags);
174         OUTB(12,FD_DOR);
175         floppy_motor = 0;
176         _local_irq_restore(eflags);
177 
178     }
179     return;
180 }
181 
182 
floppy_setmode(void)183 void floppy_setmode(void)
184 {
185     floppy_sendbyte (FD_SPECIFY);
186     floppy_sendbyte (0xcf);
187     floppy_sendbyte (0x06);
188     OUTB (0,FD_DCR);
189 }
190 
191 
block_to_hts(u32 block,u32 * head,u32 * track,u32 * sector)192 void block_to_hts(u32 block, u32 *head, u32 *track, u32 *sector )
193 {
194     *head = ( block % ( 18 * 2 ) ) /18;
195     *track =  block / ( 18 * 2 );
196     *sector = block % 18 + 1;
197 }
198 
199 
floppy_setupDMA(void)200 void floppy_setupDMA(void)
201 {
202     u32 eflags;
203     _local_irq_save(eflags);
204     DisableDma(2);
205     ClearDmaFF(2);
206     SetDmaMode(2,DMA_MODE_READ);
207     SetDmaAddr(2,(unsigned long)floppy_buffer);
208     SetDmaCount(2,512);
209     EnableDma(2);
210     _local_irq_restore(eflags);
211 }
212 
213 
floppy_read_cmd(u32 blk)214 void floppy_read_cmd(u32 blk)
215 {
216     u32 head;
217     u32 track;
218     u32 sector;
219 
220     block_to_hts(blk,&head,&track,&sector);
221 
222     floppy_motorOn();
223     io_delay();
224 
225     floppy_setupDMA();
226     io_delay();
227 
228     floppy_setmode();
229     io_delay();
230     floppy_sendbyte (FD_READ);                  //send read command
231     floppy_sendbyte (head*4 + 0);
232     floppy_sendbyte (track);                    /*  Cylinder  */
233     floppy_sendbyte (head);                     /*  Head  */
234     floppy_sendbyte (sector);                   /*  Sector  */
235     floppy_sendbyte (2);                        /*  0=128, 1=256, 2=512, 3=1024, ...  */
236     floppy_sendbyte (18);
237     //floppy_sendbyte (sector+secs-1);          /*  Last sector in track:here are  sectors count */
238     floppy_sendbyte (0x1B);
239     floppy_sendbyte (0xff);
240     return;
241 }
242 
243 static struct rt_device devF;
244 static struct rt_mutex lock;
245 static struct rt_semaphore sem;
246 
247 /* RT-Thread device interface */
248 
rt_floppy_init_internal(rt_device_t dev)249 static rt_err_t rt_floppy_init_internal(rt_device_t dev)
250 {
251     return RT_EOK;
252 }
253 
rt_floppy_open(rt_device_t dev,rt_uint16_t oflag)254 static rt_err_t rt_floppy_open(rt_device_t dev, rt_uint16_t oflag)
255 {
256     return RT_EOK;
257 }
258 
rt_floppy_close(rt_device_t dev)259 static rt_err_t rt_floppy_close(rt_device_t dev)
260 {
261     return RT_EOK;
262 }
263 
264 /* position: block page address, not bytes address
265  * buffer:
266  * size  : how many blocks
267  */
rt_floppy_read(rt_device_t device,rt_off_t position,void * buffer,rt_size_t size)268 static rt_ssize_t rt_floppy_read(rt_device_t device, rt_off_t position, void *buffer, rt_size_t size)
269 {
270     rt_size_t doSize = size;
271 
272     rt_mutex_take(&lock, RT_WAITING_FOREVER);
273     while(size>0)
274     {
275         floppy_read_cmd(position);
276 
277         rt_sem_take(&sem, RT_WAITING_FOREVER); /* waiting isr sem forever */
278 
279         floppy_result();
280         io_delay();
281 
282         if(ST1 != 0 || ST2 != 0)
283         {
284             panic("ST0 %d ST1 %d ST2 %d\n",ST0,ST1,ST2);
285         }
286 
287         rt_memcpy(buffer, floppy_buffer, 512);
288 
289         floppy_motorOff();
290         io_delay();
291 
292         position += 1;
293         size     -= 1;
294     }
295     rt_mutex_release(&lock);
296 
297     return doSize;
298 }
299 
300 /* position: block page address, not bytes address
301  * buffer:
302  * size  : how many blocks
303  */
rt_floppy_write(rt_device_t device,rt_off_t position,const void * buffer,rt_size_t size)304 static rt_ssize_t rt_floppy_write(rt_device_t device, rt_off_t position, const void *buffer, rt_size_t size)
305 {
306     rt_mutex_take(&lock, RT_WAITING_FOREVER);
307     panic("FIXME:I don't know how!\n");
308     rt_mutex_release(&lock);
309     return size;
310 }
311 
rt_floppy_control(rt_device_t dev,int cmd,void * args)312 static rt_err_t rt_floppy_control(rt_device_t dev, int cmd, void *args)
313 {
314     RT_ASSERT(dev != RT_NULL);
315 
316     if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
317     {
318         struct rt_device_blk_geometry *geometry;
319 
320         geometry = (struct rt_device_blk_geometry *)args;
321         if (geometry == RT_NULL) return -RT_ERROR;
322 
323         geometry->bytes_per_sector = SECTOR_SIZE;
324         geometry->block_size = SECTOR_SIZE;
325 
326         geometry->sector_count = floppy_size / SECTOR_SIZE;
327     }
328 
329     return RT_EOK;
330 }
331 
rt_floppy_isr(int vector,void * param)332 static void rt_floppy_isr(int vector, void* param)
333 {
334     (void)vector;
335     (void)param;
336     rt_sem_release(&sem);
337 }
338 
rt_floppy_init(void)339 void rt_floppy_init(void)
340 {
341     struct rt_device *device;
342 
343     rt_mutex_init(&lock,"fdlock", RT_IPC_FLAG_PRIO);
344     rt_sem_init(&sem, "fdsem", 0, RT_IPC_FLAG_FIFO);
345 
346     rt_hw_interrupt_install(FLOPPY_IRQ, rt_floppy_isr, RT_NULL, "floppy");
347     rt_hw_interrupt_umask(FLOPPY_IRQ);
348 
349     floppy_get_info();
350     rt_kprintf("Floppy Inc : %s  Floppy Type : %s\n",floppy_inc_name,floppy_type);
351 
352     device = &(devF);
353 
354     device->type  = RT_Device_Class_Block;
355     device->init = rt_floppy_init_internal;
356     device->open = rt_floppy_open;
357     device->close = rt_floppy_close;
358     device->read = rt_floppy_read;
359     device->write = rt_floppy_write;
360     device->control = rt_floppy_control;
361     device->user_data = RT_NULL;
362 
363     rt_device_register(device, "floppy",
364                        RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);
365 
366 }
367