src/wd279x.c

Mon, 06 Dec 2010 01:43:04 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Mon, 06 Dec 2010 01:43:04 +0000
changeset 54
57c6ef81ae81
parent 53
e1693c4b8a0c
child 57
feb84193a43a
child 76
2ef98ea1e944
permissions
-rw-r--r--

fix side-select bug in WDC FDC driver, was causing all reads to occur on side0... now the Loader boots!

Loader will boot, but immediately gives up on the floppy drive... Not sure why.

philpem@48 1 #include <stdint.h>
philpem@48 2 #include <stdbool.h>
philpem@49 3 #include <malloc.h>
philpem@53 4 #include "musashi/m68k.h"
philpem@48 5 #include "wd279x.h"
philpem@48 6
philpem@48 7 /// WD2797 command constants
philpem@48 8 enum {
philpem@48 9 CMD_MASK = 0xF0, ///< Bit mask to detect command bits
philpem@48 10 CMD_RESTORE = 0x00, ///< Restore (recalibrate, seek to track 0)
philpem@48 11 CMD_SEEK = 0x10, ///< Seek to given track
philpem@48 12 CMD_STEP = 0x20, ///< Step
philpem@48 13 CMD_STEP_TU = 0x30, ///< Step and update track register
philpem@48 14 CMD_STEPIN = 0x40, ///< Step In
philpem@48 15 CMD_STEPIN_TU = 0x50, ///< Step In and update track register
philpem@48 16 CMD_STEPOUT = 0x60, ///< Step Out
philpem@48 17 CMD_STEPOUT_TU = 0x70, ///< Step Out and update track register
philpem@48 18 CMD_READ_SECTOR = 0x80, ///< Read Sector
philpem@48 19 CMD_READ_SECTOR_MULTI = 0x90, ///< Read Multiple Sectors
philpem@48 20 CMD_WRITE_SECTOR = 0xA0, ///< Write Sector
philpem@48 21 CMD_WRITE_SECTOR_MULTI = 0xB0, ///< Write Multiple Sectors
philpem@48 22 CMD_READ_ADDRESS = 0xC0, ///< Read Address (IDAM contents)
philpem@48 23 CMD_FORCE_INTERRUPT = 0xD0, ///< Force Interrupt
philpem@48 24 CMD_READ_TRACK = 0xE0, ///< Read Track
philpem@48 25 CMD_FORMAT_TRACK = 0xF0 ///< Format Track
philpem@48 26 };
philpem@48 27
philpem@48 28
philpem@49 29 void wd2797_init(WD2797_CTX *ctx)
philpem@48 30 {
philpem@48 31 // track, head and sector unknown
philpem@49 32 ctx->track = ctx->head = ctx->sector = 0;
philpem@48 33
philpem@49 34 // no IRQ pending
philpem@49 35 ctx->irql = ctx->irqe = false;
philpem@48 36
philpem@48 37 // no data available
philpem@49 38 ctx->data_pos = ctx->data_len = 0;
philpem@49 39 ctx->data = NULL;
philpem@49 40
philpem@49 41 // Status register clear, not busy
philpem@49 42 ctx->status = 0;
philpem@49 43
philpem@49 44 // Clear data register
philpem@49 45 ctx->data_reg = 0;
philpem@49 46
philpem@49 47 // Last step direction
philpem@49 48 ctx->last_step_dir = -1;
philpem@48 49
philpem@48 50 // No disc image loaded
philpem@48 51 ctx->disc_image = NULL;
philpem@49 52 ctx->geom_secsz = ctx->geom_spt = ctx->geom_heads = ctx->geom_tracks = 0;
philpem@48 53 }
philpem@48 54
philpem@48 55
philpem@49 56 void wd2797_reset(WD2797_CTX *ctx)
philpem@49 57 {
philpem@49 58 // track, head and sector unknown
philpem@49 59 ctx->track = ctx->head = ctx->sector = 0;
philpem@49 60
philpem@49 61 // no IRQ pending
philpem@49 62 ctx->irql = ctx->irqe = false;
philpem@49 63
philpem@49 64 // no data available
philpem@49 65 ctx->data_pos = ctx->data_len = 0;
philpem@49 66
philpem@49 67 // Status register clear, not busy
philpem@49 68 ctx->status = 0;
philpem@49 69
philpem@49 70 // Clear data register
philpem@49 71 ctx->data_reg = 0;
philpem@49 72
philpem@49 73 // Last step direction
philpem@49 74 ctx->last_step_dir = -1;
philpem@49 75 }
philpem@49 76
philpem@49 77
philpem@49 78 void wd2797_done(WD2797_CTX *ctx)
philpem@49 79 {
philpem@49 80 // Reset the WD2797
philpem@49 81 wd2797_reset(ctx);
philpem@49 82
philpem@49 83 // Free any allocated memory
philpem@49 84 if (ctx->data) {
philpem@49 85 free(ctx->data);
philpem@49 86 ctx->data = NULL;
philpem@49 87 }
philpem@49 88 }
philpem@49 89
philpem@49 90
philpem@49 91 bool wd2797_get_irq(WD2797_CTX *ctx)
philpem@48 92 {
philpem@48 93 // If an IRQ is pending, clear it and return true, otherwise return false
philpem@48 94 if (ctx->irqe) {
philpem@48 95 ctx->irqe = false;
philpem@48 96 return true;
philpem@48 97 } else {
philpem@48 98 return false;
philpem@48 99 }
philpem@48 100 }
philpem@48 101
philpem@48 102
philpem@49 103 bool wd2797_get_drq(WD2797_CTX *ctx)
philpem@48 104 {
philpem@48 105 return (ctx->data_pos < ctx->data_len);
philpem@48 106 }
philpem@48 107
philpem@48 108
philpem@49 109 WD2797_ERR wd2797_load(WD2797_CTX *ctx, FILE *fp, int secsz, int spt, int heads)
philpem@49 110 {
philpem@49 111 size_t filesize;
philpem@49 112
philpem@49 113 // Start by finding out how big the image file is
philpem@49 114 fseek(fp, 0, SEEK_END);
philpem@49 115 filesize = ftell(fp);
philpem@49 116 fseek(fp, 0, SEEK_SET);
philpem@49 117
philpem@49 118 // Now figure out how many tracks it contains
philpem@49 119 int tracks = filesize / secsz / spt / heads;
philpem@49 120 // Confirm...
philpem@49 121 if (tracks < 1) {
philpem@49 122 return WD2797_ERR_BAD_GEOM;
philpem@49 123 }
philpem@49 124
philpem@49 125 // Allocate enough memory to store one disc track
philpem@49 126 if (ctx->data) {
philpem@49 127 free(ctx->data);
philpem@49 128 }
philpem@49 129 ctx->data = malloc(secsz * spt);
philpem@49 130 if (!ctx->data)
philpem@49 131 return WD2797_ERR_NO_MEMORY;
philpem@49 132
philpem@49 133 // Load the image and the geometry data
philpem@49 134 ctx->disc_image = fp;
philpem@49 135 ctx->geom_tracks = tracks;
philpem@49 136 ctx->geom_secsz = secsz;
philpem@49 137 ctx->geom_heads = heads;
philpem@49 138 ctx->geom_spt = spt;
philpem@49 139
philpem@49 140 return WD2797_ERR_OK;
philpem@49 141 }
philpem@49 142
philpem@49 143
philpem@49 144 void wd2797_unload(WD2797_CTX *ctx)
philpem@49 145 {
philpem@49 146 // Free memory buffer
philpem@49 147 if (ctx->data) {
philpem@49 148 free(ctx->data);
philpem@49 149 ctx->data = NULL;
philpem@49 150 }
philpem@49 151
philpem@49 152 // Clear file pointer
philpem@49 153 ctx->disc_image = NULL;
philpem@49 154
philpem@49 155 // Clear the disc geometry
philpem@49 156 ctx->geom_tracks = ctx->geom_secsz = ctx->geom_spt = ctx->geom_heads = 0;
philpem@49 157 }
philpem@49 158
philpem@49 159
philpem@49 160 uint8_t wd2797_read_reg(WD2797_CTX *ctx, uint8_t addr)
philpem@48 161 {
philpem@48 162 uint8_t temp = 0;
philpem@48 163
philpem@48 164 switch (addr & 0x03) {
philpem@49 165 case WD2797_REG_STATUS: // Status register
philpem@48 166 // Read from status register clears IRQ
philpem@48 167 ctx->irql = false;
philpem@53 168 ctx->irqe = false;
philpem@48 169
philpem@48 170 // Get current status flags (set by last command)
philpem@48 171 // DRQ bit
philpem@53 172 if (ctx->cmd_has_drq) {
philpem@53 173 printf("\tWDFDC rd sr, has drq, pos=%lu len=%lu\n", ctx->data_pos, ctx->data_len);
philpem@53 174 temp = ctx->status & ~0x03;
philpem@48 175 temp |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00;
philpem@53 176 } else {
philpem@53 177 temp = ctx->status & ~0x01;
philpem@53 178 }
philpem@48 179 // FDC is busy if there is still data in the buffer
philpem@48 180 temp |= (ctx->data_pos < ctx->data_len) ? 0x01 : 0x00; // if data in buffer, then DMA hasn't copied it yet, and we're still busy!
philpem@49 181 // TODO: also if seek delay / read delay hasn't passed (but that's for later)
philpem@48 182 return temp;
philpem@48 183
philpem@49 184 case WD2797_REG_TRACK: // Track register
philpem@48 185 return ctx->track;
philpem@48 186
philpem@49 187 case WD2797_REG_SECTOR: // Sector register
philpem@48 188 return ctx->sector;
philpem@48 189
philpem@49 190 case WD2797_REG_DATA: // Data register
philpem@48 191 // If there's data in the buffer, return it. Otherwise return 0xFF.
philpem@48 192 if (ctx->data_pos < ctx->data_len) {
philpem@53 193 // set IRQ if this is the last data byte
philpem@53 194 if (ctx->data_pos == (ctx->data_len-1)) {
philpem@53 195 // Set IRQ only if IRQL has been cleared (no pending IRQs)
philpem@53 196 ctx->irqe = ctx->irql ? ctx->irqe : true;
philpem@53 197 ctx->irql = true;
philpem@53 198 }
philpem@48 199 // return data byte and increment pointer
philpem@48 200 return ctx->data[ctx->data_pos++];
philpem@48 201 } else {
philpem@53 202 // command finished
philpem@48 203 return 0xff;
philpem@48 204 }
philpem@48 205
philpem@48 206 default:
philpem@48 207 // shut up annoying compilers which don't recognise unreachable code when they see it
philpem@48 208 // (here's looking at you, gcc!)
philpem@48 209 return 0xff;
philpem@48 210 }
philpem@48 211 }
philpem@48 212
philpem@48 213
philpem@49 214 void wd2797_write_reg(WD2797_CTX *ctx, uint8_t addr, uint8_t val)
philpem@48 215 {
philpem@48 216 uint8_t cmd = val & CMD_MASK;
philpem@48 217 size_t lba;
philpem@48 218 bool is_type1 = false;
philpem@49 219 int temp;
philpem@48 220
philpem@53 221 m68k_end_timeslice();
philpem@53 222
philpem@48 223 switch (addr) {
philpem@49 224 case WD2797_REG_COMMAND: // Command register
philpem@48 225 // write to command register clears interrupt request
philpem@48 226 ctx->irql = false;
philpem@48 227
philpem@48 228 // Is the drive ready?
philpem@48 229 if (ctx->disc_image == NULL) {
philpem@48 230 // No disc image, thus the drive is busy.
philpem@48 231 ctx->status = 0x80;
philpem@48 232 return;
philpem@48 233 }
philpem@48 234
philpem@48 235 // Handle Type 1 commands
philpem@48 236 switch (cmd) {
philpem@48 237 case CMD_RESTORE:
philpem@48 238 // Restore. Set track to 0 and throw an IRQ.
philpem@48 239 is_type1 = true;
philpem@48 240 ctx->track = 0;
philpem@48 241 break;
philpem@48 242
philpem@48 243 case CMD_SEEK:
philpem@48 244 // Seek. Seek to the track specced in the Data Register.
philpem@48 245 is_type1 = true;
philpem@48 246 if (ctx->data_reg < ctx->geom_tracks) {
philpem@48 247 ctx->track = ctx->data_reg;
philpem@48 248 } else {
philpem@48 249 // Seek error. :(
philpem@48 250 ctx->status = 0x10;
philpem@48 251 }
philpem@48 252
philpem@48 253 case CMD_STEP:
philpem@48 254 // TODO! deal with trk0!
philpem@48 255 // Need to keep a copy of the track register; when it hits 0, set the TRK0 flag.
philpem@48 256 is_type1 = true;
philpem@48 257 break;
philpem@48 258
philpem@48 259 case CMD_STEPIN:
philpem@48 260 case CMD_STEPOUT:
philpem@48 261 // TODO! deal with trk0!
philpem@48 262 // Need to keep a copy of the track register; when it hits 0, set the TRK0 flag.
philpem@48 263 if (cmd == CMD_STEPIN) {
philpem@48 264 ctx->last_step_dir = 1;
philpem@48 265 } else {
philpem@48 266 ctx->last_step_dir = -1;
philpem@48 267 }
philpem@48 268 is_type1 = true;
philpem@48 269 break;
philpem@48 270
philpem@48 271 case CMD_STEP_TU:
philpem@48 272 case CMD_STEPIN_TU:
philpem@48 273 case CMD_STEPOUT_TU:
philpem@48 274 // if this is a Step In or Step Out cmd, set the step-direction
philpem@48 275 if (cmd == CMD_STEPIN_TU) {
philpem@48 276 ctx->last_step_dir = 1;
philpem@48 277 } else if (cmd == CMD_STEPOUT_TU) {
philpem@48 278 ctx->last_step_dir = -1;
philpem@48 279 }
philpem@48 280
philpem@48 281 // Seek one step in the last direction used.
philpem@48 282 ctx->track += ctx->last_step_dir;
philpem@48 283 if (ctx->track < 0) ctx->track = 0;
philpem@48 284 if (ctx->track >= ctx->geom_tracks) {
philpem@48 285 // Seek past end of disc... that'll be a Seek Error then.
philpem@48 286 ctx->status = 0x10;
philpem@48 287 ctx->track = ctx->geom_tracks - 1;
philpem@48 288 }
philpem@48 289 is_type1 = true;
philpem@48 290 break;
philpem@48 291
philpem@48 292 default:
philpem@48 293 break;
philpem@48 294 }
philpem@48 295
philpem@48 296 if (is_type1) {
philpem@48 297 // Terminate any sector reads or writes
philpem@48 298 ctx->data_len = ctx->data_pos = 0;
philpem@48 299
philpem@48 300 // No DRQ bit for these commands.
philpem@48 301 ctx->cmd_has_drq = false;
philpem@48 302
philpem@48 303 // Type1 status byte...
philpem@48 304 ctx->status = 0;
philpem@48 305 // S7 = Not Ready. Command executed, therefore the drive was ready... :)
philpem@48 306 // S6 = Write Protect. TODO: add this
philpem@48 307 // S5 = Head Loaded. For certain emulation-related reasons, the heads are always loaded...
philpem@48 308 ctx->status |= 0x20;
philpem@48 309 // S4 = Seek Error. Not bloody likely if we got down here...!
philpem@48 310 // S3 = CRC Error. Not gonna happen on a disc image!
philpem@48 311 // S2 = Track 0
philpem@48 312 ctx->status |= (ctx->track == 0) ? 0x04 : 0x00;
philpem@48 313 // S1 = Index Pulse. TODO -- need periodics to emulate this
philpem@48 314 // S0 = Busy. We just exec'd the command, thus we're not busy.
philpem@48 315 // TODO: Set a timer for seeks, and ONLY clear BUSY when that timer expires. Need periodics for that.
philpem@48 316
philpem@48 317 // Set IRQ only if IRQL has been cleared (no pending IRQs)
philpem@53 318 ctx->irqe = ctx->irql ? ctx->irqe : true;
philpem@48 319 ctx->irql = true;
philpem@48 320 return;
philpem@48 321 }
philpem@48 322
philpem@48 323 // That's the Type 1 (seek) commands sorted. Now for the others.
philpem@48 324
philpem@53 325 // All these commands return the DRQ bit...
philpem@53 326 ctx->cmd_has_drq = true;
philpem@53 327
philpem@48 328 // If drive isn't ready, then set status B7 and exit
philpem@48 329 if (ctx->disc_image == NULL) {
philpem@48 330 ctx->status = 0x80;
philpem@48 331 return;
philpem@48 332 }
philpem@48 333
philpem@48 334 // If this is a Write command, check write protect status too
philpem@48 335 // TODO!
philpem@48 336 if (false) {
philpem@48 337 // Write protected disc...
philpem@48 338 if ((cmd == CMD_WRITE_SECTOR) || (cmd == CMD_WRITE_SECTOR_MULTI) || (cmd == CMD_FORMAT_TRACK)) {
philpem@48 339 // Set Write Protect bit and bail.
philpem@48 340 ctx->status = 0x40;
philpem@48 341
philpem@48 342 // Set IRQ only if IRQL has been cleared (no pending IRQs)
philpem@53 343 ctx->irqe = ctx->irql ? ctx->irqe : true;
philpem@48 344 ctx->irql = true;
philpem@48 345
philpem@48 346 return;
philpem@48 347 }
philpem@48 348 }
philpem@48 349
philpem@48 350 // Disc is ready to go. Parse the command word.
philpem@48 351 switch (cmd) {
philpem@48 352 case CMD_READ_ADDRESS:
philpem@48 353 // Read Address
philpem@54 354 ctx->head = (val & 0x02) ? 1 : 0;
philpem@48 355
philpem@48 356 // reset data pointers
philpem@48 357 ctx->data_pos = ctx->data_len = 0;
philpem@48 358
philpem@48 359 // load data buffer
philpem@48 360 ctx->data[ctx->data_len++] = ctx->track;
philpem@48 361 ctx->data[ctx->data_len++] = ctx->head;
philpem@48 362 ctx->data[ctx->data_len++] = ctx->sector;
philpem@48 363 switch (ctx->geom_secsz) {
philpem@48 364 case 128: ctx->data[ctx->data_len++] = 0; break;
philpem@48 365 case 256: ctx->data[ctx->data_len++] = 1; break;
philpem@48 366 case 512: ctx->data[ctx->data_len++] = 2; break;
philpem@48 367 case 1024: ctx->data[ctx->data_len++] = 3; break;
philpem@48 368 default: ctx->data[ctx->data_len++] = 0xFF; break; // TODO: deal with invalid values better
philpem@48 369 }
philpem@48 370 ctx->data[ctx->data_len++] = 0; // TODO: IDAM CRC!
philpem@48 371 ctx->data[ctx->data_len++] = 0;
philpem@48 372
philpem@53 373 ctx->status = 0;
philpem@48 374 // B6, B5 = 0
philpem@48 375 // B4 = Record Not Found. We're not going to see this... FIXME-not emulated
philpem@48 376 // B3 = CRC Error. Not possible.
philpem@48 377 // B2 = Lost Data. Caused if DRQ isn't serviced in time. FIXME-not emulated
philpem@48 378 // B1 = DRQ. Data request.
philpem@48 379 ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00;
philpem@48 380 break;
philpem@48 381
philpem@48 382 case CMD_READ_SECTOR:
philpem@48 383 case CMD_READ_SECTOR_MULTI:
philpem@54 384 ctx->head = (val & 0x02) ? 1 : 0;
philpem@54 385 printf("WD279X: READ SECTOR cmd=%02X chs=%d:%d:%d\n", cmd, ctx->track, ctx->head, ctx->sector);
philpem@48 386 // Read Sector or Read Sector Multiple
philpem@48 387 // reset data pointers
philpem@48 388 ctx->data_pos = ctx->data_len = 0;
philpem@48 389
philpem@49 390 // Calculate number of sectors to read from disc
philpem@49 391 if (cmd == CMD_READ_SECTOR_MULTI)
philpem@49 392 temp = ctx->geom_spt;
philpem@49 393 else
philpem@49 394 temp = 1;
philpem@48 395
philpem@49 396 for (int i=0; i<temp; i++) {
philpem@49 397 // Calculate the LBA address of the required sector
philpem@51 398 lba = ((((ctx->track * ctx->geom_heads) + ctx->head) * ctx->geom_spt) + ((ctx->sector + i - 1) % ctx->geom_spt)) * ctx->geom_secsz;
philpem@53 399 printf("\tREAD lba = %lu\n", lba);
philpem@49 400
philpem@49 401 // Read the sector from the file
philpem@49 402 fseek(ctx->disc_image, lba, SEEK_SET);
philpem@49 403 ctx->data_len += fread(&ctx->data[ctx->data_len], 1, ctx->geom_secsz, ctx->disc_image);
philpem@53 404 printf("\tREAD len=%lu, pos=%lu, ssz=%d\n", ctx->data_len, ctx->data_pos, ctx->geom_secsz);
philpem@49 405 // TODO: check fread return value! if < secsz, BAIL! (call it a crc error or secnotfound maybe? also log to stderr)
philpem@49 406 }
philpem@48 407
philpem@53 408 ctx->status = 0;
philpem@48 409 // B6 = 0
philpem@48 410 // B5 = Record Type -- 1 = deleted, 0 = normal. We can't emulate anything but normal data blocks.
philpem@48 411 // B4 = Record Not Found. We're not going to see this... FIXME-not emulated
philpem@48 412 // B3 = CRC Error. Not possible.
philpem@48 413 // B2 = Lost Data. Caused if DRQ isn't serviced in time. FIXME-not emulated
philpem@48 414 // B1 = DRQ. Data request.
philpem@48 415 ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00;
philpem@48 416 break;
philpem@48 417
philpem@48 418 case CMD_READ_TRACK:
philpem@48 419 // Read Track
philpem@49 420 // TODO! implement this
philpem@54 421 ctx->head = (val & 0x02) ? 1 : 0;
philpem@53 422 ctx->status = 0;
philpem@48 423 // B6, B5, B4, B3 = 0
philpem@48 424 // B2 = Lost Data. Caused if DRQ isn't serviced in time. FIXME-not emulated
philpem@48 425 // B1 = DRQ. Data request.
philpem@48 426 ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00;
philpem@48 427 break;
philpem@48 428
philpem@48 429 case CMD_WRITE_SECTOR:
philpem@48 430 case CMD_WRITE_SECTOR_MULTI:
philpem@48 431 // Write Sector or Write Sector Multiple
philpem@48 432
philpem@54 433 ctx->head = (val & 0x02) ? 1 : 0;
philpem@48 434 // reset data pointers
philpem@48 435 ctx->data_pos = ctx->data_len = 0;
philpem@48 436
philpem@48 437 // TODO: set "write pending" flag, and write LBA, and go from there.
philpem@48 438
philpem@53 439 ctx->status = 0;
philpem@48 440 // B6 = Write Protect. FIXME -- emulate this!
philpem@48 441 // B5 = 0
philpem@48 442 // B4 = Record Not Found. We're not going to see this... FIXME-not emulated
philpem@48 443 // B3 = CRC Error. Not possible.
philpem@48 444 // B2 = Lost Data. Caused if DRQ isn't serviced in time. FIXME-not emulated
philpem@48 445 // B1 = DRQ. Data request.
philpem@48 446 ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00;
philpem@48 447 break;
philpem@48 448
philpem@48 449 case CMD_FORMAT_TRACK:
philpem@48 450 // Write Track (aka Format Track)
philpem@54 451 ctx->head = (val & 0x02) ? 1 : 0;
philpem@53 452 ctx->status = 0;
philpem@48 453 // B6 = Write Protect. FIXME -- emulate this!
philpem@48 454 // B5, B4, B3 = 0
philpem@48 455 // B2 = Lost Data. Caused if DRQ isn't serviced in time. FIXME-not emulated
philpem@48 456 // B1 = DRQ. Data request.
philpem@48 457 ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00;
philpem@48 458 break;
philpem@48 459
philpem@48 460 case CMD_FORCE_INTERRUPT:
philpem@48 461 // Force Interrupt...
philpem@49 462 // Terminates current operation and sends an interrupt
philpem@49 463 // TODO!
philpem@53 464 ctx->status = 0;
philpem@49 465 ctx->data_pos = ctx->data_len = 0;
philpem@49 466 // Set IRQ only if IRQL has been cleared (no pending IRQs)
philpem@53 467 ctx->irqe = ctx->irql ? ctx->irqe : true;
philpem@49 468 ctx->irql = true;
philpem@48 469 break;
philpem@48 470 }
philpem@48 471 break;
philpem@48 472
philpem@49 473 case WD2797_REG_TRACK: // Track register
philpem@48 474 ctx->track = val;
philpem@48 475 break;
philpem@48 476
philpem@49 477 case WD2797_REG_SECTOR: // Sector register
philpem@48 478 ctx->sector = val;
philpem@48 479 break;
philpem@48 480
philpem@49 481 case WD2797_REG_DATA: // Data register
philpem@48 482 // Save the value written into the data register
philpem@48 483 ctx->data_reg = val;
philpem@48 484
philpem@48 485 // If we're processing a write command, and there's space in the
philpem@48 486 // buffer, allow the write.
philpem@48 487 if (ctx->data_pos < ctx->data_len) {
philpem@53 488 // set IRQ if this is the last data byte
philpem@53 489 if (ctx->data_pos == (ctx->data_len-1)) {
philpem@53 490 // Set IRQ only if IRQL has been cleared (no pending IRQs)
philpem@53 491 ctx->irqe = ctx->irql ? ctx->irqe : true;
philpem@53 492 ctx->irql = true;
philpem@53 493 }
philpem@53 494
philpem@48 495 // store data byte and increment pointer
philpem@48 496 ctx->data[ctx->data_pos++] = val;
philpem@48 497 }
philpem@48 498 break;
philpem@48 499 }
philpem@48 500 }
philpem@48 501