Add motor spindown and multisector transfer support (although we only ever seem
authorDavid Given <dg@cowlark.com>
Wed, 18 Apr 2018 21:49:23 +0000 (23:49 +0200)
committerDavid Given <dg@cowlark.com>
Wed, 18 Apr 2018 21:49:23 +0000 (23:49 +0200)
to be asked for a single sector at a time). Fix so, so many bugs.

Kernel/platform-nc200/devfd.c
Kernel/platform-nc200/devfd.h
Kernel/platform-nc200/fdc765.s

index b5e1275..1822ab3 100644 (file)
@@ -1,20 +1,12 @@
-/* 
- *     Amstrad PCW8256 Floppy Driver
- */
-
 #include <kernel.h>
 #include <kdata.h>
 #include <printf.h>
 #include <devfd.h>
 #include <device.h>
 #include <blkdev.h>
+#include <timer.h>
 
-bool fd765_ready;
-
-static uint8_t motorct;
-static int8_t devsel = -1;
-
-__sfr __at 0xe0 fd_st;
+static timer_t spindown_timer = 0;
 
 void devfd_init(void)
 {
@@ -22,29 +14,28 @@ void devfd_init(void)
     if (!blk)
         return;
 
+    fd765_do_nudge_tc();
     fd765_track = 0xff; /* not on a known track */
     blk->transfer = devfd_transfer;
     blk->drive_lba_count = 1440; /* 512-byte sectors */
     blkdev_scan(blk, 0);
 }
 
-void devfd_spindown(void)
-{
-}
-
-static void motor_on(int minor)
+static void nudge_timer(void)
 {
-    minor;
-    mod_control(0x00, 0x20); /* motor on (active low) */
-    fd765_ready = false;
-    mod_irqen(0x20, 0x00); /* enable FDC IRQ */
+    di();
+    spindown_timer = set_timer_sec(2);
+    ei();
 }
 
-static void motor_off(void)
+/* (called from interrupt context) */
+void devfd_spindown(void)
 {
-    mod_control(0x20, 0x00); /* motor off (active low( */
-    mod_irqen(0x00, 0x20); /* disable FDC IRQ */
-    devsel = -1;
+    if (spindown_timer && timer_expired(spindown_timer))
+    {
+        mod_control(0x20, 0x00); /* motor off (active low) */
+        spindown_timer = 0;
+    }
 }
 
 /* Seek to track 0. */
@@ -56,31 +47,31 @@ static void fd_recalibrate(void)
 
     for (;;)
     {
+        nudge_timer();
         fd765_do_recalibrate();
         if (((fd765_status[0] & 0xf8) == 0x20) && !fd765_status[1])
             break;
     }
 
-    fd765_track = 0;
+    /* Forget which track we've saught to */
+    fd765_track = 0xff;
 }
 
 /* Set up the controller for a given block, seek, and wait for spinup. */
-static void fd_seek(void)
+static void fd_seek(uint16_t lba)
 {
-    uint16_t block = blk_op.lba;
-    uint8_t track2 = block / 9;
+    uint8_t track2 = lba / 9;
     uint8_t newtrack = track2 >> 1;
 
-    fd765_sector = (block % 9) + 1;
+    fd765_sector = (lba % 9) + 1;
     fd765_head = track2 & 1;
 
     if (newtrack != fd765_track)
     {
-        fd765_track = newtrack;
-
         for (;;)
         {
-            fd765_do_nudge_tc();
+            fd765_track = newtrack;
+            nudge_timer();
             fd765_do_seek();
             if ((fd765_status[0] & 0xf8) == 0x20)
                 break;
@@ -93,33 +84,40 @@ static void fd_seek(void)
 /* Select a drive and ensure the motor is on. */
 static void fd_select(int minor)
 {
-    if (devsel == minor)
-        return;
-    motor_on(minor);
+    (void)minor;
+
+    mod_control(0x00, 0x20); /* motor on (active low) */
+    nudge_timer();
 }
 
-/*
- *     Block transfer
- */
 uint8_t devfd_transfer(void)
 {
     int ct = 0;
     int tries;
+    int blocks = blk_op.nblock;
+    uint16_t lba = blk_op.lba;
 
-    fd_select(0);              /* Select, motor on */
+    fd_select(0);
     fd765_is_user = blk_op.is_user;
-    while (ct < blk_op.nblock) {       /* For each block */
-        for (tries = 0; tries < 3; tries ++) { /* Try 3 times */
+    fd765_buffer = blk_op.addr;
+
+    while (blocks != 0)
+    {
+        for (tries = 0; tries < 3; tries ++)
+        {
+            nudge_timer();
             if (tries != 0)
                 fd_recalibrate();
-            fd_seek();
+            fd_seek(lba);
 
-            fd765_buffer = blk_op.addr;
-            if (blk_op.is_read) {
+            fd765_sectors = 10 - fd765_sector;
+            if (fd765_sectors > blocks)
+                fd765_sectors = blocks;
+
+            if (blk_op.is_read)
                 fd765_do_read();
-            } else {
+            else
                 fd765_do_write();
-            }
 
             /* Did it work ? */
             if ((fd765_status[0] & 0xc0) == 0)
@@ -127,13 +125,14 @@ uint8_t devfd_transfer(void)
         }
         if (tries == 3)
         {
-            kprintf("fd%d: I/O error %d:%d\n", blk_op.is_read, blk_op.lba);
+            kprintf("fd%d: I/O error %d:%d\n", blk_op.is_read, lba);
             udata.u_error = EIO;
             break;
         }
-        udata.u_block++;
-        ct++;
-        blk_op.addr += 512;
+        lba += fd765_sectors;
+        blocks -= fd765_sectors;
+        ct += fd765_sectors;
     }
+
     return ct;
 }
\ No newline at end of file
index f41426b..2c59a93 100644 (file)
@@ -18,6 +18,7 @@ extern uint8_t fd765_head;
 extern uint8_t fd765_sector;
 extern uint8_t fd765_status[8];
 extern uint8_t* fd765_buffer;
+extern uint8_t fd765_sectors;
 extern bool fd765_is_user;
 
 #endif /* __DEVRD_DOT_H__ */
index 85056ae..60eeee6 100644 (file)
@@ -22,6 +22,7 @@
        .globl _fd765_status
        .globl _fd765_buffer
        .globl _fd765_is_user
+       .globl _fd765_sectors
 
        .area _COMMONMEM
 
@@ -131,7 +132,9 @@ _fd765_do_read:
        ld hl, (_fd765_buffer)
        ld c, #FD_DT
        ld b, #0
-       ld e, #2
+       ld a, (_fd765_sectors)
+       add a
+       ld e, a
 read_loop:
        in a, (FD_ST)
        rla                                                     ; RQM...
@@ -144,6 +147,7 @@ read_loop:
        dec e
        jr nz, read_loop                        ; outer loop: 2 iterations
 read_finished:
+       ld (_fd765_buffer), hl
        call _fd765_do_nudge_tc         ; Tell FDC we've finished
        call fd765_read_status
        ei
@@ -165,7 +169,9 @@ _fd765_do_write:
        ld hl, (_fd765_buffer)
        ld c, #FD_DT
        ld b, #0
-       ld e, #2
+       ld a, (_fd765_sectors)
+       add a
+       ld e, a
 write_loop:
        in a, (FD_ST)
        rla                                                     ; RQM...
@@ -178,6 +184,7 @@ write_loop:
        dec e
        jr nz, write_loop                       ; outer loop: 2 iterations
 write_finished:
+       ld (_fd765_buffer), hl
        call _fd765_do_nudge_tc         ; Tell FDC we've finished
        call fd765_read_status
        ei
@@ -201,7 +208,9 @@ setup_read_or_write:
        call fd765_tx
        ld a, #2                                        ; 5: bytes per sector: 512
        call fd765_tx
-       ld a, b                     ; 6: last sector (same as start sector)
+       ld a, (_fd765_sectors)          
+       add b                                           ; add first sector
+       dec a                                           ; 6: last sector (*inclusive*)
        call fd765_tx
        ld a, #27                                       ; 7: Gap 3 length (27 is standard for 3.5" drives)
        call fd765_tx
@@ -213,6 +222,8 @@ _fd765_buffer:
        .dw 0
 _fd765_is_user:
        .db 0
+_fd765_sectors:
+       .db 0
 
 ; Read the next sector ID off the disk.
 ; (Only used for debugging.)