FDC READ and WRITE

Basic read and write functionality. Status codes still not correct, no media change or write protect detection yet.
This commit is contained in:
Peter Weingartner 2022-05-12 18:58:48 -04:00
parent fcd89cc069
commit 3e7f1e9f7f
10 changed files with 11723 additions and 11508 deletions

Binary file not shown.

View file

@ -7,8 +7,12 @@
#include "simpleio.h" #include "simpleio.h"
#include "sys_general.h" #include "sys_general.h"
#include "syscalls.h" #include "syscalls.h"
#include "types.h"
#include "mem_cmds.h" #include "mem_cmds.h"
/* Pointer to a function taking void and returning void */
typedef void (*p_thunk)();
/* /*
* Print out the contents of a block of memory * Print out the contents of a block of memory
* *
@ -38,9 +42,6 @@ short mem_cmd_dump(short channel, int argc, const char * argv[]) {
} }
} }
/* Pointer to a function taking void and returning void */
typedef void (*p_thunk)();
void test_thunk() { void test_thunk() {
log(LOG_ERROR, "CALL is working."); log(LOG_ERROR, "CALL is working.");
} }

View file

@ -412,7 +412,7 @@ short cli_test_seek(short screen, int argc, const char * argv[]) {
/* /*
* Test the FDC interface by reading the MBR * Test the FDC interface by reading the MBR
* *
* TEST FDC [DMA] * TEST FDC [<lba> [WRITE <data>]]
*/ */
short cli_test_fdc(short screen, int argc, const char * argv[]) { short cli_test_fdc(short screen, int argc, const char * argv[]) {
unsigned char buffer[512]; unsigned char buffer[512];
@ -422,12 +422,16 @@ short cli_test_fdc(short screen, int argc, const char * argv[]) {
short scancode; short scancode;
short n = 0; short n = 0;
short result; short result;
short is_write = 0;
unsigned char data = 0xAA;
if (argc > 1) { if (argc > 1) {
if ((strcmp(argv[1], "DMA") == 0) || ((strcmp(argv[1], "dma") == 0)) { lba = (unsigned long)cli_eval_number(argv[1]);
fdc_set_dma(1); if (argc > 2) {
print(screen, "Will attempt to write before reading...\n");
is_write = 1;
data = (unsigned long)cli_eval_number(argv[3]);
} }
// lba = (unsigned long)cli_eval_number(argv[1]);
} }
bdev_ioctrl(BDEV_FDC, FDC_CTRL_MOTOR_ON, 0, 0); bdev_ioctrl(BDEV_FDC, FDC_CTRL_MOTOR_ON, 0, 0);
@ -439,6 +443,21 @@ short cli_test_fdc(short screen, int argc, const char * argv[]) {
return result; return result;
} }
for (i = 0; i < 512; i++) {
buffer[i] = data;
}
if (is_write) {
n = bdev_write(BDEV_FDC, lba, buffer, 512);
if (n < 0) {
dump_buffer(screen, buffer, 512, 1);
sprintf(message, "Unable to write sector %d: %s\n", lba, err_message(n));
print(screen, message);
bdev_ioctrl(BDEV_FDC, FDC_CTRL_MOTOR_OFF, 0, 0);
return n;
}
}
for (i = 0; i < 512; i++) { for (i = 0; i < 512; i++) {
buffer[i] = 0xAA; buffer[i] = 0xAA;
} }

View file

@ -16,6 +16,7 @@
#include "fdc.h" #include "fdc.h"
#include "fdc_reg.h" #include "fdc_reg.h"
#include "interrupt.h" #include "interrupt.h"
#include "rtc_reg.h"
#include "syscalls.h" #include "syscalls.h"
/* /*
@ -23,7 +24,7 @@
*/ */
const long fdc_motor_wait = 18; /* The number of jiffies to wait for the motor to spin up: 300ms */ const long fdc_motor_wait = 18; /* The number of jiffies to wait for the motor to spin up: 300ms */
const long fdc_motor_timeout = 120; /* The number of jiffies to let the motor spin without activity: 2 seconds */ const long fdc_motor_timeout = 300; /* The number of jiffies to let the motor spin without activity: 30 seconds */
const long fdc_seek_timeout = 180; /* 3s timeout for the head to seek */ const long fdc_seek_timeout = 180; /* 3s timeout for the head to seek */
const long fdc_timeout = 120; /* The number of jiffies to allow for basic wait loops */ const long fdc_timeout = 120; /* The number of jiffies to allow for basic wait loops */
@ -71,6 +72,12 @@ static short fdc_cylinders = 80; /* How many cylinders */
static short fdc_bytes_per_sector = 512; /* How many bytes are in a sector */ static short fdc_bytes_per_sector = 512; /* How many bytes are in a sector */
static short fdc_use_dma = 0; /* If 0: used polled I/O, if anything else, use DMA */ static short fdc_use_dma = 0; /* If 0: used polled I/O, if anything else, use DMA */
/**
* Check the current jiffy count and turn off the motor if we've reached the time the motor should be turned off
* This time gets reset every time we ask for the motor to be turned on
*/
extern void fdc_motor_watchdog();
/* /*
* Convert a logical block address to cylinder-head-sector addressing * Convert a logical block address to cylinder-head-sector addressing
* *
@ -226,31 +233,14 @@ void fdc_delay(int jiffies) {
* 0 on success, negative number is an error * 0 on success, negative number is an error
*/ */
short fdc_in(unsigned char *ptr) { short fdc_in(unsigned char *ptr) {
unsigned char msr, data; long target_ticks = timers_jiffies() + fdc_timeout;
short step, i; while ((*FDC_MSR & FDC_MSR_RQM) != FDC_MSR_RQM) {
if (timers_jiffies() >= target_ticks) {
step = 1; log(LOG_ERROR, "fdc_in: timeout waiting for RQM");
for (i = 0; i < fdc_timeout; i += step) { return DEV_TIMEOUT;
msr = *FDC_MSR & (FDC_MSR_DIO | FDC_MSR_RQM);
if (msr == (FDC_MSR_DIO | FDC_MSR_RQM)) {
data = *FDC_DATA;
if (ptr)
*ptr = data;
return 0;
}
if (msr == FDC_MSR_RQM) {
log(LOG_ERROR, "fdc_in: ready for output during input");
return ERR_GENERAL;
} }
step += step;
fdc_delay(step);
} }
*ptr = *FDC_DATA;
log(LOG_ERROR, "fdc_in: timeout");
return DEV_TIMEOUT;
} }
/* /*
@ -263,30 +253,19 @@ short fdc_in(unsigned char *ptr) {
* 0 on success, negative number is an error * 0 on success, negative number is an error
*/ */
short fdc_out(unsigned char x) { short fdc_out(unsigned char x) {
unsigned char msr, data; long target_ticks = timers_jiffies() + fdc_timeout;
short step, i; while ((*FDC_MSR & FDC_MSR_RQM) != FDC_MSR_RQM) {
if (timers_jiffies() >= target_ticks) {
step = 1; log(LOG_ERROR, "fdc_out: timeout waiting for RQM");
for (i = 0; i < fdc_timeout; i += step) { return DEV_TIMEOUT;
msr = *FDC_MSR & (FDC_MSR_DIO | FDC_MSR_RQM);
if (msr == FDC_MSR_RQM) {
*FDC_DATA = x;
return 0;
}
if (msr == (FDC_MSR_DIO | FDC_MSR_RQM)) {
log(LOG_ERROR, "fdc_out: ready for input in output");
return ERR_GENERAL;
} }
}
step += step; *FDC_DATA = x;
fdc_delay(step); return 0;
}
log(LOG_ERROR, "fdc_out: timeout");
return DEV_TIMEOUT;
} }
/* /*
* Spin up the drive's spindle motor * Spin up the drive's spindle motor
*/ */
@ -312,9 +291,19 @@ short fdc_motor_on() {
while (wait_time > timers_jiffies()) ; while (wait_time > timers_jiffies()) ;
// } // }
short needs_handler = 0;
if (fdc_motor_off_time == 0) {
needs_handler = 1;
}
/* Set a new target time to shut off the motor */ /* Set a new target time to shut off the motor */
fdc_motor_off_time = timers_jiffies() + fdc_motor_timeout; fdc_motor_off_time = timers_jiffies() + fdc_motor_timeout;
if (needs_handler) {
// Register the FDC motor watchdog to monitor for motor timeout
rtc_register_periodic(RTC_RATE_500ms, fdc_motor_watchdog);
}
/* Flag that the motor is on */ /* Flag that the motor is on */
fdc_stat |= FDC_STAT_MOTOR_ON; fdc_stat |= FDC_STAT_MOTOR_ON;
@ -330,7 +319,7 @@ void fdc_motor_off() {
TRACE("fdc_motor_off"); TRACE("fdc_motor_off");
if ((*FDC_DOR & FDC_DOR_MOT0) == FDC_DOR_MOT0) { if ((*FDC_DOR & FDC_DOR_MOT0) == FDC_DOR_MOT0) {
/* Motor is not on... turn it on without DMA or RESET */ /* Motor is not on... turn it off without DMA or RESET */
*FDC_DOR = FDC_DOR_NRESET; *FDC_DOR = FDC_DOR_NRESET;
if (fdc_wait_rqm()) { if (fdc_wait_rqm()) {
@ -342,9 +331,26 @@ void fdc_motor_off() {
/* Flag that the motor is off */ /* Flag that the motor is off */
fdc_stat &= ~FDC_STAT_MOTOR_ON; fdc_stat &= ~FDC_STAT_MOTOR_ON;
// Reset the motor off time to 0, so we know we need to reinstall the watchdog later
fdc_motor_off_time = 0;
// Remove the FDC motor watchdog
rtc_register_periodic(0, 0);
ind_set(IND_FDC, IND_OFF); ind_set(IND_FDC, IND_OFF);
} }
/**
* Check the current jiffy count and turn off the motor if we've reached the time the motor should be turned off
* This time gets reset every time we ask for the motor to be turned on
*/
void fdc_motor_watchdog() {
unsigned char flags = *RTC_FLAGS;
if (timers_jiffies() >= fdc_motor_off_time) {
fdc_motor_off();
}
}
/* /*
* Issue the SENSE INTERRUPT command * Issue the SENSE INTERRUPT command
* *
@ -453,11 +459,14 @@ short fdc_specify() {
} }
/* Set head load time to maximum, and no DMA */ /* Set head load time to maximum, and no DMA */
unsigned char hlt_ndma = 0;
if (fdc_use_dma) { if (fdc_use_dma) {
*FDC_DATA = 0x0B; hlt_ndma = 0x0A;
} else { } else {
*FDC_DATA = 0x0A; hlt_ndma = 0x0B;
} }
log_num(LOG_INFO, "FDC specify: ", hlt_ndma);
*FDC_DATA = hlt_ndma;
return 0; return 0;
} }
@ -503,8 +512,8 @@ short fdc_configure() {
return DEV_TIMEOUT; return DEV_TIMEOUT;
} }
/* Implied seek, enable FIFO, enable POLL, FIFO threshold = 8 bytes */ /* Implied seek, enable FIFO, enable POLL, FIFO threshold = 16 bytes */
*FDC_DATA = 0x47; *FDC_DATA = 0x4F;
if (fdc_wait_write()) { if (fdc_wait_write()) {
/* Timed out waiting for the FDC to be free */ /* Timed out waiting for the FDC to be free */
@ -571,8 +580,17 @@ short fdc_reset() {
/* Reset the controller */ /* Reset the controller */
*FDC_DOR = 0; *FDC_DOR = 0;
target_time = timers_jiffies() + 2; target_time = timers_jiffies() + 2;
while (target_time > timers_jiffies()) ; while (target_time > timers_jiffies());
*FDC_DOR = FDC_DOR_NRESET;
unsigned char dor = 0;
if (fdc_use_dma) {
dor = FDC_DOR_NRESET | FDC_DOR_DMAEN;
} else {
dor = FDC_DOR_NRESET;
}
log_num(LOG_INFO, "FDC DOR: ", dor);
*FDC_DOR = dor;
/* Default precompensation, data rate for 1.44MB */ /* Default precompensation, data rate for 1.44MB */
*FDC_DSR = 0x80; *FDC_DSR = 0x80;
@ -711,6 +729,8 @@ short fdc_command_dma(p_fdc_trans transaction) {
/* Result phase: read the result bytes */ /* Result phase: read the result bytes */
fdc_delay(30);
for (i = 0; i < transaction->result_count; i++) { for (i = 0; i < transaction->result_count; i++) {
if ((result = fdc_in(&transaction->results[i])) < 0) { if ((result = fdc_in(&transaction->results[i])) < 0) {
log(LOG_ERROR, "fdc_command: timeout getting results"); log(LOG_ERROR, "fdc_command: timeout getting results");
@ -775,16 +795,21 @@ short fdc_command(p_fdc_trans transaction) {
switch (transaction->direction) { switch (transaction->direction) {
case FDC_TRANS_WRITE: case FDC_TRANS_WRITE:
/* We're writing to the FDC */ /* We're writing to the FDC */
for (i = 0; (i < transaction->data_count); i++) {
if ((result = fdc_out(transaction->data[i])) < 0) {
log(LOG_ERROR, "fdc_command: timeout writing data");
return result;
}
}
break; break;
case FDC_TRANS_READ: case FDC_TRANS_READ:
/* We're reading from the FDC */ /* We're reading from the FDC */
for (i = 0; (i < transaction->data_count) && ((*FDC_MSR & FDC_MSR_NONDMA) == FDC_MSR_NONDMA); i++) { for (i = 0; (i < transaction->data_count); i++) {
if ((result = fdc_in(&transaction->data[i])) < 0) { if ((result = fdc_in(&transaction->data[i])) < 0) {
log(LOG_ERROR, "fdc_command: timeout getting data"); log(LOG_ERROR, "fdc_command: timeout getting data");
return result; return result;
} }
sys_chan_write_b(0, '.');
} }
break; break;
@ -794,6 +819,8 @@ short fdc_command(p_fdc_trans transaction) {
/* Result phase: read the result bytes */ /* Result phase: read the result bytes */
fdc_delay(2);
for (i = 0; i < transaction->result_count; i++) { for (i = 0; i < transaction->result_count; i++) {
if ((result = fdc_in(&transaction->results[i])) < 0) { if ((result = fdc_in(&transaction->results[i])) < 0) {
log(LOG_ERROR, "fdc_command: timeout getting results"); log(LOG_ERROR, "fdc_command: timeout getting results");
@ -892,7 +919,7 @@ short fdc_recalibrate() {
if ((result == 0)) { if ((result == 0)) {
break; break;
} else { } else {
log_num(LOG_ERROR, "fdc_recalibrate: retry ", result); log_num(LOG_INFO, "fdc_recalibrate: retry ", result);
} }
fdc_init(); fdc_init();
trans.retries--; trans.retries--;
@ -947,7 +974,7 @@ short fdc_sense_status() {
if ((result == 0)) { if ((result == 0)) {
break; break;
} else { } else {
log_num(LOG_ERROR, "fdc_sense_status: retry ", result); log_num(LOG_INFO, "fdc_sense_status: retry ", result);
} }
fdc_init(); fdc_init();
trans.retries--; trans.retries--;
@ -989,16 +1016,6 @@ short fdc_read(long lba, unsigned char * buffer, short size) {
fdc_motor_on(); fdc_motor_on();
/* Check if the disk has changed and recalibrate if it has */
// if (*FDC_DIR & 0x80) {
// fdc_stat = FDC_STAT_NOINIT;
// if (fdc_recalibrate()) {
// return DEV_NOMEDIA;
// } else {
// return ERR_MEDIA_CHANGE;
// }
// }
trans.retries = 1; //FDC_DEFAULT_RETRIES; trans.retries = 1; //FDC_DEFAULT_RETRIES;
trans.command = 0x40 | FDC_CMD_READ_DATA; /* MFM read command */ trans.command = 0x40 | FDC_CMD_READ_DATA; /* MFM read command */
trans.direction = FDC_TRANS_READ; /* We're going to read from the drive */ trans.direction = FDC_TRANS_READ; /* We're going to read from the drive */
@ -1020,13 +1037,16 @@ short fdc_read(long lba, unsigned char * buffer, short size) {
while (trans.retries > 0) { while (trans.retries > 0) {
if (fdc_use_dma) { if (fdc_use_dma) {
result = fdc_command_dma(&trans); /* Issue the transaction */ result = fdc_command_dma(&trans); /* Issue the transaction */
log_num(LOG_ERROR, "fdc_command_dma: ", result); log_num(LOG_INFO, "fdc_command_dma: ", result);
} else { } else {
result = fdc_cmd_asm(trans.command, trans.parameter_count, &trans.parameters, buffer, trans.result_count, &trans.results); result = fdc_command(&trans);
log_num(LOG_ERROR, "fdc_cmd_asm: ", result); log_num(LOG_INFO, "fdc_cmd: ", result);
} }
if ((result == 0)) { //} && ((trans.results[0] & 0xC0) == 0)) { if ((result == 0)) { //} && ((trans.results[0] & 0xC0) == 0)) {
sprintf(message, "fdc_read: success? ST0=%02X ST1=%02X ST2=%02X C=%02X H=%02X R=%02X N=%02X",
trans.results[0], trans.results[1], trans.results[2], trans.results[3], trans.results[4], trans.results[5], trans.results[6]);
log(LOG_ERROR, message);
return size; return size;
} else { } else {
sprintf(message, "fdc_read: retry ST0=%02X ST1=%02X ST2=%02X C=%02X H=%02X R=%02X N=%02X", sprintf(message, "fdc_read: retry ST0=%02X ST1=%02X ST2=%02X C=%02X H=%02X R=%02X N=%02X",
@ -1056,7 +1076,63 @@ short fdc_read(long lba, unsigned char * buffer, short size) {
* number of bytes written, any negative number is an error code * number of bytes written, any negative number is an error code
*/ */
short fdc_write(long lba, const unsigned char * buffer, short size) { short fdc_write(long lba, const unsigned char * buffer, short size) {
return 0; t_fdc_trans trans;
unsigned char head, cylinder, sector;
short result, i;
char message[80];
TRACE("fdc_read");
lba_2_chs((unsigned long)lba, &cylinder, &head, &sector);
fdc_motor_on();
trans.retries = 1; //FDC_DEFAULT_RETRIES;
trans.command = 0x40 | FDC_CMD_WRITE_DATA; /* MFM read command */
trans.direction = FDC_TRANS_WRITE; /* We're going to read from the drive */
trans.parameters[0] = (head == 1) ? 0x04 : 0x00; /* Set head and drive # */
trans.parameters[1] = cylinder & 0x00ff;
trans.parameters[2] = head & 0x0001;
trans.parameters[3] = sector & 0x00ff;
trans.parameters[4] = 2;
trans.parameters[5] = fdc_sectors_per_track;
trans.parameters[6] = 0x1B; /* GPL = 0x1B */
trans.parameters[7] = 0xFF; /* DTL = 0xFF */
trans.parameter_count = 8; /* Sending 8 parameter bytes */
trans.data = buffer; /* Transfer sector data to buffer */
trans.data_count = size;
trans.result_count = 7; /* Expect 7 result bytes */
while (trans.retries > 0) {
if (fdc_use_dma) {
result = fdc_command_dma(&trans); /* Issue the transaction */
log_num(LOG_INFO, "fdc_command_dma: ", result);
} else {
result = fdc_command(&trans);
log_num(LOG_INFO, "fdc_cmd: ", result);
}
if ((result == 0)) { //} && ((trans.results[0] & 0xC0) == 0)) {
sprintf(message, "fdc_write: success? ST0=%02X ST1=%02X ST2=%02X C=%02X H=%02X R=%02X N=%02X",
trans.results[0], trans.results[1], trans.results[2], trans.results[3], trans.results[4], trans.results[5], trans.results[6]);
log(LOG_ERROR, message);
return size;
} else {
sprintf(message, "fdc_write: retry ST0=%02X ST1=%02X ST2=%02X C=%02X H=%02X R=%02X N=%02X",
trans.results[0], trans.results[1], trans.results[2], trans.results[3], trans.results[4], trans.results[5], trans.results[6]);
log(LOG_ERROR, message);
sprintf(message, "fdc_write: retry EXTRA0=%02X EXTRA1=%02X",
trans.results[7], trans.results[8]);
log(LOG_ERROR, message);
}
fdc_init();
trans.retries--;
}
/* If we got here, we exhausted our retry attempts */
return DEV_CANNOT_WRITE;
} }
/* /*

View file

@ -71,6 +71,29 @@ void rtc_enable_ticks() {
int_enable(INT_RTC); int_enable(INT_RTC);
} }
/**
* Register a function to be called periodically
*
* @param rate the rate at which the function should be called using the bq4802LY periodic rate values (0 to disable)
* @param handler a pointer to a function from void to void to be called
* @return 0 on success, any other number is an error
*/
short rtc_register_periodic(short rate, FUNC_V_2_V handler) {
if (rate == 0) {
int_disable(INT_RTC);
*RTC_RATES = 0;
*RTC_ENABLES &= ~RTC_PIE;
} else {
int_register(INT_RTC, handler);
*RTC_RATES = rate;
unsigned char flags = *RTC_FLAGS;
*RTC_ENABLES = RTC_PIE;
int_enable(INT_RTC);
}
}
/* /*
* Set the time on the RTC * Set the time on the RTC
* *

View file

@ -5,6 +5,8 @@
#ifndef __RTC_H #ifndef __RTC_H
#define __RTC_H #define __RTC_H
#include "types.h"
typedef struct s_time { typedef struct s_time {
short year; short year;
short month; short month;
@ -54,4 +56,13 @@ extern void rtc_get_time(p_time time);
*/ */
extern long rtc_get_jiffies(); extern long rtc_get_jiffies();
/**
* Register a function to be called periodically
*
* @param rate the rate at which the function should be called using the bq4802LY periodic rate values (0 to disable)
* @param handler a pointer to a function from void to void to be called
* @return 0 on success, any other number is an error
*/
extern short rtc_register_periodic(short rate, FUNC_V_2_V handler);
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -55,7 +55,7 @@
#define RTC_RATE_976us 0x06 #define RTC_RATE_976us 0x06
#define RTC_RATE_4ms 0x08 #define RTC_RATE_4ms 0x08
#define RTC_RATE_15ms 0x0A #define RTC_RATE_15ms 0x0A
#define RTC_RATE_500ms 0x0F
/* Enable bits */ /* Enable bits */
#define RTC_AIE 0x08 #define RTC_AIE 0x08

15641
src/mapfile

File diff suppressed because it is too large Load diff

View file

@ -6,7 +6,7 @@
#define __VERSION_H #define __VERSION_H
#define VER_MAJOR 0 #define VER_MAJOR 0
#define VER_MINOR 53 #define VER_MINOR 60
#define VER_BUILD 8 #define VER_BUILD 2
#endif #endif