/* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: */ #include #include #include typedef rt_uint8_t u8; typedef rt_uint16_t u16; typedef rt_uint32_t u32; typedef rt_int8_t s8; typedef rt_int16_t s16; typedef rt_int32_t s32; #define OUTB(v,p) outb(p,v) #include "floppy.h" #include "dma.h" #define SECTOR_SIZE 512 #define panic(str,...) do { rt_kprintf("panic::" str,##__VA_ARGS__); while(1); } while(0) #define _local_irq_save(level) level = rt_hw_interrupt_disable() #define _local_irq_restore(level) rt_hw_interrupt_enable(level) static u8 floppy_buffer[512]; /* 软盘高速缓冲区地址指针 */ #define MAX_REPLIES 7 static u8 floppy_reply_buffer[MAX_REPLIES]; /* 软驱回应缓冲区 */ #define ST0 (floppy_reply_buffer[0]) /* 软驱回应0号字节 */ #define ST1 (floppy_reply_buffer[1]) /* 软驱回应1号字节 */ #define ST2 (floppy_reply_buffer[2]) /* 软驱回应2号字节 */ #define ST3 (floppy_reply_buffer[3]) /* 软驱回应3号字节 */ static char *floppy_inc_name; /* 软驱型号名 */ static char *floppy_type; static u32 floppy_motor=0; /* 软驱马达状态字节 */ static u32 floppy_size =0; /**********************功能函数***************************/ static void floppy_result(void); /* 获得软驱响应状态 */ static u32 floppy_sendbyte(u32); /* 向软驱控制寄存器发送一个控制字节 */ static u32 floppy_getbyte(void); /* 从软驱数据寄存器得到一个数据字节 */ static u32 floppy_get_info(void); /* 得到软驱信息 */ static void floppy_motorOn(void); /* 打开软驱马达 */ static void floppy_motorOff(void); /* 关闭软驱马达 */ static void floppy_setmode(void); /* 软驱模式设置 */ static void block_to_hts(u32, u32*, u32*, u32*); /* 逻辑块转为磁盘头、磁道号和扇区号 */ static void floppy_setupDMA(void); /* 设置软驱DMA通道 */ static void floppy_read_cmd(u32 blk); /* 从软盘上读取指定的逻辑块到缓冲区 */ void floppy_result(void) { u8 stat, i,count; i=0; for(count=0; count<0xFF; count++) { stat = inb( FD_STATUS ) & (STATUS_READY|STATUS_DIR|STATUS_BUSY); //读取状态寄存器 if (stat == STATUS_READY) return; if (stat == (STATUS_READY|STATUS_DIR|STATUS_BUSY)) { if(i>7) break; floppy_reply_buffer[i++]=inb_p(FD_DATA); } } panic("Get floppy status times out !\n"); } u32 floppy_sendbyte( u32 value ) { u8 stat, i; for ( i = 0; i < 128; i++ ) { stat = inb( FD_STATUS ) & (STATUS_READY|STATUS_DIR); //读取状态寄存器 if ( stat == STATUS_READY ) { OUTB( value ,FD_DATA); //将参数写入数据寄存器 return 1; } io_delay(); // 作一些延迟 } return 0; } u32 floppy_getbyte(void) { u8 stat, i; for ( i = 0; i < 128; i++ ) { stat = inb( FD_STATUS ) & (STATUS_READY|STATUS_DIR|STATUS_BUSY); //读取状态寄存器 if (stat == STATUS_READY) return -1; if ( stat == 0xD0 ) return inb(FD_DATA); io_delay(); } return 0; } u32 floppy_get_info(void) { u32 i; u8 CmType, FdType; floppy_sendbyte(0x10); i = floppy_getbyte(); switch (i) { case 0x80: floppy_inc_name = "NEC765A controller"; break; case 0x90: floppy_inc_name = "NEC765B controller"; break; default: floppy_inc_name = "Enhanced controller"; break; } CmType = readcmos(0x10); //read floppy type from cmos FdType = (CmType>>4) & 0x07; if ( FdType == 0 ) panic("Floppy driver not found!"); switch( FdType ) { case 0x02: // 1.2MB floppy_type = "1.2MB"; floppy_size = 2458*512; break; case 0x04: // 1.44MB 标准软盘 floppy_type = "1.44MB"; floppy_size = 2880*512; break; case 0x05: // 2.88MB floppy_type = "2.88MB"; floppy_size = 2*2880*512; break; } return 1; } void floppy_motorOn( void ) { u32 eflags; if (!floppy_motor) { _local_irq_save(eflags); OUTB(28,FD_DOR); floppy_motor = 1; _local_irq_restore(eflags); } return; } void floppy_motorOff( void ) { u32 eflags; if (floppy_motor) { _local_irq_save(eflags); OUTB(12,FD_DOR); floppy_motor = 0; _local_irq_restore(eflags); } return; } void floppy_setmode(void) { floppy_sendbyte (FD_SPECIFY); floppy_sendbyte (0xcf); floppy_sendbyte (0x06); OUTB (0,FD_DCR); } void block_to_hts(u32 block, u32 *head, u32 *track, u32 *sector ) { *head = ( block % ( 18 * 2 ) ) /18; *track = block / ( 18 * 2 ); *sector = block % 18 + 1; } void floppy_setupDMA(void) { u32 eflags; _local_irq_save(eflags); DisableDma(2); ClearDmaFF(2); SetDmaMode(2,DMA_MODE_READ); SetDmaAddr(2,(unsigned long)floppy_buffer); SetDmaCount(2,512); EnableDma(2); _local_irq_restore(eflags); } void floppy_read_cmd(u32 blk) { u32 head; u32 track; u32 sector; block_to_hts(blk,&head,&track,§or); floppy_motorOn(); io_delay(); floppy_setupDMA(); io_delay(); floppy_setmode(); io_delay(); floppy_sendbyte (FD_READ); //send read command floppy_sendbyte (head*4 + 0); floppy_sendbyte (track); /* Cylinder */ floppy_sendbyte (head); /* Head */ floppy_sendbyte (sector); /* Sector */ floppy_sendbyte (2); /* 0=128, 1=256, 2=512, 3=1024, ... */ floppy_sendbyte (18); //floppy_sendbyte (sector+secs-1); /* Last sector in track:here are sectors count */ floppy_sendbyte (0x1B); floppy_sendbyte (0xff); return; } static struct rt_device devF; static struct rt_mutex lock; static struct rt_semaphore sem; /* RT-Thread device interface */ static rt_err_t rt_floppy_init_internal(rt_device_t dev) { return RT_EOK; } static rt_err_t rt_floppy_open(rt_device_t dev, rt_uint16_t oflag) { return RT_EOK; } static rt_err_t rt_floppy_close(rt_device_t dev) { return RT_EOK; } /* position: block page address, not bytes address * buffer: * size : how many blocks */ static rt_ssize_t rt_floppy_read(rt_device_t device, rt_off_t position, void *buffer, rt_size_t size) { rt_size_t doSize = size; rt_mutex_take(&lock, RT_WAITING_FOREVER); while(size>0) { floppy_read_cmd(position); rt_sem_take(&sem, RT_WAITING_FOREVER); /* waiting isr sem forever */ floppy_result(); io_delay(); if(ST1 != 0 || ST2 != 0) { panic("ST0 %d ST1 %d ST2 %d\n",ST0,ST1,ST2); } rt_memcpy(buffer, floppy_buffer, 512); floppy_motorOff(); io_delay(); position += 1; size -= 1; } rt_mutex_release(&lock); return doSize; } /* position: block page address, not bytes address * buffer: * size : how many blocks */ static rt_ssize_t rt_floppy_write(rt_device_t device, rt_off_t position, const void *buffer, rt_size_t size) { rt_mutex_take(&lock, RT_WAITING_FOREVER); panic("FIXME:I don't know how!\n"); rt_mutex_release(&lock); return size; } static rt_err_t rt_floppy_control(rt_device_t dev, int cmd, void *args) { RT_ASSERT(dev != RT_NULL); if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME) { struct rt_device_blk_geometry *geometry; geometry = (struct rt_device_blk_geometry *)args; if (geometry == RT_NULL) return -RT_ERROR; geometry->bytes_per_sector = SECTOR_SIZE; geometry->block_size = SECTOR_SIZE; geometry->sector_count = floppy_size / SECTOR_SIZE; } return RT_EOK; } static void rt_floppy_isr(int vector, void* param) { (void)vector; (void)param; rt_sem_release(&sem); } void rt_floppy_init(void) { struct rt_device *device; rt_mutex_init(&lock,"fdlock", RT_IPC_FLAG_PRIO); rt_sem_init(&sem, "fdsem", 0, RT_IPC_FLAG_FIFO); rt_hw_interrupt_install(FLOPPY_IRQ, rt_floppy_isr, RT_NULL, "floppy"); rt_hw_interrupt_umask(FLOPPY_IRQ); floppy_get_info(); rt_kprintf("Floppy Inc : %s Floppy Type : %s\n",floppy_inc_name,floppy_type); device = &(devF); device->type = RT_Device_Class_Block; device->init = rt_floppy_init_internal; device->open = rt_floppy_open; device->close = rt_floppy_close; device->read = rt_floppy_read; device->write = rt_floppy_write; device->control = rt_floppy_control; device->user_data = RT_NULL; rt_device_register(device, "floppy", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE); }