Example #1
0
int init_floppy()
{
	int drive = floppy_get_current_drive();
	uint8_t drive_type = 0;
	uint8_t CCR;
	
	/* On vérifie qu'on a bien un controleur standard, sinon on affiche un warning */
	if(floppy_get_version() != 0x90)
		kerr("WARNING: Floppy driver may not work with 0x%x controler.", floppy_get_version());

	floppy_reset_irq();
	
	// On fait le reset du controler + activation DMA/IRQ
	outb(0x00, FLOPPY_BASE + FLOPPY_DOR);
	outb(0x0C, FLOPPY_BASE + FLOPPY_DOR);
	
	floppy_wait_irq();
	floppy_sense_interrupt(NULL,NULL);
	
	// On regle la vitesse de transfert en fonction du type de disquette
	drive_type = floppy_get_type(drive);
	switch(drive_type)
	{
		case 1: // 300 kbps (01)
		case 3:
			CCR = 0x01;
			break;
			
		case 2: // 500 kbps (00)	
		case 4:
		
			CCR = 0x00;
			break;
		case 5: // 1 Mbps (11)
			CCR= 0x03;
			break;
			
		default:
			CCR = 0x00; // choix arbitraire btw
			break;
	}
	outb(CCR, FLOPPY_BASE + FLOPPY_CCR);
	
	
/* Totalement hardcodé et moche à fortiori*/
	floppy_write_command(SPECIFY);
    floppy_write_command(0xdf); /* steprate = 3ms, unload time = 240ms */
    floppy_write_command(0x02); /* load time = 16ms, no-DMA = 0 */
/* *************************************** */
	
	// On calibre le lecteur
	if(floppy_calibrate()) return -1;
	return 0;
}
Example #2
0
// Repositionne la tête de lecture sur le cylindre 0
int floppy_calibrate()
{
	int i, st0, cy1 = -1;
	int drive = floppy_get_current_drive();
	
	// Allumer le moteur
	floppy_motor(ON);
	
	// On essaye 5 fois (oui c'est totalement arbitraire)
	for(i=0; i<5; i++)
	{
		// Le recalibrage déclenche l'IRQ, on se prépare donc à attendre l'IRQ
		floppy_reset_irq();
		
		// Procedure de calibrage:
		// On envoi dans un premier temps la commande RECALIBRATE,
		// puis on envoi le numero du lecteur que l'on veut recalibrer
		floppy_write_command(RECALIBRATE);
		floppy_write_command(drive);
		
		// On attend la réponse
		floppy_wait_irq();
		
		// une fois l'IRQ arrivée, on peut récuperer les données de retour via SENSE_INTERRUPT
		floppy_sense_interrupt(&st0, &cy1);
		
		if(st0 & 0xC0)
		{
			static const char * status[] =
			{ 0, "error", "invalid", "drive" };
			klog("floppy_recalibrate: status = %s.", status[st0 >> 6]);
			klog("\tST0:0x%x.\nCY1:0x%x.", st0, cy1);
			continue;
		}
	
		if(!cy1) // si cy1=0, on a bien atteint le cylindre 0 et on peut arreter la calibration
		{
			floppy_motor(OFF);
			return 0;
		}
		
	}
	kerr("floppy_recalibrate: failure.");
	
	floppy_motor(OFF);
	
	return -1;
}
Example #3
0
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;
}