1/* 2 * Copyright 2003-2008, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Fran��ois Revol <revol@free.fr> 7 */ 8 9 10#include <Drivers.h> 11#include "floppy.h" 12 13 14/* VERY verbose... */ 15//#define DEBUG_LOWLEVEL 16 17#if defined(DEBUG) && DEBUG > 0 18# define PRINT_SR0(x) print_sr0(x) 19#else 20# define PRINT_SR0(x) ; 21#endif 22 23 24#if defined(DEBUG) && DEBUG > 0 25static void 26print_sr0(uint8 sr0) 27{ 28 const char *result = "ok"; 29 switch (sr0 & FDC_SR0_IC) { 30 case 0x80: 31 result = "invalid"; 32 break; 33 case 0x40: 34 result = "abterm"; 35 break; 36 case 0xc0: 37 result = "drvchngd"; 38 break; 39 } 40 41 TRACE("sr0: ds %d, hs %d, ec %d, se %d, %s\n", (sr0 & FDC_SR0_DS), !!(sr0 & FDC_SR0_HS), !!(sr0 & FDC_SR0_EC), !!(sr0 & FDC_SR0_SE), result); 42} 43#endif 44 45 46void 47write_reg(floppy_t *flp, floppy_reg_selector selector, uint8 data) 48{ 49#ifdef DEBUG_LOWLEVEL 50 TRACE("write to 0x%lx, data 0x%x\n", flp->iobase + selector, data); 51#endif 52 flp->isa->write_io_8(flp->iobase + selector, data); 53} 54 55uint8 read_reg(floppy_t *flp, floppy_reg_selector selector) 56{ 57 uint8 data; 58 data = flp->isa->read_io_8(flp->iobase + selector); 59#ifdef DEBUG_LOWLEVEL 60 TRACE("read from 0x%lx = 0x%x\n", flp->iobase + selector, data); 61#endif 62 return data; 63} 64 65 66void 67reset_controller(floppy_t *master) 68{ 69 uint8 command[4]; /* for SPECIFY & CONFIGURE */ 70 uint8 result[1]; /* for SPECIFY */ 71 72 TRACE("reset_controller()\n"); 73 LOCK(master->ben); 74 75 //master->pending_cmd = CMD_RESET; 76 master->pending_cmd = 0; 77 write_reg(master, DIGITAL_OUT, read_reg(master, DIGITAL_OUT) & ~0x04); /* reset */ 78 //wait_result(master); 79 spin(20); 80 write_reg(master, DATA_RATE_SELECT, FDC_500KBPS); // 500 kbps 81 master->data_rate = FDC_500KBPS; 82 write_reg(master, DIGITAL_OUT, /*(master->dma < 0)?0x04:*//*0x0c*/0x04); /* motors[abcd] off, DMA on, deassert reset, drive select(0) */ 83 84 wait_result(master); /* wait for reset interrupt */ 85 86 command[0] = CMD_CONFIG; // configure command 87 command[1] = 0; // N/A 88 command[2] = 0x57;//0x70; // Implied Seek, FIFO, Poll Disable, THRESH = default 89 command[3] = 0; // PRETRK 90 91 send_command(master, command, sizeof(command)); 92 93 command[0] = CMD_SPECIFY; 94 command[1] = (((16 - (3)) << 4) | ((240 / 16))); /* step rate 3ms, head unload time 240ms */ 95 command[2] = 0x02 | 0x01; /* head load time 2ms, NO DMA */ 96 97 send_command(master, command, 3); /* send SPECIFY */ 98 read_result(master, result, 1); 99 100 UNLOCK(master->ben); 101} 102 103 104/* returns a bitmap of the present drives */ 105int 106count_floppies(floppy_t *master) 107{ 108 int i, err; 109 int flops = 0; 110 111 master->master = master; 112 113 //floppy_dump_reg(master); 114 115 /* reset controller */ 116 reset_controller(master); 117 118 119 for (i = 0; i < MAX_DRIVES_PER_CTRL; i++) { 120 master->drive_num = i; /* fake */ 121 TRACE("DETECTING DRIVE %d...\n", i); 122 turn_on_motor(master); 123 drive_select(master); 124 err = recalibrate_drive(master); 125 if (err == 0) 126 flops |= 1 << i; 127 TRACE("DRIVE %d %s\n", i, err?"NOT here":"is here"); 128 drive_deselect(master); 129 //snooze(50000); 130 //turn_off_motor(master); 131 } 132 133// floppy_dump_reg(master); 134 135 master->drive_num = 0; 136 return flops; 137} 138 139 140/* selects the drive until deselect(), takes the benaphore */ 141void 142drive_select(floppy_t *flp) 143{ 144 cpu_status st; 145 uint8 reg; 146 TRACE("drive_select(%d)\n", flp->drive_num); 147 LOCK(flp->master->ben); 148 149 /* must be atomic to not change motor states! */ 150 st = disable_interrupts(); 151 acquire_spinlock(&(flp->master->slock)); 152 153 /* make sure the speed for this drive is correct */ 154 if (flp->geometry && (flp->master->data_rate != flp->geometry->data_rate)) { 155 write_reg(flp, DATA_RATE_SELECT, flp->geometry->data_rate); // 500 kbps 156 flp->master->data_rate = flp->geometry->data_rate; 157 } 158 159 /* make sure the drive is selected and DMA is on */ 160 reg = read_reg(flp, DIGITAL_OUT); 161 if((reg & 0x0b) != ((flp->drive_num & 0x03) | 0x08)) 162 write_reg(flp, DIGITAL_OUT, (reg & 0xfc) | (flp->drive_num & 0x03) | /*(flp->master->dma < 0)?0x04:*/0x0c); /* DMA on, reset off */ 163 164 release_spinlock(&(flp->master->slock)); 165 restore_interrupts(st); 166 167 flp->master->current = flp->drive_num; 168} 169 170 171void 172drive_deselect(floppy_t *flp) 173{ 174 UNLOCK(flp->master->ben); 175 TRACE("drive_deselect(%d)\n", flp->drive_num); 176} 177 178 179void 180turn_on_motor(floppy_t *flp) 181{ 182 cpu_status st; 183 uint8 reg; 184 bool do_snooze = false; 185 186 TRACE("turn_on_motor(%d)\n", flp->drive_num); 187 flp->motor_timeout = MOTOR_TIMEOUT; 188 189 /* must be atomic to not deselect a drive! */ 190 st = disable_interrupts(); 191 acquire_spinlock(&(flp->master->slock)); 192 193 if(((reg = read_reg(flp, DIGITAL_OUT)) & (0x10 << flp->drive_num)) == 0) { 194 /* it's off now, turn it on and wait */ 195 //reg = 0x0c; 196 //reg &= 0xfc; /* mask out drive num */ 197 write_reg(flp, DIGITAL_OUT, (0x10 << flp->drive_num) | reg); 198 do_snooze = true; 199 } 200 201 release_spinlock(&(flp->master->slock)); 202 restore_interrupts(st); 203 204 if (do_snooze) 205 snooze(MOTOR_SPINUP_DELAY); 206} 207 208 209void 210turn_off_motor(floppy_t *flp) 211{ 212 cpu_status st; 213 TRACE("turn_off_motor(%d)\n", flp->drive_num); 214 215 /* must be atomic to not deselect a drive! */ 216 st = disable_interrupts(); 217 acquire_spinlock(&(flp->master->slock)); 218 219 write_reg(flp, DIGITAL_OUT, read_reg(flp, DIGITAL_OUT) & ~(0x10 << flp->drive_num)); 220 //write_reg(flp, DIGITAL_OUT, 0x4); 221 222 flp->motor_timeout = 0; 223 224 release_spinlock(&(flp->master->slock)); 225 restore_interrupts(st); 226} 227 228 229void 230wait_for_rqm(floppy_t *flp) 231{ 232 while ((read_reg(flp, MAIN_STATUS) & 0x80) == 0); 233} 234 235 236int 237send_command(floppy_t *flp, const uint8 *data, int len) 238{ 239 int i, status; 240 241 switch (data[0] & CMD_SWITCH_MASK) { 242 case CMD_SENSEI: 243 case CMD_SENSED: 244 case CMD_CONFIG: 245 case CMD_DUMPREG: 246 /* those don't generate an interrupt 247 * (SENSEI is sent by the intrrupt handler itself!) 248 */ 249 break; 250 default: 251 flp->pending_cmd = data[0]; 252 } 253 for(i = 0; i < len; i++) { 254 status = wait_til_ready(flp); 255 if ((status < 0) || (status & 0x40)) 256 break; 257 write_reg(flp, DATA, data[i]); 258 } 259#ifdef DEBUG_LOWLEVEL 260 TRACE("sent %d B\n", i); 261#endif 262 return i; 263} 264 265 266int 267wait_result(floppy_t *flp) { 268 status_t err; 269 270 { int32 c; get_sem_count(flp->completion, &c); TRACE("SEM< %ld\n", c); } 271 272 if ((err = acquire_sem_etc(flp->completion, 1, B_TIMEOUT, FLOPPY_CMD_TIMEOUT)) < B_OK) { 273 if (err == B_TIMED_OUT) { 274 cpu_status st; 275 TRACE("timed out! faking intr !!\n"); 276 st = disable_interrupts(); 277 flo_intr(flp); 278 restore_interrupts(st); 279 acquire_sem_etc(flp->completion, 1, B_TIMEOUT, FLOPPY_CMD_TIMEOUT); 280 } 281 return -1; 282 } 283 { int32 c; get_sem_count(flp->completion, &c); TRACE("SEM> %ld\n", c); } 284 return 0; 285} 286 287 288int 289read_result(floppy_t *flp, uint8 *data, int len) 290{ 291 int i, status; 292 293 //if (flp->master->need_reset) 294 // return -1; 295 for(i = 0; i < len; i++) { 296 status = wait_til_ready(flp); 297 if ((status < 0) || ((status & 0x40) == 0)) 298 break; 299 data[i] = read_reg(flp, DATA); 300 } 301 //flp->master->need_reset = 1; 302#ifdef DEBUG_LOWLEVEL 303 TRACE("read %d B\n", i); 304#endif 305 return i; 306} 307 308 309int 310wait_til_ready(floppy_t *flp) 311{ 312 int i, status; 313 314 for (i = 0; i < 1000; i++) 315 if ((status = read_reg(flp, MAIN_STATUS)) & 0x80) 316 return status; 317 TRACE("timeout waiting for %d !\n", flp->drive_num); 318 return -1; 319} 320 321#if 0 322static int 323has_drive_changed(floppy_t *flp) 324{ 325 return !!(read_reg(flp, DIGITAL_IN) & 0x80); 326} 327#endif 328 329status_t 330query_media(floppy_t *flp, bool forceupdate) 331{ 332 status_t err = B_OK; 333 uint8 command[4]; 334 uint8 result[7]; 335 const floppy_geometry *geom = NULL; 336 337 TRACE("query_media(%d, %s)\n", flp->drive_num, forceupdate?"true":"false"); 338 339 turn_on_motor(flp); 340 drive_select(flp); 341 342 if (read_reg(flp, DIGITAL_IN) & 0x80) {/* media changed */ 343 flp->status = FLOP_MEDIA_CHANGED; 344 TRACE("media changed\n"); 345 } 346 if (err || (flp->status < FLOP_MEDIA_UNREADABLE) || forceupdate) { 347 geom = supported_geometries; 348 TRACE("querying format [err %08lx, st %d, fu %s]\n", err, flp->status, forceupdate?"t":"f"); 349 350 /* zero the current geometry */ 351 flp->geometry = 0; 352 flp->bgeom.bytes_per_sector = 255; 353 flp->bgeom.sectors_per_track = 0; 354 flp->bgeom.cylinder_count = 0; 355 flp->bgeom.head_count = 0; 356 flp->bgeom.read_only = true; 357 358 command[0] = 0x04; // sense drive command 359 command[1] = 0x00 | (flp->drive_num & 0x03); // 360 361 send_command(flp, command, 2); 362 363 read_result(flp, result, 1); 364 TRACE("sense_drive(%d): wp %d, trk0 %d, hd %d, drivesel %d\n", flp->drive_num, !!(result[0]&0x40), !!(result[0]&0x10), !!(result[0]&0x04), (result[0]&0x03)); 365 flp->bgeom.read_only = !!(result[0]&0x40); 366 367 for (; geom->numsectors; geom++) { 368 TRACE("trying geometry %s\n", geom->name); 369 370 /* apply geometry parameters */ 371 if (flp->master->data_rate != geom->data_rate) { 372 write_reg(flp, DATA_RATE_SELECT, geom->data_rate); // 500 kbps 373 flp->master->data_rate = geom->data_rate; 374 } 375 376 /* seek track 0, head 0 */ 377 command[0] = 0x0f; // seek command 378 command[1] = (flp->drive_num & 0x03) | 0x00; // drive | head 0 379 command[2] = 0x00; // track 0 380 381 TRACE("SEEK at track 0 head 0\n"); 382 send_command(flp, command, 3); 383 if (wait_result(flp) < 0) 384 continue; 385 386 /* if it went there then there si something, even if we can't read it */ 387 flp->status = FLOP_MEDIA_UNREADABLE; 388 389 //command[0] = 8; // sense interrupt command 390 //send_command(flp, command, 1); 391 392 //read_result(flp, result, 2); // read the result 393 PRINT_SR0(flp->result[0]); 394 TRACE("track is %d\n", flp->result[1]); 395 if (flp->result[0] & FDC_SR0_IC) 396 continue; 397 398 command[0] = 0x0a | ((geom->flags&FL_MFM)?0x40:0); // read track id 399 command[1] = (flp->drive_num & 0x03) | 0x00; // drive | head 0 400 401 TRACE("READ_TRACK_ID\n"); 402 send_command(flp, command, 2); 403 if (wait_result(flp) < 0) 404 continue; 405 406 //read_result(flp, result, 7); 407 PRINT_SR0(flp->result[0]); 408 TRACE("sr1: %02x\n", flp->result[1]); 409 TRACE("sr2: %02x\n", flp->result[2]); 410 TRACE("read id: track %d, head %d, sec %d, bps %d\n", flp->result[3], flp->result[4], flp->result[5], flp->result[6]); 411 if (flp->result[0] & FDC_SR0_IC) 412 continue; 413 414 /* seek track 2, head 1 */ 415 command[0] = 0x0f; // seek command 416 command[1] = (flp->drive_num & 0x03) | 0x04; // drive | head 1 417 command[2] = 0x02; // track 2 418 419 TRACE("SEEK at track 2 head 1\n"); 420 send_command(flp, command, 3); 421 if (wait_result(flp) < 0) 422 continue; 423 424 //command[0] = 8; // sense interrupt command 425 //send_command(flp, command, 1); 426 427 //read_result(flp, result, 2); // read the result 428 PRINT_SR0(flp->result[0]); 429 TRACE("track is %d\n", flp->result[1]); 430 if (flp->result[0] & FDC_SR0_IC) 431 continue; 432 433 command[0] = 0x0a | ((geom->flags&FL_MFM)?0x40:0); // read track id 434 command[1] = (flp->drive_num & 0x03) | 0x00; // drive | head 0 435 436 TRACE("READ_TRACK_ID\n"); 437 send_command(flp, command, 2); 438 if (wait_result(flp) < 0) 439 continue; 440 441 //read_result(flp, result, 7); 442 443 //read_result(flp, result, 7); 444 PRINT_SR0(flp->result[0]); 445 TRACE("sr1: %02x\n", flp->result[1]); 446 TRACE("sr2: %02x\n", flp->result[2]); 447 TRACE("read id: track %d, head %d, sec %d, bps %d\n", flp->result[3], flp->result[4], flp->result[5], flp->result[6]); 448 if (flp->result[0] & FDC_SR0_IC) 449 continue; 450 451 break; 452 } 453 if (geom->numsectors) { 454 dprintf(FLO "drive %d: media type is %s\n", flp->drive_num, geom->name); 455 flp->status = FLOP_MEDIA_FORMAT_FOUND; 456 err = B_OK; 457 flp->geometry = geom; 458 flp->bgeom.bytes_per_sector = geom->g.bytes_per_sector; 459 flp->bgeom.sectors_per_track = geom->g.sectors_per_track; 460 flp->bgeom.cylinder_count = geom->g.cylinder_count; 461 flp->bgeom.head_count = geom->g.head_count; 462 //flp->bgeom.read_only = true; 463 } else { 464 flp->status = FLOP_NO_MEDIA; 465 } 466 } 467 468 switch (flp->status) { 469 case FLOP_NO_MEDIA: 470 err = B_DEV_NO_MEDIA; 471 break; 472 case FLOP_MEDIA_CHANGED: 473 err = B_DEV_MEDIA_CHANGED; 474 break; 475 case FLOP_MEDIA_UNREADABLE: 476 err = B_DEV_UNREADABLE; 477 break; 478 case FLOP_MEDIA_FORMAT_FOUND: 479 case FLOP_WORKING: 480 default: 481 err = B_OK; 482 } 483 484 drive_deselect(flp); 485 return err; 486} 487 488 489int 490recalibrate_drive(floppy_t *flp) 491{ 492 int retry; 493 494 TRACE("recalibrate_drive(%d)\n", flp->drive_num); 495 496 turn_on_motor(flp); 497 498 for(retry = 0; retry < 1; retry++) { 499 uint8 command[2] = { 7, 0 }; // recalibrate command 500 501 command[1] = flp->drive_num & 0x03; 502 // send the recalibrate command 503 send_command(flp, command, sizeof(command)); 504 505 if (wait_result(flp) < 0) 506 return 3; 507 508 //command[0] = 8; // sense interrupt command 509 //send_command(flp, command, 1); 510 511 // read the result 512 //read_result(flp, result, sizeof(result)); 513 if (flp->result[0] & 0xd0) { 514 TRACE("recalibration failed\n"); 515 return 2; 516 } if (flp->result[1] != 0) { 517 TRACE("drive is at cylinder %d, didn't make it to 0\n", flp->result[1]); 518 if (retry > 3) 519 return 1; 520 } else { 521 // successful 522 break; 523 } 524 } 525 526 TRACE("recalibration done\n"); 527 return 0; 528} 529 530 531int32 532flo_intr(void *arg) 533{ 534 int i; 535 int len; 536 int32 err = B_UNHANDLED_INTERRUPT; 537 floppy_t *flp = (floppy_t *)arg; 538 floppy_t *master = flp->master; 539 540 if (master ==NULL) 541 return B_UNHANDLED_INTERRUPT; 542 acquire_spinlock(&master->slock); 543 544 while (flp && (flp->drive_num != master->current) && !flp->pending_cmd) 545 flp = flp->next; 546 if (flp) { 547 uint8 msr; 548 int got = 0; 549 msr = read_reg(flp, MAIN_STATUS); 550 //TRACE("got irq for %d! MSR=%02x\n", flp->drive_num, msr); 551 if ((((flp->pending_cmd & CMD_SWITCH_MASK) == CMD_READD) || 552 ((flp->pending_cmd & CMD_SWITCH_MASK) == CMD_READTRK)) && ((msr & 0x60) == 0x60)) { 553 /* non DMA xfer(data) & need read */ 554/* uint8 command[1]; 555 command[0] = CMD_SENSEI; 556 send_command(flp, command, 1); 557 len = read_result(flp, flp->result, 2); 558 PRINT_SR0(flp->result[0]);*/ 559 560 //TRACE("READi\n"); 561// while ((msr & 0x60) == 0x60 /*&& (got < 256)*/) { 562 while ((msr & 0xF0) == 0xF0 && (master->buffer_index < CYL_BUFFER_SIZE)) { 563 master->buffer[master->buffer_index++] = read_reg(flp, DATA); 564 master->avail++; 565 msr = read_reg(flp, MAIN_STATUS); 566 got++; 567// spin(10); 568/* if (got < 30) 569 TRACE("%02x", msr); 570 else 571 spin(15);*/ 572 // if (got > 255) 573 // break; 574 } 575// TRACE("intr: READ %d\n", got); 576 } else if (((flp->pending_cmd & CMD_SWITCH_MASK) == CMD_WRITED) && ((msr & 0x60) == 0x20)) { 577 /* non DMA xfer(data) & need write */ 578 TRACE("WRITEi\n"); 579 580 } else { 581 len = 8; 582// if (flp->pending_cmd != CMD_RESET) 583 len = read_result(flp, flp->result, len); 584// else 585// len = 0; 586 if (len < 0) { 587 TRACE("buggy interrupt from %d !\n", flp->drive_num); 588 } else if (len < 1) { /* must pool the interrupt reason */ 589 uint8 command[1] = { CMD_SENSEI }; 590 for (i = 0; i < 4; i++) { /* might have to issue 4 SENSEI */ 591 TRACE("intr: %dth SENSEI\n", i+1); 592 if (send_command(flp, command, 1) < 1) 593 break; 594 len = read_result(flp, flp->result, 2); 595 if (len > 0) 596 PRINT_SR0(flp->result[0]); 597 if (len != 2) 598 break; 599 if ((flp->result[0] & (0x80|FDC_SR0_DS)) == master->current) 600 break; 601 } 602 } else 603 TRACE("RES(%d) %02x %02x %02x %02x\n", len, flp->result[0], flp->result[1], flp->result[2], flp->result[3]); 604 /* only do that for !READ && !WRITE */ 605 flp->pending_cmd = 0; 606 release_sem_etc(flp->completion, 1, B_DO_NOT_RESCHEDULE); 607 } 608 err = B_HANDLED_INTERRUPT; 609 } 610 611 release_spinlock(&master->slock); 612 613 if (err == B_UNHANDLED_INTERRUPT) 614 TRACE("unhandled irq!\n"); 615 return err; 616} 617 618 619void 620floppy_dump_reg(floppy_t *flp) { 621 uint8 command[1] = { 0x0e }; // dumpreg command 622 //uint8 result[10]; 623 uint8 *result = flp->result; 624 625 send_command(flp, command, sizeof(command)); 626 627 //wait_result(flp); 628 read_result(flp, result, 8); 629 630 dprintf(FLO "dumpreg: tracks - d1=%d d2=%d d3=%d d4=%d\n", 631 result[0], result[1], result[2], result[3]); 632 dprintf(FLO "dumpreg: step_rate_time=%d motor_off_time=%d motor_on_time=%d dma=%d\n", 633 result[4] >> 4, result[4] & 0x0f, result[5] >> 1, result[5] & 0x01); 634 dprintf(FLO "sec_per_trk/end_of_trk=0x%.2x lock=%d, byte[7]=0x%.2x\n", 635 result[6], result[7] >> 7,result[7]); 636 dprintf(FLO "gap=%d wg=%d eis=%d fifo=%d poll=%d thresh=%d pretrk=%d\n", 637 (result[7] & 0x02) >> 1, result[7] & 0x01, (result[8] & 0x40) >> 6, 638 (result[8] & 0x20) >> 5, (result[8] & 0x10) >> 4, result[8] & 0x0f, result[9]); 639} 640 641 642static void 643fill_command_from_lba(floppy_t *flp, floppy_command *cmd, int lba) 644{ 645 cmd->cylinder = lba / (flp->bgeom.sectors_per_track * flp->bgeom.head_count); 646 cmd->head = (lba / flp->bgeom.sectors_per_track) % flp->bgeom.head_count; 647 cmd->sector = lba % flp->bgeom.sectors_per_track + 1; 648 cmd->drive = (flp->drive_num & 0x3) | (cmd->head << 2) | 0x80; /* Implied Seek */ 649} 650 651 652/* does NOT check for valid track number */ 653ssize_t 654pio_read_sectors(floppy_t *flp, /*void *buf,*/ int lba, int num_sectors) 655{ 656 ssize_t transfered = 0; 657 floppy_command cmd; 658#if 0 659 uint8 cmd2[8]; 660 uint8 result[4]; 661#endif 662 //floppy_result res; 663 664 if (flp->status < FLOP_MEDIA_FORMAT_FOUND) 665 return B_DEV_UNREADABLE; 666 turn_on_motor(flp); 667 drive_select(flp); 668 if (flp->geometry == NULL || !flp->bgeom.bytes_per_sector || !flp->bgeom.sectors_per_track) { 669 drive_deselect(flp); 670 return B_DEV_NO_MEDIA; 671 } 672 673 flp->track = -1; 674 675 num_sectors = MIN(num_sectors, (signed)(flp->bgeom.sectors_per_track - (lba % flp->bgeom.sectors_per_track))); 676 cmd.id = CMD_READD | /*0xc0*/0x40; // multi-track, read MFM, one head 677 cmd.sector_size = 2; /* 512 bytes */ 678 cmd.track_length = num_sectors;//flp->bgeom.sectors_per_track; 679 cmd.gap3_length = flp->geometry->gap; //27; /* 3.5" floppy */ 680 cmd.data_length = 0xff; /* don't care */ 681 fill_command_from_lba(flp, &cmd, lba); 682 dprintf(FLO "pio_read_sector(%d, %d={%d,%d,%d}, %d)\n", flp->drive_num, lba, cmd.cylinder, cmd.head, cmd.sector, num_sectors); 683 if (num_sectors < 1) { 684 drive_deselect(flp); 685 return EINVAL; 686 } 687 //num_sectors = 1; 688 689#if 0 690 /* first issue sense interrupt, to find the current track */ 691 TRACE("track check: SENSEI\n"); 692 cmd2[0] = CMD_SENSEI; 693 send_command(flp, cmd2, 1); 694 read_result(flp, result, 2); 695 PRINT_SR0(result[0]); 696 /* if the current track is not the one we want, seek */ 697 if (result[1] != cmd.cylinder) { 698 /* seek */ 699 cmd2[0] = CMD_SEEK; // seek command 700 cmd2[1] = (flp->drive_num & 0x3) | (cmd.head << 2); 701 cmd2[2] = cmd.cylinder; // track 0 702 703 TRACE("SEEK at track %d head %d\n", cmd.cylinder, cmd.head); 704 send_command(flp, cmd2, 3); 705 if (wait_result(flp) < 0) 706 return ENXIO; 707 } 708 709#endif 710 711 flp->master->avail = 0; 712 flp->master->buffer_index = (lba % (flp->bgeom.sectors_per_track/* * flp->bgeom.head_count*/)) * flp->bgeom.bytes_per_sector; 713 //flp->pending_cmd = CMD_READD; 714 715 send_command(flp, (uint8 *)&cmd, sizeof(cmd)); 716 717 if (wait_result(flp) < 0) { 718 drive_deselect(flp); 719 return ENXIO; 720 } 721 PRINT_SR0(flp->result[0]); 722 TRACE("sr1: %02x\n", flp->result[1]); 723 TRACE("sr2: %02x\n", flp->result[2]); 724 TRACE("@ track %d, head %d, sec %d, bps %d\n", flp->result[3], flp->result[4], flp->result[5], flp->result[6]); 725 switch (flp->result[0] & FDC_SR0_IC) { 726 case 0x80: 727 transfered = EINVAL; 728 break; 729 case 0x40: 730 //if (flp->result[1] != 0x80) /* End Of Track is not really an error, actually it means it worked :) */ 731 // transfered = ENXIO; 732 break; 733 case 0xc0: 734 transfered = B_DEV_MEDIA_CHANGED; 735 break; 736 } 737 if (transfered) { 738 drive_deselect(flp); 739 return ENXIO; 740 } 741 /* normal termination */ 742 transfered = flp->avail; 743/* if (transfered > 0) 744 memcpy(buf, flp->buffer, flp->avail);*/ 745 746 drive_deselect(flp); 747 return num_sectors;//transfered; 748} 749 750 751ssize_t 752pio_write_sectors(floppy_t *flp, /*const void *buf,*/ int lba, int num_sectors) 753{ 754 return -1; 755} 756 757 758/* does NOT check for valid track number */ 759ssize_t 760pio_read_track(floppy_t *flp, /*void *buf,*/ int lba) 761{ 762 ssize_t transfered = 0; 763 floppy_command cmd; 764#if 0 765 uint8 cmd2[8]; 766 uint8 result[4]; 767#endif 768 int tries = 0; 769 770 if (flp->status < FLOP_MEDIA_FORMAT_FOUND) 771 return B_DEV_UNREADABLE; 772 turn_on_motor(flp); 773 drive_select(flp); 774 if (flp->geometry == NULL || !flp->bgeom.bytes_per_sector || !flp->bgeom.sectors_per_track) { 775 drive_deselect(flp); 776 return B_DEV_NO_MEDIA; 777 } 778 779 flp->track = -1; 780 781retry_track: 782 783 //num_sectors = MIN(num_sectors, (signed)(flp->bgeom.sectors_per_track - (lba % flp->bgeom.sectors_per_track))); 784 cmd.id = CMD_READTRK | 0x40; // read MFM 785 cmd.sector_size = 2; /* 512 bytes */ 786 cmd.track_length = flp->bgeom.sectors_per_track; 787 cmd.gap3_length = flp->geometry->gap; //27; /* 3.5" floppy */ 788 cmd.data_length = 0xff; /* don't care */ 789 fill_command_from_lba(flp, &cmd, lba); 790 cmd.sector = 1; 791 dprintf(FLO "pio_read_track(%d, %d={%d,%d,%d}) try %d\n", flp->drive_num, lba, cmd.cylinder, cmd.head, cmd.sector, tries); 792 793#if 0 794 /* first issue sense interrupt, to find the current track */ 795 TRACE("track check: SENSEI\n"); 796 cmd2[0] = CMD_SENSEI; 797 send_command(flp, cmd2, 1); 798 read_result(flp, result, 2); 799 PRINT_SR0(result[0]); 800 /* if the current track is not the one we want, seek */ 801 if (result[1] != cmd.cylinder) { 802 /* seek */ 803 cmd2[0] = CMD_SEEK; // seek command 804 cmd2[1] = (flp->drive_num & 0x3) | (cmd.head << 2); 805 cmd2[2] = cmd.cylinder; // track 0 806 807 TRACE("SEEK at track %d head %d\n", cmd.cylinder, cmd.head); 808 send_command(flp, cmd2, 3); 809 if (wait_result(flp) < 0) 810 return ENXIO; 811 } 812#endif 813 814 flp->master->avail = 0; 815 flp->master->buffer_index = 0;//(lba % (flp->bgeom.sectors_per_track * flp->bgeom.head_count)) * flp->bgeom.bytes_per_sector; 816 817 send_command(flp, (uint8 *)&cmd, sizeof(cmd)); 818 819 if (wait_result(flp) < 0) { 820 drive_deselect(flp); 821 return ENXIO; 822 } 823 824 PRINT_SR0(flp->result[0]); 825 TRACE("sr1: %02x\n", flp->result[1]); 826 TRACE("sr2: %02x\n", flp->result[2]); 827 TRACE("@ track %d, head %d, sec %d, bps %d\n", flp->result[3], flp->result[4], flp->result[5], flp->result[6]); 828 829 switch (flp->result[0] & FDC_SR0_IC) { 830 case 0x80: 831 transfered = EINVAL; 832 break; 833 case 0x40: 834 TRACE(FLO "sr1: %02x\n", flp->result[1]); 835 if (flp->result[1] != 0x80) {/* End Of Track is not really an error, actually it means it worked :) */ 836 if (/*(flp->result[1] == 0x10) && */tries < 3) { /* overrun */ 837 tries++; 838 goto retry_track; 839 } else 840 transfered = EIO; 841 } 842 break; 843 case 0xc0: 844 transfered = B_DEV_MEDIA_CHANGED; 845 break; 846 } 847 if (transfered) { 848 drive_deselect(flp); 849 return ENXIO; 850 } 851 /* normal termination */ 852 transfered = flp->avail; 853/* if (transfered > 0) 854 memcpy(buf, flp->buffer, flp->avail);*/ 855 flp->master->track = cmd.cylinder*flp->bgeom.head_count + cmd.head; 856 857 drive_deselect(flp); 858 return 1;//transfered; 859} 860 861 862ssize_t 863read_sectors(floppy_t *flp, int lba, int num_sectors) 864{ 865 ssize_t transfered = 0; 866 //return pio_read_sectors(flp, lba, num_sectors); 867 /* if (nothing cached || not the same track cached) */ 868 dprintf(FLO "read_sector(%d, %d, %d)\n", flp->drive_num, lba, num_sectors); 869 num_sectors = MIN(num_sectors, (signed)(flp->bgeom.sectors_per_track - (lba % flp->bgeom.sectors_per_track))); 870 if ((flp->master->track < 0) || 871 (flp->master->track != (signed)(lba / (flp->bgeom.sectors_per_track)))) { 872 if ((lba / (flp->bgeom.sectors_per_track)) >= (flp->bgeom.head_count * flp->bgeom.cylinder_count)) 873 return ENXIO; 874 transfered = pio_read_track(flp, lba); 875 if (transfered < 0) 876 return transfered; 877 /* XXX: TODO: in case of IO error, retry by single sector */ 878 } 879 return num_sectors; 880} 881 882