uint8_t* floppy_read(uint32_t addr, uint8_t sectorc) { uint8_t cylinder = addr / CY_NUM; uint8_t head = (addr % CY_NUM) / HE_NUM; uint8_t sector = ((addr % CY_NUM) % HE_NUM) / SE_NUM + 1; uint8_t st, cy; floppy_control_motor(true); if(floppy_seek(cylinder, head, 0) != 0) return 0; prepare_floppy_DMA_read(sectorc); floppy_send_cmd(MT | MF | SK | READ_DATA); floppy_send_cmd(head << 2); floppy_send_cmd(cylinder); floppy_send_cmd(head); floppy_send_cmd(sector); floppy_send_cmd(2); floppy_send_cmd(sectorc); // read sector count floppy_send_cmd(0x1b); floppy_send_cmd(0xff); wait_floppy_irq(); floppy_check_int(&st, &cy); // result phase for(uint32_t index_1 = 0 ; index_1 < 7; index_1++) floppy_read_byte(); floppy_control_motor(false); return (uint8_t*) DMA_ADDR; }
/******************************************************************************* * void floppy_reset() * * This resets the floppy (duh!) into a known condition. * * Date: December 31, 2004 * *****************************************************************************/ void floppy_reset() { outportb(FDC_DOR, 0); floppy_mtick = 0; floppy_motor = false; /*disable interrupt*/ outportb(FDC_DRS, 0); /*reenable interrupts*/ outportb(FDC_DOR, 0x0C); /*the reset triggered an interrupt, wait for it to be handled*/ floppy_done = true; floppy_wait(true); /*specify driv timings*/ floppy_sendbyte(CMD_SPECIFY); floppy_sendbyte(0xDF); floppy_sendbyte(0x02); /*clear the "disk change" status */ floppy_seek(1); floppy_recalibrate(); floppy_dchange = false; }
uint8_t read_sector(uint8_t C,uint8_t H,uint8_t S) { wait_for_FDC(); while(!floppy_motor); if(floppy_C != C) { floppy_seek(C); } init_floppy_DMA(); send_floppy_command(FLOPPY_READ_CMD); send_floppy_data((H<<2)|FLOPPY_SELECT_A); send_floppy_data(C); send_floppy_data(H); send_floppy_data(S); send_floppy_data(2); send_floppy_data(1);//Sector Number send_floppy_data(0x1B); send_floppy_data(0xFF); floppy_interrupt_finished = 0; backup_eflags(); sti(); floppy_disable_other_interrupt(); while(!floppy_interrupt_finished); floppy_enable_other_interrupt(); restore_eflags(); st0 = read_floppy_data(); st1 = read_floppy_data(); st2 = read_floppy_data(); C = read_floppy_data(); H = read_floppy_data(); S = read_floppy_data(); read_floppy_data();//Sector Number wait_for_FDC(); if((st0>>6)||st1||st2) { return 0; } }
/* Low-level block device routine */ static int floppy_rw_blk(struct blkdev *bdev, int write, block_t blk, char *buf, size_t len) { int head, track, sector; int tries = 3; long flags; if ( write ) { printk("floppy0: read-only device\n"); return -1; } try_again: if ( inb(dprts->dir) & DIR_CHAN ) { printk("floppy: disk change on read\n"); return -1; } floppy_block(blk, &head, &track, §or); floppy_seek(dprts, track); /* select data rate (is this redundant?) */ outb(dprts->ccr, 0); /* Do the read */ lock_irq(flags); dma_read(2, buf, 512); floppy_send(dprts, CMD_READ); floppy_send(dprts, head<<2); floppy_send(dprts, track); floppy_send(dprts, head); floppy_send(dprts, sector); floppy_send(dprts, 2); floppy_send(dprts, geom->spt); floppy_send(dprts, geom->g3_rw); floppy_send(dprts, 0xff); sleep_on(&floppyq); unlock_irq(flags); /* Success */ if ( (status[0] & 0xc0) == 0 ) { if ( --len ) { blk++; buf+=512; goto try_again; } return 0; } if ( --tries ) { printk("floppy_rw_block: I/O err, try again\n"); floppy_recal(dprts); goto try_again; } return -1; }
static int floppy_cylinder(int drive, int cylinder, floppy_io io_dir) { uint8_t command = 0; int i; const uint8_t flags = 0xC0; // Multitrack et MFM activés // Variables recevant les valeurs de retour de la lecture uint8_t st0, st1, st2, rcy, rhe, rse, bps; int error = 0; switch(io_dir) { case FLOPPY_WRITE: command = WRITE_DATA | flags; break; case FLOPPY_READ: command = READ_DATA | flags; break; default: kerr("Invalid io_dir (0x%x).", io_dir); return -1; } // On lit avec les deux têtes, on les met donc toutes en position if(floppy_seek(drive, cylinder, 0)) return -1; if(floppy_seek(drive, cylinder, 1)) return -1; // On s'accord 5 essais, totalement arbitraire, à calibrer donc. for(i=0; i<5; i++) { // Allumage moteur floppy_motor(drive, ON); // Initialisation DMA floppy_dma_init(io_dir); //TODO: Sleep pour attendre que le seek soit bien fini // Envoi de la commande //1) Commande //2) (head<<2)|drive //3) Numero du cylindre //4) head //5) Numero du premier secteur //6) Taille des secteur(2=512 bytes, ce qui est le cas pour toutes les floppy...) //7) Nombre de secteurs à lire //8) 0x1b (taille par défaut de GAP1) //9) 0xff (??) floppy_write_command(command); floppy_write_command(drive&0x03); // head = 0 dans le cas du MT, et drive&0x03 au cas ou drive > 3 floppy_write_command(cylinder); floppy_write_command(0); // voir plus haut floppy_write_command(1); // On compte les secteurs a partir de 1 floppy_write_command(2); floppy_write_command(18); // 18 secteurs par piste floppy_write_command(0x1b); floppy_write_command(0xff); floppy_wait_irq(); // On verifie que la lecture c'est correctement déroulée // Informations de statut st0 = floppy_read_data(); st1 = floppy_read_data(); st2 = floppy_read_data(); // Informations sur les CHS rcy = floppy_read_data(); // Cylindre rhe = floppy_read_data(); // Head rse = floppy_read_data(); // Secteur bps = floppy_read_data(); // Nomber de byte par secteur /* Traitement des erreurs repompée */ if(st0 & 0xC0) { static const char * status[] = { 0, "error", "invalid command", "drive not ready" }; klog("floppy_do_sector: status = %s", status[st0 >> 6]); error = 1; } if(st1 & 0x80) { kerr("end of cylinder"); error = 1; } if(st0 & 0x08) { kerr("drive not ready "); error = 1; } if(st1 & 0x20) { kerr("CRC error"); error = 1; } if(st1 & 0x10) { kerr("controller timeout"); error = 1; } if(st1 & 0x04) { kerr("no data found\n"); error = 1; } if((st1|st2) & 0x01) { kerr("no address mark found"); error = 1; } if(st2 & 0x40) { kerr("deleted address mark"); error = 1; } if(st2 & 0x20) { kerr("CRC error in data"); error = 1; } if(st2 & 0x10) { kerr("wrong cylinder"); error = 1; } if(st2 & 0x04) { kerr("uPD765 sector not found"); error = 1; } if(st2 & 0x02) { kerr("bad cylinder"); error = 1; } if(bps != 0x2) { kerr("wanted 512B/sector, got %d", (1<<(bps+7))); error = 1; } if(st1 & 0x02) { kerr("not writable"); error = 2; } if(!error) { floppy_motor(drive, OFF); return 0; } if(error > 1) { kerr("not retrying...(rcy = %0x%x, rhe = %0x%x, rse = %0x%x)", rcy, rhe, rse); floppy_motor(drive, OFF); return -2; } } return 0; }
/******************************************************************************* * bool floppy_rw(int block, unsigned char *blockbuff, * unsigned char read, unsigned long nosectors) * * Since the read and write to a floppy disk is not that much different, most of * the code is the same. The only difference is dependent on what the 'read' * variable is set as. * * Parameters: * 1) int block * This is the block that we want to read. * 2) unsigned char *blockbuff * This is the buffer that we want it read into or written out to. The size * of this buffer should be 512 * nosectors, as each sector read in is 512 * bytes * 3) unsigned char read * Are we going to read or write to this block. * 4) unsigned long nosectors * The number of sectors that we want to be read in. * * Return value: * This returns where or not the read/write was successfull. * * Date: December 31, 2004 * *****************************************************************************/ bool floppy_rw(int block, unsigned char *blockbuff, unsigned char read, unsigned long nosectors) { int head; int track; int sector; int tries; int copycount=0; unsigned char *p_track_buffer = (unsigned char*)floppy_dma_address; unsigned char *p_block_buffer = blockbuff; ///convert logical address into physical address floppy_block2hts(block , &head, &track, §or); ///start the floppy motor floppy_motor_start(); if (!read && blockbuff) ///copy data from the data buffer into the track buffer for (copycount=0; copycount<(nosectors*512); copycount++) *(p_track_buffer++) = *(p_block_buffer++); for (tries = 0; tries < 3; tries++) { ///check for disk change if (inportb(FDC_DIR) & 0x80) { floppy_dchange = true; floppy_seek(1); floppy_recalibrate(); floppy_motor_stop(); ERROR_MSG(("FDC: Disk change detected. Trying again.")); return floppy_rw(block, blockbuff, read, nosectors); } ///move head to the right track if (!floppy_seek(track)) { floppy_motor_stop(); ERROR_MSG(("FDC: Seek error")); return false; } ///program data rate (500Kb/s) outportb(FDC_CCR, 0); ///send command if (read) { dma_xfer(2, (unsigned long)floppy_dma_address, nosectors*512, false); floppy_sendbyte(CMD_READ); } else { dma_xfer(2, (unsigned long)floppy_dma_address, nosectors*512, true); floppy_sendbyte(CMD_WRITE); } floppy_sendbyte(head << 2); floppy_sendbyte(track); floppy_sendbyte(head); floppy_sendbyte(sector); floppy_sendbyte(2); floppy_sendbyte(floppy_geometry.spt); if (floppy_geometry.spt == DG144_SPT) floppy_sendbyte(DG144_GAP3RW); else floppy_sendbyte(DG168_GAP3RW); floppy_sendbyte(0xff); ///wait for commmand completion if (!floppy_wait(true)) { ERROR_MSG(("Timed out, trying operation again after reset")); floppy_reset(); return floppy_rw(block, blockbuff, read, nosectors); } ///let's see if the transfer worked if ((floppy_status[0] & 0xC0) == 0) break; ///it didn't work. try again floppy_recalibrate(); } floppy_motor_stop(); if (read && blockbuff) { ///copy data from track buffer into data buffer p_block_buffer = blockbuff; p_track_buffer = (unsigned char *)floppy_dma_address; for (copycount = 0; copycount <(nosectors*512); copycount++) { *p_block_buffer = *p_track_buffer; p_block_buffer++; p_track_buffer++; } } return (tries != 3); }