src/wd2010.c

Wed, 13 Mar 2013 00:43:25 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Wed, 13 Mar 2013 00:43:25 +0000
changeset 134
b826697f411a
parent 130
1fc7d607dbb4
child 135
159f937af10d
child 136
f7d78dfb45d0
permissions
-rw-r--r--

[wd2010,main] WD2010 disc geometry fixes

I believe I have fixed the geometry problem with FreeBee. The geometry was set
to 17 sectors per track instead of 16, which obviously throws off addressing.
I changed it to use 16 sectors per track. However, s4diag tries to format
sector 17, so I changed the WD2010 emulation to accept any address when
formatting (since the format command doesn't actually do anything, it doesn't
matter). It is now possible to format the hard disk, initialize the file
system, and mount it. However, cpio still fails to copy the system to the hard
disk.

Author: Andrew Warkentin <andreww591 gmail com>

philpem@112 1 #include <stdint.h>
philpem@112 2 #include <stdbool.h>
philpem@112 3 #include <malloc.h>
philpem@112 4 #include "SDL.h"
philpem@112 5 #include "musashi/m68k.h"
philpem@112 6 #include "wd2010.h"
philpem@112 7
philpem@112 8 #define WD2010_DEBUG
philpem@112 9
philpem@112 10 #ifndef WD2010_DEBUG
philpem@112 11 #define NDEBUG
philpem@112 12 #endif
philpem@112 13 #include "utils.h"
philpem@112 14
philpem@126 15 #ifndef WD2010_SEEK_DELAY
philpem@126 16 #define WD2010_SEEK_DELAY 30
philpem@126 17 #endif
philpem@112 18
philpem@112 19 #define CMD_ENABLE_RETRY 0x01
philpem@112 20 #define CMD_LONG_MODE 0x02
philpem@112 21 #define CMD_MULTI_SECTOR 0x04
philpem@112 22 #define CMD_INTRQ_WHEN_COMPLETE 0x08
philpem@112 23
philpem@112 24 #define ER_BAD_BLOCK 0x80
philpem@112 25 #define ER_CRC 0x40
philpem@112 26 #define ER_ID_NOT_FOUND 0x10
philpem@112 27 #define ER_ABORTED_COMMAND 0x04
philpem@112 28 #define ER_NO_TK0 0x02
philpem@112 29 #define ER_NO_ADDRESS_MARK 0x01
philpem@112 30
philpem@112 31 #define SR_BUSY 0x80
philpem@112 32 #define SR_READY 0x40
philpem@112 33 #define SR_WRITE_FAULT 0x20
philpem@112 34 #define SR_SEEK_COMPLETE 0x10
philpem@112 35 #define SR_DRQ 0x08
philpem@112 36 #define SR_CORRECTED 0x04
philpem@112 37 #define SR_COMMAND_IN_PROGRESS 0x02
philpem@112 38 #define SR_ERROR 0x01
philpem@112 39
philpem@112 40 extern int cpu_log_enabled;
philpem@112 41
philpem@112 42 /// WD2010 command constants
philpem@112 43 enum {
philpem@112 44 CMD_MASK = 0xF0, ///< Bit mask to detect command bits
philpem@112 45 CMD_2010_EXT = 0x00, ///< WD2010 extended commands (compute correction, set parameter)
philpem@112 46 CMD_RESTORE = 0x10, ///< Restore (recalibrate, seek to track 0)
philpem@112 47 CMD_READ_SECTOR = 0x20, ///< Read sector
philpem@112 48 CMD_WRITE_SECTOR = 0x30, ///< Write sector
philpem@112 49 CMD_SCAN_ID = 0x40, ///< Scan ID
philpem@112 50 CMD_WRITE_FORMAT = 0x50, ///< Write format
philpem@112 51 CMD_SEEK = 0x70, ///< Seek to given track
philpem@112 52 };
philpem@112 53
philpem@112 54 int wd2010_init(WD2010_CTX *ctx, FILE *fp, int secsz, int spt, int heads)
philpem@112 55 {
philpem@122 56 size_t filesize;
philpem@122 57
philpem@112 58 wd2010_reset(ctx);
philpem@122 59
philpem@112 60 // Start by finding out how big the image file is
philpem@112 61 fseek(fp, 0, SEEK_END);
philpem@112 62 filesize = ftell(fp);
philpem@112 63 fseek(fp, 0, SEEK_SET);
philpem@112 64
philpem@112 65 // Now figure out how many tracks it contains
philpem@122 66 unsigned int tracks = filesize / secsz / spt / heads;
philpem@112 67 // Confirm...
philpem@112 68 if (tracks < 1) {
philpem@112 69 return WD2010_ERR_BAD_GEOM;
philpem@112 70 }
philpem@112 71
philpem@122 72 LOG("WD2010 initialised, %d cylinders, %d heads, %d sectors per track", tracks, heads, spt);
philpem@122 73
philpem@112 74 // Allocate enough memory to store one disc track
philpem@112 75 if (ctx->data) {
philpem@112 76 free(ctx->data);
philpem@112 77 }
philpem@112 78 ctx->data = malloc(secsz * spt);
philpem@112 79 if (!ctx->data)
philpem@112 80 return WD2010_ERR_NO_MEMORY;
philpem@112 81
philpem@112 82 // Load the image and the geometry data
philpem@112 83 ctx->disc_image = fp;
philpem@112 84 ctx->geom_tracks = tracks;
philpem@112 85 ctx->geom_secsz = secsz;
philpem@112 86 ctx->geom_heads = heads;
philpem@112 87 ctx->geom_spt = spt;
philpem@122 88
philpem@112 89 return WD2010_ERR_OK;
philpem@112 90 }
philpem@112 91
philpem@112 92 void wd2010_reset(WD2010_CTX *ctx)
philpem@112 93 {
philpem@112 94 // track, head and sector unknown
philpem@112 95 ctx->track = ctx->head = ctx->sector = 0;
philpem@112 96
philpem@112 97 // no IRQ pending
philpem@112 98 ctx->irq = false;
philpem@112 99
philpem@112 100 // no data available
philpem@112 101 ctx->data_pos = ctx->data_len = 0;
philpem@112 102
philpem@112 103 // Status register clear, not busy
philpem@112 104 ctx->status = 0;
philpem@112 105
philpem@112 106 ctx->sector_count = 0;
philpem@112 107 ctx->sector_number = 0;
philpem@112 108 ctx->cylinder_low_reg = 0;
philpem@112 109 ctx->cylinder_high_reg = 0;
philpem@112 110 ctx->sdh = 0;
philpem@116 111 ctx->mcr2_hdsel3 = 0;
philpem@116 112 ctx->mcr2_ddrive1 = 0;
philpem@112 113 }
philpem@112 114
philpem@112 115 void wd2010_done(WD2010_CTX *ctx)
philpem@112 116 {
philpem@112 117 // Reset the WD2010
philpem@112 118 wd2010_reset(ctx);
philpem@112 119
philpem@112 120 // Free any allocated memory
philpem@112 121 if (ctx->data) {
philpem@112 122 free(ctx->data);
philpem@112 123 ctx->data = NULL;
philpem@112 124 }
philpem@112 125 }
philpem@112 126
philpem@112 127
philpem@112 128 bool wd2010_get_irq(WD2010_CTX *ctx)
philpem@112 129 {
philpem@112 130 return ctx->irq;
philpem@112 131 }
philpem@112 132
philpem@112 133 bool wd2010_get_drq(WD2010_CTX *ctx)
philpem@112 134 {
philpem@112 135 return (ctx->drq && ctx->data_pos < ctx->data_len);
philpem@112 136 }
philpem@112 137
philpem@112 138 void wd2010_dma_miss(WD2010_CTX *ctx)
philpem@112 139 {
philpem@112 140 ctx->data_pos = ctx->data_len;
philpem@112 141 ctx->write_pos = 0;
philpem@112 142 ctx->status = SR_READY | SR_SEEK_COMPLETE;
philpem@112 143 ctx->irq = true;
philpem@112 144 }
philpem@112 145
philpem@112 146 uint8_t wd2010_read_data(WD2010_CTX *ctx)
philpem@112 147 {
philpem@112 148 // If there's data in the buffer, return it. Otherwise return 0xFF.
philpem@112 149 if (ctx->data_pos < ctx->data_len) {
philpem@123 150 if (ctx->multi_sector && (ctx->data_pos > 0) && ((ctx->data_pos % ctx->geom_secsz) == 0)){
philpem@112 151 ctx->sector_count--;
philpem@112 152 ctx->sector_number++;
philpem@112 153 }
philpem@112 154 // set IRQ if this is the last data byte
philpem@112 155 if (ctx->data_pos == (ctx->data_len-1)) {
philpem@112 156 ctx->status = SR_READY | SR_SEEK_COMPLETE;
philpem@112 157 // Set IRQ
philpem@112 158 ctx->irq = true;
philpem@112 159 ctx->drq = false;
philpem@112 160 }
philpem@112 161 // return data byte and increment pointer
philpem@112 162 return ctx->data[ctx->data_pos++];
philpem@112 163 } else {
philpem@112 164 // empty buffer (this shouldn't happen)
philpem@115 165 LOGS("WD2010: attempt to read from empty data buffer");
philpem@112 166 return 0xff;
philpem@112 167 }
philpem@112 168 }
philpem@112 169
philpem@112 170 void wd2010_write_data(WD2010_CTX *ctx, uint8_t val)
philpem@112 171 {
philpem@112 172 // If we're processing a write command, and there's space in the
philpem@112 173 // buffer, allow the write.
philpem@112 174 if (ctx->write_pos >= 0 && ctx->data_pos < ctx->data_len) {
philpem@112 175 // store data byte and increment pointer
philpem@123 176 if (ctx->multi_sector && (ctx->data_pos > 0) && ((ctx->data_pos % ctx->geom_secsz) == 0)){
philpem@112 177 ctx->sector_count--;
philpem@112 178 ctx->sector_number++;
philpem@112 179 }
philpem@112 180 ctx->data[ctx->data_pos++] = val;
philpem@112 181 // set IRQ and write data if this is the last data byte
philpem@112 182 if (ctx->data_pos == ctx->data_len) {
philpem@112 183 if (!ctx->formatting){
philpem@112 184 fseek(ctx->disc_image, ctx->write_pos, SEEK_SET);
philpem@112 185 fwrite(ctx->data, 1, ctx->data_len, ctx->disc_image);
philpem@112 186 fflush(ctx->disc_image);
philpem@112 187 }
philpem@112 188 ctx->formatting = false;
philpem@112 189 ctx->status = SR_READY | SR_SEEK_COMPLETE;
philpem@112 190 // Set IRQ and reset write pointer
philpem@112 191 ctx->irq = true;
philpem@112 192 ctx->write_pos = -1;
philpem@112 193 ctx->drq = false;
philpem@112 194 }
philpem@112 195 }else{
philpem@115 196 LOGS("WD2010: attempt to write to data buffer without a write command in progress");
philpem@112 197 }
philpem@112 198 }
philpem@112 199
philpem@112 200 uint32_t seek_complete(uint32_t interval, WD2010_CTX *ctx)
philpem@112 201 {
philpem@112 202 /*m68k_end_timeslice();*/
philpem@112 203 ctx->status = SR_READY | SR_SEEK_COMPLETE;
philpem@112 204 ctx->irq = true;
philpem@112 205 return (0);
philpem@112 206 }
philpem@112 207
philpem@112 208 uint32_t transfer_seek_complete(uint32_t interval, WD2010_CTX *ctx)
philpem@112 209 {
philpem@112 210 /*m68k_end_timeslice();*/
philpem@112 211 ctx->drq = true;
philpem@112 212 return (0);
philpem@112 213 }
philpem@112 214
philpem@112 215 uint8_t wd2010_read_reg(WD2010_CTX *ctx, uint8_t addr)
philpem@112 216 {
philpem@112 217 uint8_t temp = 0;
philpem@112 218
philpem@112 219 /*cpu_log_enabled = 1;*/
philpem@112 220
philpem@112 221 switch (addr & 0x07) {
philpem@112 222 case WD2010_REG_ERROR:
philpem@112 223 return ctx->error_reg;
philpem@112 224 case WD2010_REG_SECTOR_COUNT:
philpem@112 225 return ctx->sector_count;
philpem@112 226 case WD2010_REG_SECTOR_NUMBER:
philpem@112 227 return ctx->sector_number;
philpem@112 228 case WD2010_REG_CYLINDER_HIGH: // High byte of cylinder
philpem@112 229 return ctx->cylinder_high_reg;
philpem@112 230 case WD2010_REG_CYLINDER_LOW: // Low byte of cylinder
philpem@112 231 return ctx->cylinder_low_reg;
philpem@112 232 case WD2010_REG_SDH:
philpem@112 233 return ctx->sdh;
philpem@112 234 case WD2010_REG_STATUS: // Status register
philpem@112 235 // Read from status register clears IRQ
philpem@112 236 ctx->irq = false;
philpem@112 237 // Get current status flags (set by last command)
philpem@112 238 // DRQ bit
philpem@112 239 if (ctx->cmd_has_drq) {
philpem@112 240 temp = ctx->status & ~(SR_BUSY & SR_DRQ);
philpem@112 241 temp |= (ctx->data_pos < ctx->data_len) ? SR_DRQ : 0;
philpem@112 242 LOG("\tWDFDC rd sr, has drq, pos=%lu len=%lu, sr=0x%02X", ctx->data_pos, ctx->data_len, temp);
philpem@112 243 } else {
philpem@112 244 temp = ctx->status & ~0x80;
philpem@112 245 }
philpem@112 246 /*XXX: where should 0x02 (command in progress) be set? should it be set here instead of 0x80 (busy)?*/
philpem@112 247 // HDC is busy if there is still data in the buffer
philpem@112 248 temp |= (ctx->data_pos < ctx->data_len) ? SR_BUSY : 0; // if data in buffer, then DMA hasn't copied it yet, and we're still busy!
philpem@112 249 // TODO: also if seek delay / read delay hasn't passed (but that's for later)
philpem@112 250 /*XXX: should anything else be set here?*/
philpem@112 251 return temp;
philpem@112 252 default:
philpem@112 253 // shut up annoying compilers which don't recognise unreachable code when they see it
philpem@112 254 // (here's looking at you, gcc!)
philpem@112 255 return 0xff;
philpem@112 256 }
philpem@112 257 }
philpem@112 258
philpem@112 259
philpem@112 260 void wd2010_write_reg(WD2010_CTX *ctx, uint8_t addr, uint8_t val)
philpem@112 261 {
philpem@112 262 uint8_t cmd = val & CMD_MASK;
philpem@112 263 size_t lba;
philpem@112 264 int new_track;
philpem@112 265 int sector_count;
philpem@112 266
philpem@112 267 m68k_end_timeslice();
philpem@112 268
philpem@112 269 /*cpu_log_enabled = 1;*/
philpem@112 270
philpem@116 271 if (addr == UNIXPC_REG_MCR2) {
philpem@116 272 // The UNIX PC has an "MCR2" register with the following format:
philpem@116 273 // [ 7..2 ][1][0]
philpem@116 274 // Bits 7..2: Not used
philpem@116 275 // Bit 1: DDRIVE1 (hard disk drive 1 select - not used?)
philpem@116 276 // Bit 0: HDSEL3 (head-select bit 3)
philpem@116 277 ctx->mcr2_hdsel3 = ((val & 1) == 1);
philpem@116 278 ctx->mcr2_ddrive1 = ((val & 2) == 2);
philpem@116 279 return;
philpem@116 280 }
philpem@116 281
philpem@112 282 switch (addr & 0x07) {
philpem@112 283 case WD2010_REG_WRITE_PRECOMP_CYLINDER:
philpem@112 284 break;
philpem@112 285 case WD2010_REG_SECTOR_COUNT:
philpem@112 286 ctx->sector_count = val;
philpem@112 287 break;
philpem@112 288 case WD2010_REG_SECTOR_NUMBER:
philpem@112 289 ctx->sector_number = val;
philpem@112 290 break;
philpem@112 291 case WD2010_REG_CYLINDER_HIGH: // High byte of cylinder
philpem@112 292 ctx->cylinder_high_reg = val;
philpem@112 293 break;
philpem@112 294 case WD2010_REG_CYLINDER_LOW: // Low byte of cylinder
philpem@112 295 ctx->cylinder_low_reg = val;
philpem@112 296 break;
philpem@112 297 case WD2010_REG_SDH:
philpem@112 298 /*XXX: remove this once the DMA page fault test passes (unless this is actually the correct behavior here)*/
philpem@130 299 //ctx->data_pos = ctx->data_len = 0;
philpem@112 300 ctx->sdh = val;
philpem@112 301 break;
philpem@112 302 case WD2010_REG_COMMAND: // Command register
philpem@112 303 // write to command register clears interrupt request
philpem@112 304 ctx->irq = false;
philpem@112 305 ctx->error_reg = 0;
philpem@112 306
philpem@112 307 /*cpu_log_enabled = 1;*/
philpem@112 308 switch (cmd) {
philpem@112 309 case CMD_RESTORE:
philpem@112 310 // Restore. Set track to 0 and throw an IRQ.
philpem@112 311 ctx->track = 0;
philpem@126 312 SDL_AddTimer(WD2010_SEEK_DELAY, (SDL_NewTimerCallback)seek_complete, ctx);
philpem@112 313 break;
philpem@112 314 case CMD_SCAN_ID:
philpem@112 315 ctx->cylinder_high_reg = (ctx->track >> 8) & 0xff;
philpem@112 316 ctx->cylinder_low_reg = ctx->track & 0xff;
philpem@112 317 ctx->sector_number = ctx->sector;
philpem@112 318 ctx->sdh = (ctx->sdh & ~7) | (ctx->head & 7);
philpem@112 319 case CMD_WRITE_FORMAT:
philpem@112 320 case CMD_SEEK:
philpem@112 321 case CMD_READ_SECTOR:
philpem@112 322 case CMD_WRITE_SECTOR:
philpem@112 323 // Seek. Seek to the track specced in the cylinder
philpem@112 324 // registers.
philpem@112 325 new_track = (ctx->cylinder_high_reg << 8) | ctx->cylinder_low_reg;
philpem@112 326 if (new_track < ctx->geom_tracks) {
philpem@112 327 ctx->track = new_track;
philpem@112 328 } else {
philpem@112 329 // Seek error. :(
philpem@134 330 LOG("WD2010 ALERT: track %d out of range", new_track);
philpem@112 331 ctx->status = SR_ERROR;
philpem@112 332 ctx->error_reg = ER_ID_NOT_FOUND;
philpem@112 333 ctx->irq = true;
philpem@112 334 break;
philpem@112 335 }
philpem@116 336 // The SDH register provides 3 head select bits; the 4th comes from MCR2.
philpem@116 337 ctx->head = (ctx->sdh & 0x07) + (ctx->mcr2_hdsel3 ? 8 : 0);
philpem@112 338 ctx->sector = ctx->sector_number;
philpem@112 339
philpem@112 340 ctx->formatting = cmd == CMD_WRITE_FORMAT;
philpem@112 341 switch (cmd){
philpem@112 342 case CMD_SEEK:
philpem@126 343 SDL_AddTimer(WD2010_SEEK_DELAY, (SDL_NewTimerCallback)seek_complete, ctx);
philpem@112 344 break;
philpem@112 345 case CMD_READ_SECTOR:
philpem@112 346 /*XXX: does a separate function to set the head have to be added?*/
philpem@124 347 LOG("WD2010: READ SECTOR cmd=%02X chs=%d:%d:%d nsectors=%d", cmd, ctx->track, ctx->head, ctx->sector, ctx->sector_count);
philpem@112 348
philpem@112 349 // Read Sector
philpem@112 350
philpem@112 351 // Check to see if the cyl, hd and sec are valid
philpem@125 352 if ((ctx->track > (ctx->geom_tracks-1)) || (ctx->head > (ctx->geom_heads-1)) || ((ctx->sector + ctx->sector_count - 1) > ctx->geom_spt-1)) {
philpem@125 353 LOG("*** WD2010 ALERT: CHS parameter limit exceeded! CHS=%d:%d:%d, nSecs=%d, endSec=%d maxCHS=%d:%d:%d",
philpem@112 354 ctx->track, ctx->head, ctx->sector,
philpem@125 355 ctx->sector_count,
philpem@125 356 ctx->sector + ctx->sector_count - 1,
philpem@125 357 ctx->geom_tracks-1, ctx->geom_heads-1, ctx->geom_spt);
philpem@112 358 // CHS parameters exceed limits
philpem@112 359 ctx->status = SR_ERROR;
philpem@112 360 ctx->error_reg = ER_ID_NOT_FOUND;
philpem@112 361 // Set IRQ
philpem@112 362 ctx->irq = true;
philpem@112 363 break;
philpem@112 364 }
philpem@112 365
philpem@112 366 // reset data pointers
philpem@112 367 ctx->data_pos = ctx->data_len = 0;
philpem@112 368
philpem@112 369 if (val & CMD_MULTI_SECTOR){
philpem@112 370 ctx->multi_sector = 1;
philpem@112 371 sector_count = ctx->sector_count;
philpem@112 372 }else{
philpem@112 373 ctx->multi_sector = 0;
philpem@112 374 sector_count = 1;
philpem@112 375 }
philpem@112 376 for (int i=0; i<sector_count; i++) {
philpem@112 377 // Calculate the LBA address of the required sector
philpem@112 378 // LBA = (C * nHeads * nSectors) + (H * nSectors) + S - 1
philpem@112 379 lba = (((ctx->track * ctx->geom_heads * ctx->geom_spt) + (ctx->head * ctx->geom_spt) + ctx->sector) + i);
philpem@112 380 // convert LBA to byte address
philpem@112 381 lba *= ctx->geom_secsz;
philpem@112 382 LOG("\tREAD lba = %lu", lba);
philpem@112 383
philpem@112 384 // Read the sector from the file
philpem@112 385 fseek(ctx->disc_image, lba, SEEK_SET);
philpem@112 386 // TODO: check fread return value! if < secsz, BAIL! (call it a crc error or secnotfound maybe? also log to stderr)
philpem@112 387 ctx->data_len += fread(&ctx->data[ctx->data_len], 1, ctx->geom_secsz, ctx->disc_image);
philpem@112 388 LOG("\tREAD len=%lu, pos=%lu, ssz=%d", ctx->data_len, ctx->data_pos, ctx->geom_secsz);
philpem@112 389 }
philpem@112 390
philpem@112 391 ctx->status = 0;
philpem@112 392 ctx->status |= (ctx->data_pos < ctx->data_len) ? SR_DRQ | SR_COMMAND_IN_PROGRESS | SR_BUSY : 0x00;
philpem@126 393 SDL_AddTimer(WD2010_SEEK_DELAY, (SDL_NewTimerCallback)transfer_seek_complete, ctx);
philpem@112 394
philpem@112 395 break;
philpem@112 396 case CMD_WRITE_FORMAT:
philpem@112 397 ctx->sector = 0;
philpem@112 398 case CMD_WRITE_SECTOR:
philpem@124 399 LOG("WD2010: WRITE SECTOR cmd=%02X chs=%d:%d:%d nsectors=%d", cmd, ctx->track, ctx->head, ctx->sector, ctx->sector_count);
philpem@124 400 // Write Sector
philpem@112 401
philpem@112 402 // Check to see if the cyl, hd and sec are valid
philpem@134 403 if (cmd != CMD_WRITE_FORMAT && ((ctx->track > (ctx->geom_tracks-1)) || (ctx->head > (ctx->geom_heads-1)) || ((ctx->sector + ctx->sector_count - 1) > ctx->geom_spt-1))) {
philpem@125 404 LOG("*** WD2010 ALERT: CHS parameter limit exceeded! CHS=%d:%d:%d, nSecs=%d, endSec=%d maxCHS=%d:%d:%d",
philpem@112 405 ctx->track, ctx->head, ctx->sector,
philpem@125 406 ctx->sector_count,
philpem@125 407 ctx->sector + ctx->sector_count - 1,
philpem@112 408 ctx->geom_tracks-1, ctx->geom_heads-1, ctx->geom_spt);
philpem@112 409 // CHS parameters exceed limits
philpem@112 410 ctx->status = SR_ERROR;
philpem@112 411 ctx->error_reg = ER_ID_NOT_FOUND;
philpem@112 412 // Set IRQ
philpem@112 413 ctx->irq = true;
philpem@112 414 break;
philpem@112 415 }
philpem@112 416
philpem@112 417 // reset data pointers
philpem@112 418 ctx->data_pos = ctx->data_len = 0;
philpem@112 419
philpem@112 420 if (val & CMD_MULTI_SECTOR){
philpem@112 421 ctx->multi_sector = 1;
philpem@112 422 sector_count = ctx->sector_count;
philpem@112 423 }else{
philpem@112 424 ctx->multi_sector = 0;
philpem@112 425 sector_count = 1;
philpem@112 426 }
philpem@112 427 ctx->data_len = ctx->geom_secsz * sector_count;
philpem@112 428 lba = (((ctx->track * ctx->geom_heads * ctx->geom_spt) + (ctx->head * ctx->geom_spt) + ctx->sector));
philpem@112 429 // convert LBA to byte address
philpem@124 430 ctx->write_pos = (lba *= ctx->geom_secsz);
philpem@124 431 LOG("\tWRITE lba = %zu", lba);
philpem@112 432
philpem@112 433 ctx->status = 0;
philpem@112 434 ctx->status |= (ctx->data_pos < ctx->data_len) ? SR_DRQ | SR_COMMAND_IN_PROGRESS | SR_BUSY : 0x00;
philpem@126 435 SDL_AddTimer(WD2010_SEEK_DELAY, (SDL_NewTimerCallback)transfer_seek_complete, ctx);
philpem@112 436
philpem@112 437 break;
philpem@112 438 default:
philpem@112 439 LOG("WD2010: invalid seeking command %x (this shouldn't happen!)\n", cmd);
philpem@112 440 break;
philpem@112 441 }
philpem@112 442 break;
philpem@112 443 case CMD_2010_EXT: /* not implemented */
philpem@112 444 default:
philpem@112 445 LOG("WD2010: unknown command %x\n", cmd);
philpem@112 446 ctx->status = SR_ERROR;
philpem@112 447 ctx->error_reg = ER_ABORTED_COMMAND;
philpem@112 448 ctx->irq = true;
philpem@112 449 break;
philpem@112 450 }
philpem@112 451 break;
philpem@112 452
philpem@112 453 }
philpem@112 454 }
philpem@112 455