summaryrefslogtreecommitdiff
path: root/kernel/floppy.c
diff options
context:
space:
mode:
authorMichal Idziorek <m.i@gmx.at>2014-08-20 15:55:03 +0200
committerMichal Idziorek <m.i@gmx.at>2014-08-20 15:55:03 +0200
commitdc164927e71d760a41494ab1edf8e3deeda401db (patch)
tree65253b4a5e443c599341d5972b58449388a4b2b1 /kernel/floppy.c
parent46063e75f3f81dfb532fa5772c88e9027a0faebd (diff)
started implementing floppy driver etc.
Diffstat (limited to 'kernel/floppy.c')
-rw-r--r--kernel/floppy.c426
1 files changed, 426 insertions, 0 deletions
diff --git a/kernel/floppy.c b/kernel/floppy.c
new file mode 100644
index 0000000..2c71cdb
--- /dev/null
+++ b/kernel/floppy.c
@@ -0,0 +1,426 @@
+#include "x86.h"
+
+#define FLPY_SECTORS_PER_TRACK 80
+static volatile int _CurrentDrive=0;
+static volatile uint8_t _FloppyDiskIRQ = 0;
+
+// temporary dma hack
+//! initialize DMA to use phys addr 1k-64k
+void flpydsk_initialize_dma () {
+
+ scr_put_string_nl("dma: initialize direct memory access");
+ x86_outb (0x0a,0x06); //mask dma channel 2
+ x86_outb (0xd8,0xff); //reset master flip-flop
+
+ //changed to 0x000 (Address)
+ x86_outb (0x04, 0x0); //low
+ x86_outb (0x04, 0xa0); //high
+
+ x86_outb (0xd8, 0xff); //reset master flip-flop
+ x86_outb (0x05, 0xff); //count to 0x23ff (number of bytes in a 3.5" floppy disk track)
+ x86_outb (0x05, 0x23);
+ x86_outb (0x80, 0); //external page register = 0
+ x86_outb (0x0a, 0x02); //unmask dma channel 2
+}
+
+//! prepare the DMA for read transfer
+void flpydsk_dma_read () {
+
+ x86_outb (0x0a, 0x06); //mask dma channel 2
+ x86_outb (0x0b, 0x56); //single transfer, address increment, autoinit, read, channel 2
+ x86_outb (0x0a, 0x02); //unmask dma channel 2
+ scr_put_string_nl("dma: configured for reading");
+}
+
+//! prepare the DMA for write transfer
+void flpydsk_dma_write () {
+
+ x86_outb (0x0a, 0x06); //mask dma channel 2
+ x86_outb (0x0b, 0x5a); //single transfer, address increment, autoinit, write, channel 2
+ x86_outb (0x0a, 0x02); //unmask dma channel 2
+ scr_put_string_nl("dma: configured for writing");
+}
+//
+//
+
+enum FLPYDSK_IO {
+
+ FLPYDSK_DOR = 0x3f2,
+ FLPYDSK_MSR = 0x3f4,
+ FLPYDSK_FIFO = 0x3f5, //data register
+ FLPYDSK_CTRL = 0x3f7
+};
+
+enum FLPYDSK_DOR_MASK {
+
+ FLPYDSK_DOR_MASK_DRIVE0 = 0, //00000000 = here for completeness sake
+ FLPYDSK_DOR_MASK_DRIVE1 = 1, //00000001
+ FLPYDSK_DOR_MASK_DRIVE2 = 2, //00000010
+ FLPYDSK_DOR_MASK_DRIVE3 = 3, //00000011
+ FLPYDSK_DOR_MASK_RESET = 4, //00000100
+ FLPYDSK_DOR_MASK_DMA = 8, //00001000
+ FLPYDSK_DOR_MASK_DRIVE0_MOTOR = 16, //00010000
+ FLPYDSK_DOR_MASK_DRIVE1_MOTOR = 32, //00100000
+ FLPYDSK_DOR_MASK_DRIVE2_MOTOR = 64, //01000000
+ FLPYDSK_DOR_MASK_DRIVE3_MOTOR = 128 //10000000
+};
+
+enum FLPYDSK_MSR_MASK {
+
+ FLPYDSK_MSR_MASK_DRIVE1_POS_MODE = 1, //00000001
+ FLPYDSK_MSR_MASK_DRIVE2_POS_MODE = 2, //00000010
+ FLPYDSK_MSR_MASK_DRIVE3_POS_MODE = 4, //00000100
+ FLPYDSK_MSR_MASK_DRIVE4_POS_MODE = 8, //00001000
+ FLPYDSK_MSR_MASK_BUSY = 16, //00010000
+ FLPYDSK_MSR_MASK_DMA = 32, //00100000
+ FLPYDSK_MSR_MASK_DATAIO = 64, //01000000
+ FLPYDSK_MSR_MASK_DATAREG = 128 //10000000
+};
+
+enum FLPYDSK_CMD {
+
+ FDC_CMD_READ_TRACK = 2,
+ FDC_CMD_SPECIFY = 3,
+ FDC_CMD_CHECK_STAT = 4,
+ FDC_CMD_WRITE_SECT = 5,
+ FDC_CMD_READ_SECT = 6,
+ FDC_CMD_CALIBRATE = 7,
+ FDC_CMD_CHECK_INT = 8,
+ FDC_CMD_WRITE_DEL_S = 9,
+ FDC_CMD_READ_ID_S = 0xa,
+ FDC_CMD_READ_DEL_S = 0xc,
+ FDC_CMD_FORMAT_TRACK = 0xd,
+ FDC_CMD_SEEK = 0xf
+};
+
+enum FLPYDSK_CMD_EXT {
+
+ FDC_CMD_EXT_SKIP = 0x20, //00100000
+ FDC_CMD_EXT_DENSITY = 0x40, //01000000
+ FDC_CMD_EXT_MULTITRACK = 0x80 //10000000
+};
+
+enum FLPYDSK_GAP3_LENGTH {
+
+ FLPYDSK_GAP3_LENGTH_STD = 42,
+ FLPYDSK_GAP3_LENGTH_5_14= 32,
+ FLPYDSK_GAP3_LENGTH_3_5= 27
+};
+
+enum FLPYDSK_SECTOR_DTL {
+
+ FLPYDSK_SECTOR_DTL_128 = 0,
+ FLPYDSK_SECTOR_DTL_256 = 1,
+ FLPYDSK_SECTOR_DTL_512 = 2,
+ FLPYDSK_SECTOR_DTL_1024 = 4
+};
+
+void flpydsk_write_dor (uint8_t val ) {
+
+ //! write the digital output register
+ x86_outb (FLPYDSK_DOR, val);
+
+}
+
+void flpydsk_write_ccr (uint8_t val) {
+
+ //! write the configuation control
+ x86_outb (FLPYDSK_CTRL, val);
+}
+
+void sleep(int i)
+{
+ i*=1000000;
+ for(;i>0;i--)
+ {
+
+ }
+}
+
+void flpydsk_motor_on()
+{
+ scr_put_string("floppy: starting motor...");
+ x86_outb (FLPYDSK_DOR, FLPYDSK_DOR_MASK_DRIVE0_MOTOR | FLPYDSK_DOR_MASK_RESET);
+ sleep(20);
+ scr_put_string_nl("ok");
+}
+void flpydsk_motor_off()
+{
+ scr_put_string("floppy: stopping motor...");
+ x86_outb (FLPYDSK_DOR,FLPYDSK_DOR_MASK_RESET);
+ scr_put_string_nl("ok");
+}
+
+int flpydsk_calibrate (uint32_t drive) {
+
+ uint32_t st0, cyl;
+
+ if (drive >= 4)
+ {
+
+ scr_put_string_nl("floppy: ERROR");
+ return -2;
+ }
+
+ //! turn on the motor
+ flpydsk_motor_on();
+
+ int i;
+ for (i = 0; i < 10; i++) {
+
+ scr_put_string_nl("floppy: calibrate");
+ //! send command
+ flpydsk_send_command ( FDC_CMD_CALIBRATE );
+ flpydsk_send_command ( drive );
+ flpydsk_wait_irq ();
+ flpydsk_check_int ( &st0, &cyl);
+
+ //! did we fine cylinder 0? if so, we are done
+ if (!cyl) {
+
+ // flpydsk_control_motor (false);
+ flpydsk_motor_off();
+ return 0;
+ }
+ }
+
+// flpydsk_control_motor (false);
+ flpydsk_motor_off();
+ return -1;
+}
+
+
+
+void flpydsk_disable_controller () {
+
+ flpydsk_write_dor (0);
+}
+
+void flpydsk_enable_controller () {
+
+ flpydsk_write_dor ( FLPYDSK_DOR_MASK_RESET | FLPYDSK_DOR_MASK_DMA);
+}
+
+
+uint8_t flpydsk_read_status () {
+
+ //! just return main status register
+ return x86_inb (FLPYDSK_MSR);
+}
+
+uint8_t flpydsk_read_data () {
+
+ //! same as above function but returns data register for reading
+ int i;
+ for (i = 0; i < 500; i++ )
+ if ( flpydsk_read_status () & FLPYDSK_MSR_MASK_DATAREG )
+ return x86_inb (FLPYDSK_FIFO);
+}
+void flpydsk_send_command (uint8_t cmd) {
+
+ //! wait until data register is ready. We send commands to the data register
+ int i;
+ for (i = 0; i < 500; i++ )
+ if ( flpydsk_read_status () & FLPYDSK_MSR_MASK_DATAREG )
+ {
+ x86_outb(FLPYDSK_FIFO, cmd);
+ return;
+ }
+}
+
+void flpydsk_drive_data (uint32_t stepr, uint32_t loadt, uint32_t unloadt, int nondma ) {
+
+ uint32_t data = 0;
+
+ flpydsk_send_command (FDC_CMD_SPECIFY);
+
+ data = ( (stepr & 0xf) << 4) | (unloadt & 0xf);
+ flpydsk_send_command (data);
+
+ data = (loadt) << 1 | nondma;
+ flpydsk_send_command (data);
+}
+
+void flpydsk_reset()
+{
+ uint32_t st0, cyl;
+
+ //! reset the controller
+ scr_put_string_nl("floppy: reset controller");
+ flpydsk_disable_controller ();
+ flpydsk_enable_controller ();
+ flpydsk_wait_irq ();
+
+ //! send CHECK_INT/SENSE INTERRUPT command to all drives
+ int i;
+ for (i=0; i<4; i++)
+ flpydsk_check_int (&st0,&cyl);
+
+ //! transfer speed 500kb/s
+ flpydsk_write_ccr (0);
+
+ //! pass mechanical drive info. steprate=3ms, unload time=240ms, load time=16ms
+ flpydsk_drive_data (3,16,240,0);
+
+ //! calibrate the disk
+ flpydsk_calibrate ( _CurrentDrive );
+}
+
+void floppy_init()
+{
+ // init dma
+ flpydsk_initialize_dma ();
+
+ _CurrentDrive=0;
+ _FloppyDiskIRQ = 0;
+
+ scr_put_string_nl("floppy: init floppy driver.");
+
+ flpydsk_reset ();
+ flpydsk_drive_data (13, 1, 0xf, 0);
+
+}
+
+void int_floppy_handler()
+{
+
+ X86_IRQ_BEGIN
+ _FloppyDiskIRQ=1;
+ X86_IRQ_END
+
+}
+
+void flpydsk_wait_irq()
+{
+ scr_put_string_nl("floppy: wait for irq6");
+ while ( _FloppyDiskIRQ == 0);
+ _FloppyDiskIRQ = 0;
+ scr_put_string_nl("floppy: ok received ");
+}
+
+void flpydsk_check_int (uint32_t* st0, uint32_t* cyl) {
+
+ flpydsk_send_command (FDC_CMD_CHECK_INT);
+
+ *st0 = flpydsk_read_data ();
+ *cyl = flpydsk_read_data ();
+}
+
+void flpydsk_read_sector_imp (uint8_t head, uint8_t track, uint8_t sector) {
+
+ //! set the DMA for read transfer
+ flpydsk_dma_read ();
+
+ flpydsk_drive_data (13, 1, 0xf, 0);
+ scr_put_string_nl("floppy: reading sector (2)");
+
+ uint32_t st0, cyl;
+
+
+ //! read in a sector
+ flpydsk_send_command (
+ FDC_CMD_READ_SECT | FDC_CMD_EXT_MULTITRACK |
+ FDC_CMD_EXT_SKIP | FDC_CMD_EXT_DENSITY);
+ flpydsk_send_command ( head << 2 | _CurrentDrive );
+ flpydsk_send_command ( track);
+ flpydsk_send_command ( head);
+ flpydsk_send_command ( sector);
+ flpydsk_send_command ( FLPYDSK_SECTOR_DTL_512 );
+ flpydsk_send_command (
+ ( ( sector + 1 ) >= FLPY_SECTORS_PER_TRACK )
+ ? FLPY_SECTORS_PER_TRACK : sector + 1 );
+ flpydsk_send_command ( FLPYDSK_GAP3_LENGTH_3_5 );
+ flpydsk_send_command ( 0xff );
+
+ //! wait for irq
+ //flpydsk_wait_irq ();
+
+ //! read status info
+ int j;
+ for (j=0; j<7; j++)
+ flpydsk_read_data ();
+
+ //! let FDC know we handled interrupt
+ flpydsk_check_int (&st0,&cyl);
+}
+
+int flpydsk_seek ( uint32_t cyl, uint32_t head )
+{
+
+ uint32_t st0, cyl0;
+
+ if (_CurrentDrive >= 4)
+ return -1;
+
+ int i;
+ for (i = 0; i < 10; i++ ) {
+
+ scr_put_string("floppy: seeking (cyl/head) : ");
+ scr_put_hex(cyl);
+ scr_put_string("/");
+ scr_put_hex(head);
+ scr_put_string_nl("");
+
+ //! send the command
+ flpydsk_send_command (FDC_CMD_SEEK);
+ flpydsk_send_command ( (head) << 2 | _CurrentDrive);
+ flpydsk_send_command (cyl);
+
+ //! wait for the results phase IRQ
+ //flpydsk_wait_irq ();
+
+ flpydsk_check_int (&st0,&cyl0);
+
+ //! found the cylinder?
+ if ( cyl0 == cyl)
+ return 0;
+ }
+
+ return -1;
+}
+
+void flpydsk_lba_to_chs (int lba,int *head,int *track,int *sector) {
+
+ *head = ( lba % ( FLPY_SECTORS_PER_TRACK * 2 ) ) / ( FLPY_SECTORS_PER_TRACK );
+ *track = lba / ( FLPY_SECTORS_PER_TRACK * 2 );
+ *sector = lba % FLPY_SECTORS_PER_TRACK + 1;
+}
+
+
+uint8_t* flpydsk_read_sector (int sectorLBA) {
+
+ sectorLBA=0x10;
+
+ scr_put_string("floppy: reading sector:");
+ scr_put_hex(sectorLBA);
+ scr_put_string_nl(".");
+
+
+ if (_CurrentDrive >= 4)
+ return 0;
+
+ //! convert LBA sector to CHS
+ int head=0, track=0, sector=1;
+ flpydsk_lba_to_chs (sectorLBA, &head, &track, &sector);
+
+
+ //! turn motor on and seek to track
+// flpydsk_control_motor (true);
+ // start motor
+ flpydsk_motor_on();
+
+ if (flpydsk_seek (track, head) != 0)
+ return 0;
+
+ //! read sector and turn motor off
+ flpydsk_read_sector_imp (head, track, sector);
+ // flpydsk_control_motor (false);
+ flpydsk_motor_off();
+
+
+ //! warning: this is a bit hackish
+ //return (uint8_t*) DMA_BUFFER;
+ return (uint8_t*) 0x0;
+}
+
+