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