floppy.c

Go to the documentation of this file.
00001 /* floppy.c */
00002 
00003 /*
00004  * Revision: 22 Marzo 2004
00005  *    + Se migra la funcion (Floppy) llamada desde la rutina de atencion a interrupcion (intFloppy) a este archivo, 
00006  *      con lo que se hace la variable "continuar" (de ahora en mas llamada "floppy_continuar") como local al
00007  *      archivo (static).
00008  *
00009  *    + Se ajustan los valores de inicializacion del floppy (comandos CONFIGURE y SPECIFY) de la siguiente forma:
00010  *              Se habilita la fifo (propia del 82077a) con un tama#o de 10 bytes.
00011  *              Step rate interval:  4mseg
00012  *              Head Unload time  : 16mseg
00013  *              Head Load time    : 16mseg
00014  *              
00015  *    + Proxima revision:
00016  *              funciones de lectura y escritura
00017  *              conversion de sectores logicos a fisicos (LBA)
00018  * ----------------------------------------------------------------
00019  *
00020  * Revision: 24 Marzo 2004
00021  *
00022  *    + Se crea la funcion dump_status_register() con fin de poder dumpear y debugear el estado de los registros
00023  *      de estado (ST0 a ST3)
00024  *
00025  *    + En la funcion read_sector se reemplaza la verificacion de todos los bits del ST0 por una macro "COMMAND_OK"
00026  *      (definida en include/drivers/floppy.h) que solo chequea el valor del IC de este registro de estado.
00027  *      Esto es ya que cuando estamos en la condicion de sector=18 el valor de "H" devuelto por ST0 cambia (de 0 a 1
00028  *      por ejemplo), pienso que se debera que nos indica la proxima posicion de la cabeza para leer el proximo
00029  *      sector (el sector numero 18 es el ultimo sector de un track en una cara).
00030  *      Con este cambio se observa que pueden ejecutarse sin problemas todos los archivos de disco.
00031  */
00032 
00033 
00034 
00035 #include <drivers/floppy.h>
00036 #include <fs/blockcache.h>
00037 #include <routix/device.h>
00038 #include <routix/atomic.h>
00039 #include <routix/8259.h>
00040 #include <routix/kstdio.h>
00041 #include <routix/timer.h>
00042 
00043 #define OK  0
00044 
00045 int block(void);
00046 int floppy_get_result(void);
00047 int leer_sec(byte cara, byte cilindro, byte sector , byte *buffer);
00048 void dump_states(void);
00049 void dump_status_register(int numero, byte valor);
00050 
00051 void leer_escribir_new();
00052 void init_floppy_block_new(void);
00053 void recalibrate_block_new(void);
00054 void motor_on_new_finish(timer_t *timer);
00055 void seek_block_new();
00056 void read_sector_block_new();
00057 void error();
00058 void error_por_timeout();
00059 
00060 
00061 
00062 
00063 // Puntero a funcion para manejar las interrupciones
00064 static void (*func)(void) = NULL;
00065 
00066 // Solicitud en proceso
00067 static block_cache_t *actual_request = NULL;
00068 #define ACTUAL_REQUEST (actual_request)
00069 
00070 //Contiene el estado del motor (0=apagado , 1=encendido)
00071 static byte motor_status=MOTOR_OFF;
00072 static byte floppy_calibrado=0;
00073 static byte seek_status=0;
00074 static byte rw_status=0;
00075 
00076 // Timer para encendido y apagado de motor
00077 static timer_t *timer_motor = NULL;
00078 // Timer de deteccion de TIMEOUTs
00079 static timer_t *timer_timeout = NULL;
00080 
00081 // Array con los valores de estados y pcn en la fase de resultado.
00082 // Valores validos: 0-255   ;   ERR_TIMEOUT     ; NO_VALIDO
00083 static int status[12];  
00084 
00085 #define ST0 status[0]
00086 #define ST1 status[1]
00087 #define ST2 status[2]
00088 #define ST3 status[3]
00089 
00090 
00091 // En esta direccion (640K - 1024) se ubica el bloque para transferencias DMA. La ubicacion de este bloque no puede
00092 // quedar entre dos paginas (el tamaño de estas paginas es de 64K) es decir tiene que estar totalmente contenido dentro
00093 // del mismo bloque.
00094 addr_t dma_address=0xA0000 - 1024;
00095 
00096 
00097 void motor_on()
00098 {
00099     outportb(DOR, DMA_INT | MOTA);
00100     motor_status=1;
00101     dword demora=0x3ffff;   
00102     while (demora--);           //Esperar por el regimen permanente del motor
00103 }
00104 
00105 
00106 
00107 // Version de motor on con timers
00108 void motor_on_new()
00109 {
00110   timer_motor = create_timer(USECONDS_TO_TICKS(TIME_WAIT_FOR_MOTOR_ON), NULL, motor_on_new_finish, NULL);
00111   
00112   outportb(DOR, DMA_INT | MOTA);
00113 }
00114 
00115 // Regimen permanente alcanzado
00116 void motor_on_new_finish(timer_t *timer)
00117 {
00118   //kprintf("Pasaron 500mseg... regimen permanente alcanzado\n");
00119   motor_status=MOTOR_ON;
00120 
00121   // El timer ya no existe
00122   timer_motor = NULL;
00123 
00124 
00125   // Si fue como resultado de un pedido de lectura o escritura
00126   if ( ACTUAL_REQUEST != NULL )
00127     leer_escribir_new();
00128   
00129 }
00130 
00131 
00132 void motor_off()
00133 {
00134     outportb(DOR, DMA_INT);
00135     motor_status=0;
00136     floppy_calibrado=0;
00137 }
00138 
00139 
00140 void motor_off_new(timer_t *timer)
00141 {
00142   outportb(DOR, DMA_INT);
00143   motor_status=MOTOR_OFF;
00144 
00145   // Todo a su posicion original
00146   floppy_calibrado=0;
00147   seek_status=0;
00148   rw_status=0;
00149 
00150   //kprintf("motor_off_new: Apagando el motor\n");
00151 
00152   // Eliminamos el timer
00153   //clean_timer(timer);
00154 
00155   // No existe
00156   timer_motor = NULL;
00157 }
00158 
00159 
00160 
00161 void set_dor(word valor)
00162 {
00163  outportb(DOR, valor);
00164 }
00165 
00166 
00167 
00169 // Envia un byte al registro de datos del controlador                       //
00171 int floppy_sendbyte(byte valor)
00172 {
00173  unsigned char msr;
00174  int timeout;
00175  
00176  for (timeout=SENDBYTE_TIMEOUT; timeout; timeout--) {
00177  
00178   // Leemos primero el MSR (Main Status Register)
00179   msr = inportb(MSR);
00180 
00181   // Si RQM=1 y DIO=0 ( Host puede escribir info)
00182   if ( (msr & RQM) && ~(msr & DIO)  ) {
00183     outportb(DATA, valor);
00184     break;
00185   }
00186 
00187  }
00188 
00189  // Si timeout llego a 0 no se pudo completar la escritura
00190  return timeout;
00191 }
00192 
00193 
00195 // Lee un byte del registro de datos del controlador //
00197 int floppy_get_result()
00198 {
00199  unsigned char msr;
00200  byte posicion=0;
00201  int timeout;
00202  
00203     for (timeout=GETBYTE_TIMEOUT; timeout; timeout--) 
00204     {
00205         // Leemos primero el MSR (Main Status Register)
00206         msr = inportb(MSR) & (RQM | CMDBUSY | DIO);
00207 
00208         // Si RQM=1, DIO=1 y CMD_BUSY=1 ( Host puede leer info)
00209         if ( msr == (RQM | CMDBUSY | DIO) )
00210         {
00211             status[posicion++]=inportb(DATA);
00212             continue;
00213         }
00214         //Si el controller dejo de estar ocupado (CMD_BUSY=0), no hay mas resultados que levantar, salida Ok
00215         else if ( msr == RQM )
00216         {
00217             status[posicion]=NO_VALIDO;
00218             return OK;
00219         }
00220     }
00221 
00222     // Si timeout llego a 0 no se pudo completar la escritura
00223     return ERR_TIMEOUT; 
00224 
00225 }
00226 
00227 
00228 // Inicializacion del floppy
00229 int init_floppy()
00230 {
00231     int i;
00232 
00233      // Reset
00234     outportb(DOR, 0);
00235     
00236     outportb(DOR, 0x0C);
00237 
00238     // Programamos la velocidad de datos (500 Kbps para 1.44MB)
00239     outportb(CCR, DR_500KBPS);
00240 
00241     //Esperamos la interrupcion
00242     block();
00243 
00244     // Recolectamos el estado de las interrupciones de los 4 drives
00245     // que soporta el controlador
00246     for (i=0; i<4; i++) {
00247 
00248         if ( ! floppy_sendbyte(SENSE_INTERRUPT_STATUS) ) {
00249           return ERR_TIMEOUT;
00250         }
00251     
00252    
00253         if (floppy_get_result()==ERR_TIMEOUT)     {
00254           return ERR_TIMEOUT;
00255         }
00256 
00257     }
00258 
00259     
00260  // Ahora reconfiguramos el controlador
00261  if ( ! floppy_sendbyte(CONFIGURE_0) ) {
00262         return ERR_TIMEOUT;
00263  }
00264  if ( ! floppy_sendbyte(CONFIGURE_1) ) {
00265         return ERR_TIMEOUT;
00266  }
00267 
00268  // COMENTARIO: me quedan dudas respecto a estos valores ya que
00269  //     CONF_EIS: habilitamos los seeks automaticos (implicitos)
00270  //     CONF_EFIFO: deshabilitamos los fifos !! (modo 8272a)
00271  //     CONF_POLL:  deshabilitamos el polling, esto esta oks
00272  //if ( ! floppy_sendbyte(CONF_EIS|CONF_EFIFO|CONF_POLL) ) {}
00273  if ( ! floppy_sendbyte( (CONF_EIS|CONF_POLL) | 0xa) ) {                // 10 bytes de threshold
00274         return ERR_TIMEOUT;
00275  }
00276  if ( ! floppy_sendbyte(0) ) {
00277         return ERR_TIMEOUT;
00278  }
00279 
00280  // Seguimos con SPECIFY
00281  if ( ! floppy_sendbyte(SPECIFY) ) {
00282         return ERR_TIMEOUT;
00283  } 
00284 
00285  if ( ! floppy_sendbyte(0xC1) ) {                       // Seteamos SRT=4mseg (0xC0) y HUT=16mseg (0x01)
00286         return ERR_TIMEOUT;
00287  }
00288 
00289  if ( ! floppy_sendbyte(0x8<<1) ) {             // Seteamos HLT=16mseg (0x08 << 1) y ND (Ahora esta en NON-DMA !!)
00290         return ERR_TIMEOUT;
00291  }
00292 
00293    //kprintf("Inicializacion Oks !!\n");
00294 
00295         return OK;   
00296 }
00297 
00298 
00299 
00300 
00301 // Inicializacion del floppy
00302 void init_floppy_new()
00303 {
00304 
00305   // Reset
00306   outportb(DOR, 0);
00307     
00308   outportb(DOR, 0x0C);
00309 
00310   // Programamos la velocidad de datos (500 Kbps para 1.44MB)
00311   outportb(CCR, DR_500KBPS);
00312 
00313   //Esperamos la interrupcion, le indicamos la nueva rutina de atencion de interrupcion
00314   //block();
00315   func=init_floppy_block_new;
00316 }
00317 
00318 
00319 void init_floppy_block_new(void)
00320 {       
00321   int i;
00322 
00323   // Reseteamos a func a su valor default
00324   func=NULL;
00325 
00326   // Recolectamos el estado de las interrupciones de los 4 drives
00327   // que soporta el controlador
00328   for (i=0; i<4; i++) {
00329 
00330     if ( ! floppy_sendbyte(SENSE_INTERRUPT_STATUS) ) {
00331       //return ERR_TIMEOUT;
00332     }
00333     
00334    
00335     if (floppy_get_result()==ERR_TIMEOUT)     {
00336       //return ERR_TIMEOUT;
00337     }
00338 
00339   }
00340 
00341     
00342  // Ahora reconfiguramos el controlador
00343  if ( ! floppy_sendbyte(CONFIGURE_0) ) {
00344         //return ERR_TIMEOUT;
00345  }
00346  if ( ! floppy_sendbyte(CONFIGURE_1) ) {
00347         //return ERR_TIMEOUT;
00348  }
00349 
00350  // COMENTARIO: me quedan dudas respecto a estos valores ya que
00351  //     CONF_EIS: habilitamos los seeks automaticos (implicitos)
00352  //     CONF_EFIFO: deshabilitamos los fifos !! (modo 8272a)
00353  //     CONF_POLL:  deshabilitamos el polling, esto esta oks
00354  //if ( ! floppy_sendbyte(CONF_EIS|CONF_EFIFO|CONF_POLL) ) {}
00355  if ( ! floppy_sendbyte( (CONF_EIS|CONF_POLL) | 0xa) ) {                // 10 bytes de threshold
00356         //return ERR_TIMEOUT;
00357  }
00358  if ( ! floppy_sendbyte(0) ) {
00359         //return ERR_TIMEOUT;
00360  }
00361 
00362  // Seguimos con SPECIFY
00363  if ( ! floppy_sendbyte(SPECIFY) ) {
00364         //return ERR_TIMEOUT;
00365  } 
00366 
00367  if ( ! floppy_sendbyte(0xC1) ) {                       // Seteamos SRT=4mseg (0xC0) y HUT=16mseg (0x01)
00368         //return ERR_TIMEOUT;
00369  }
00370 
00371  if ( ! floppy_sendbyte(0x8<<1) ) {             // Seteamos HLT=16mseg (0x08 << 1) y ND (Ahora esta en NON-DMA !!)
00372         //return ERR_TIMEOUT;
00373  }
00374 
00375 // Si fue como resultado de un pedido de lectura o escritura
00376 if ( ACTUAL_REQUEST != NULL )
00377   leer_escribir_new();
00378 
00379 }
00380 
00381 
00383 // Recalibra la posicion de la cabeza a la pista 0
00385 #define PCN     status[1]
00386 
00387 int recalibrate()
00388 {
00389 
00390     // Reseteamos el flag
00391     floppy_calibrado=0;
00392          
00393     // Habilita el motor A y el Drive 0
00394     motor_on();
00395 
00396     // Ejecutamos un RECALIBRATE 
00397     if ( ! floppy_sendbyte(RECALIBRATE) ) {     
00398                 return ERR_TIMEOUT;
00399     }
00400 
00401     if ( ! floppy_sendbyte(DRIVE_0) ) {                 // DS0=0 DS1=0 (Drive 0)
00402                 return ERR_TIMEOUT;
00403     }
00404 
00405     if ( block()!=OK )  {
00406                 return ERR_NEED_RESET;
00407     }
00408     
00409     // Sensamos el estado de interrupcion
00410     if ( ! floppy_sendbyte(SENSE_INTERRUPT_STATUS) ) {
00411                 return ERR_TIMEOUT;
00412     }
00413 
00414     // Obtener resultados de ejecucion 
00415     if (floppy_get_result()==ERR_TIMEOUT)     {
00416                 return ERR_TIMEOUT;
00417     }
00418    
00419     // Analizamos el resultado del comando 
00420     if ( ! COMMAND_OK ) {
00421                 //kprintf("RECALIBRATE\n");
00422                 dump_states();
00423                 return ERR_NEED_RESET;
00424     }
00425 
00426     // Pudimos calibrarlo sin problemas
00427     floppy_calibrado=1;
00428     
00429     return OK;
00430 }
00431 
00432 
00433 
00434         int recalibrate_new()
00435         {
00436 
00437           // Reseteamos el flag
00438           floppy_calibrado=0;
00439                  
00440           // Ejecutamos un RECALIBRATE 
00441           if ( ! floppy_sendbyte(RECALIBRATE) ) {       
00442             return ERR_TIMEOUT;
00443           }
00444 
00445           if ( ! floppy_sendbyte(DRIVE_0) ) {                   // DS0=0 DS1=0 (Drive 0)
00446             return ERR_TIMEOUT;
00447           }
00448 
00449           //Esperamos la interrupcion, le indicamos la nueva rutina de atencion de interrupcion
00450           func=recalibrate_block_new;
00451 
00452           // Aca debemos agregar el timer de timeout
00453           timer_timeout = create_timer(USECONDS_TO_TICKS(TIEMPO_TIMEOUT_COMANDO), NULL, error_por_timeout, NULL);
00454 
00455                 if ( getvar("debugfloppy")==1 )
00456                         kprintf("Envio de recalibrate_new !!\n");
00457 
00458           return OK;
00459           
00460         }
00461 
00462         void recalibrate_block_new(void)
00463         {
00464           // Reseteamos a func a su valor default
00465           func=NULL;
00466 
00467           // Eliminamos el timer de timeout
00468           clean_timer(timer_timeout);
00469 
00470           // El timer ya no existe
00471           timer_timeout = NULL;
00472           
00473                 if ( getvar("debugfloppy")==1 )
00474                         kprintf("Recalibrado ok !!\n");
00475 
00476           // Sensamos el estado de interrupcion
00477           if ( ! floppy_sendbyte(SENSE_INTERRUPT_STATUS) ) {
00478             //return ERR_TIMEOUT;
00479             error();
00480             return;
00481           }
00482 
00483           // Obtener resultados de ejecucion 
00484           if (floppy_get_result()==ERR_TIMEOUT)     {
00485             //return ERR_TIMEOUT;
00486             error();
00487             return;
00488           }
00489            
00490           // Analizamos el resultado del comando 
00491           if ( ! COMMAND_OK ) {
00492             dump_states();
00493             //return ERR_NEED_RESET;
00494             error();
00495             return;
00496           }
00497 
00498           // Pudimos calibrarlo sin problemas
00499           floppy_calibrado=1;
00500 
00501           // Si fue como resultado de un pedido de lectura o escritura
00502           if ( ACTUAL_REQUEST != NULL )
00503             leer_escribir_new();
00504     
00505   //return OK;
00506 }
00507 
00508 
00509 byte read_sector_id (void)
00510 {
00511     // Habilita el motor A y el Drive 0
00512     motor_on();
00513 
00514     // Ejecutamos un Read sector id
00515     if ( ! floppy_sendbyte(READ_SECTOR_ID) ) {  
00516         return ERR_TIMEOUT;
00517     }
00518 
00519     if ( ! floppy_sendbyte(0) ) {                       // HD=0 (head number) , DS0=0 DS1=0 (Drive 0)
00520         return ERR_TIMEOUT;
00521     }
00522 
00523     block();
00524     
00525     // Sensamos el estado de interrupcion
00526 /*    if ( ! floppy_sendbyte(SENSE_INTERRUPT_STATUS) ) {
00527         puts("Error, timeout enviando SENSE_INTERRUPT_STATUS\n");
00528         return;
00529     }
00530 */
00531     // Obtener resultados de ejecucion 
00532 
00533     if (floppy_get_result()==ERR_TIMEOUT)
00534     {
00535         return ERR_TIMEOUT;
00536     }
00537 
00538     byte posicion=0;
00539     while ( status[posicion] != NO_VALIDO && posicion < 12)
00540     {
00541         //kprintf("Resultado Read Id%d: %x\n", (posicion), status[posicion]);
00542         posicion++;
00543     }
00544 
00545     return 1;
00546 
00547 }       
00548 
00549 
00551 // Posicionar el cabezal sobre la pista indicada
00553 
00554 byte seek (byte cara, byte pista)
00555 {
00556 
00557     // Ejecutamos un Read sector
00558     if ( ! floppy_sendbyte(SEEK) ) {    
00559         return ERR_TIMEOUT;
00560     }
00561 
00562     if ( ! floppy_sendbyte( (cara << 2) |DRIVE_0) ) {                   // HD=0 (head number) , DS0=0 DS1=0 (Drive 0)
00563         return ERR_TIMEOUT;
00564     }
00565 
00566     if ( ! floppy_sendbyte(pista) ) {                   // Cilindro
00567             return ERR_TIMEOUT;
00568     }
00569 
00570     block();
00571     
00572     // Sensamos el estado de interrupcion
00573     if ( ! floppy_sendbyte(SENSE_INTERRUPT_STATUS) ) {
00574         return ERR_TIMEOUT;
00575     }
00576 
00577     // Obtener resultados de ejecucion 
00578     if (floppy_get_result()==ERR_TIMEOUT)     {
00579         return ERR_TIMEOUT;
00580     }
00581     
00582     // Analizamos el resultado del comando 
00583     if ( ! COMMAND_OK ) {
00584         //kprintf("SEEK !!!\n");
00585         dump_states();
00586         return ERR_TIMEOUT;
00587     }
00588 
00589     return OK;
00590 }       
00591 
00592 
00593 int seek_new (byte cara, byte pista)
00594 {
00595 
00596   // Ejecutamos un Read sector
00597   if ( ! floppy_sendbyte(SEEK) ) {      
00598     return ERR_TIMEOUT;
00599   }
00600 
00601   if ( ! floppy_sendbyte( (cara << 2) |DRIVE_0) ) {                     // HD=0 (head number) , DS0=0 DS1=0 (Drive 0)
00602     return ERR_TIMEOUT;
00603   }
00604 
00605   if ( ! floppy_sendbyte(pista) ) {                     // Cilindro
00606     return ERR_TIMEOUT;
00607   }
00608 
00609   //Esperamos la interrupcion, le indicamos la nueva rutina de atencion de interrupcion
00610   func=seek_block_new;
00611 
00612   // Aca debemos agregar el timer de timeout
00613   timer_timeout = create_timer(USECONDS_TO_TICKS(TIEMPO_TIMEOUT_COMANDO), NULL, error_por_timeout, NULL);
00614 
00615         if ( getvar("debugfloppy")==1 )
00616                 kprintf("Envio de seek_new !!\n");
00617 
00618   return OK;
00619 }
00620   
00621 void seek_block_new()
00622 {
00623   // Reseteamos a func a su valor default
00624   func=NULL;
00625         
00626         if ( getvar("debugfloppy")==1 )
00627                 kprintf("Retorno de seek_block !!\n");
00628 
00629   // Eliminamos el timer de timeout
00630   clean_timer(timer_timeout);
00631 
00632   // El timer ya no existe
00633   timer_timeout = NULL;  
00634 
00635   //kprintf("Int de seek Ok !!\n");
00636     
00637   // Sensamos el estado de interrupcion
00638   if ( ! floppy_sendbyte(SENSE_INTERRUPT_STATUS) ) {
00639     //return ERR_TIMEOUT;
00640     error();
00641     return;
00642   }
00643 
00644   // Obtener resultados de ejecucion 
00645   if (floppy_get_result()==ERR_TIMEOUT)     {
00646     //return ERR_TIMEOUT;
00647     error();
00648     return;
00649   }
00650     
00651   // Analizamos el resultado del comando 
00652   if ( ! COMMAND_OK ) {
00653     dump_states();
00654     //return ERR_TIMEOUT;
00655     error();
00656     return;
00657   }
00658 
00659   //kprintf("seek_block_new: seek ok!!\n");
00660 
00661   // Pudimos calibrarlo sin problemas
00662   seek_status=1;
00663 
00664   // Si fue como resultado de un pedido de lectura o escritura
00665   if ( ACTUAL_REQUEST != NULL ) {
00666     //kprintf("seek_block_new: Volvemos a leer_escribir_new\n");
00667     leer_escribir_new();
00668   }
00669 
00670 }       
00671 
00673 // Lee un sector fisico (previamente el cabezal debe estar calibrado y posicionado)
00675 
00676 int read_sector (byte cara, byte cilindro, byte sector)
00677 {
00678 
00679     init_floppy_DMA (DMA_READ);
00680         
00681     // Ejecutamos un Read sector
00682     if ( ! floppy_sendbyte(READ_SECTOR) ) {     
00683         return ERR_TIMEOUT;
00684     }
00685 
00686     if ( ! floppy_sendbyte(DRIVE_0 | (cara << 2)) ) {                   // HD=0 (head number) , DS0=0 DS1=0 (Drive 0)
00687         return ERR_TIMEOUT;
00688     }
00689 
00690     if ( ! floppy_sendbyte(cilindro) ) {                        // Cilindro
00691         return ERR_TIMEOUT;
00692     }
00693 
00694     if ( ! floppy_sendbyte(cara) ) {                    // Cabeza
00695         return ERR_TIMEOUT;
00696     }
00697 
00698     if ( ! floppy_sendbyte(sector) ) {                  // Sector
00699         return ERR_TIMEOUT;
00700     }
00701     if ( ! floppy_sendbyte(2) ) {                       // Tamaño sector: 128 * 2^x (si x=2-->Sector=512 bytes)
00702         return ERR_TIMEOUT;
00703     }
00704     if ( ! floppy_sendbyte( SECTORES_POR_PISTA ) ) {                    // Sectores por pista
00705         return ERR_TIMEOUT;
00706     }
00707     if ( ! floppy_sendbyte(27) ) {                      // GAP: 27 para 3 1/2  ;    32 para 5 1/4
00708         return ERR_TIMEOUT;
00709     }
00710     if ( ! floppy_sendbyte(0xff) ) {                    // Data Lengh
00711         return ERR_TIMEOUT;
00712     }
00713 
00714     if ( block()!=OK )  {
00715         //kprintf("Error read sector block\n");
00716         return ERR_NEED_RESET;
00717     }
00718     
00719     // Obtener resultados de ejecucion 
00720     if (floppy_get_result()==ERR_TIMEOUT)     {
00721         return ERR_TIMEOUT;
00722     }
00723 
00724     // Analizamos el resultado del comando 
00725     if ( ! COMMAND_OK ) {
00726         dump_states();
00727         return ERR_NEED_RESET;
00728     }
00729 
00730     return OK;
00731 }       
00732 
00733 
00734 
00735 int read_sector_new (byte cara, byte cilindro, byte sector)
00736 {
00737   
00738   //kprintf("read_sector_new: inicializando Dma\n");
00739 
00740   init_floppy_DMA (DMA_READ);
00741         
00742   // Ejecutamos un Read sector
00743   if ( ! floppy_sendbyte(READ_SECTOR) ) {       
00744     return ERR_TIMEOUT;
00745   }
00746 
00747   if ( ! floppy_sendbyte(DRIVE_0 | (cara << 2)) ) {                     // HD=0 (head number) , DS0=0 DS1=0 (Drive 0)
00748     return ERR_TIMEOUT;
00749   }
00750 
00751   if ( ! floppy_sendbyte(cilindro) ) {                  // Cilindro
00752     return ERR_TIMEOUT;
00753   }
00754 
00755   if ( ! floppy_sendbyte(cara) ) {                      // Cabeza
00756     return ERR_TIMEOUT;
00757   }
00758 
00759   if ( ! floppy_sendbyte(sector) ) {                    // Sector
00760     return ERR_TIMEOUT;
00761   }
00762   
00763   if ( ! floppy_sendbyte(2) ) {                 // Tamaño sector: 128 * 2^x (si x=2-->Sector=512 bytes)
00764     return ERR_TIMEOUT;
00765   }
00766   
00767   if ( ! floppy_sendbyte( SECTORES_POR_PISTA ) ) {                      // Sectores por pista
00768     return ERR_TIMEOUT;
00769   }
00770 
00771   if ( ! floppy_sendbyte(27) ) {                        // GAP: 27 para 3 1/2  ;    32 para 5 1/4
00772     return ERR_TIMEOUT;
00773   }
00774   
00775   if ( ! floppy_sendbyte(0xff) ) {                      // Data Lengh
00776     return ERR_TIMEOUT;
00777   }
00778 
00779   //Esperamos la interrupcion, le indicamos la nueva rutina de atencion de interrupcion
00780   func=read_sector_block_new;
00781 
00782   // Aca debemos agregar el timer de timeout
00783   timer_timeout = create_timer(USECONDS_TO_TICKS(TIEMPO_TIMEOUT_COMANDO), NULL, error_por_timeout, NULL);
00784 
00785   return OK;
00786 }
00787 
00788 void read_sector_block_new()
00789 {
00790 
00791   // Reseteamos a func a su valor default
00792   func=NULL;
00793 
00794   // Eliminamos el timer de timeout
00795   clean_timer(timer_timeout);
00796 
00797   // El timer ya no existe
00798   timer_timeout = NULL;  
00799 
00800   // Obtener resultados de ejecucion 
00801   if (floppy_get_result()==ERR_TIMEOUT)     {
00802     //return ERR_TIMEOUT;
00803     error();
00804     return;
00805   }
00806 
00807   // Analizamos el resultado del comando 
00808   if ( ! COMMAND_OK )   {
00809     dump_states();
00810     //return ERR_NEED_RESET;
00811     error();
00812     return;
00813   }
00814 
00815   // Pudimos calibrarlo sin problemas
00816   rw_status=1;
00817 
00818   // Si fue como resultado de un pedido de lectura o escritura
00819   if ( ACTUAL_REQUEST != NULL )
00820     leer_escribir_new();
00821 
00822 }       
00823 
00824 
00825 char read_msr()
00826 {
00827  unsigned char msr;
00828 
00829  msr = inportb(MSR);
00830 
00831  return msr;
00832 }
00833 
00835 // block: bloquea la ejecucion del proceso que la llama hasta recibir una interrupcion de floppy
00837 
00838 static byte floppy_continuar;       // variable candado de block
00839 
00840 int block(void)
00841 {
00842     // Deshabilitamos las interrupciones        
00843     disable_irq(6);
00844 
00845     floppy_continuar=0;
00846 
00847     // TEMPORAL
00848     dword timeout=0xffffffff;   //Este timeout es momentaneo (sera reemplazado por un timer). Puede que en maquinas con
00849                                 //micro de mas de 600Mhz haya que aumentarlo... 
00850     // Las habilitamos nuevamente
00851     enable_irq(6); 
00852 
00853     // Esperamos que aparezca la interrupcion
00854     while (!floppy_continuar) {
00855         timeout--;
00856         if (!timeout)   //En caso de no haber llegado la IRQ6, salir con ERR_TIMEOUT
00857             return ERR_TIMEOUT;
00858     }
00859     
00860     return OK;
00861 }
00862 
00863 
00864 
00866 // Inicializa el controlador DMA, tanto para leer como para escribir (segun comando)
00868 
00869 void init_floppy_DMA ( byte comando )
00870 {
00871     outportb( DMA_MASK, 0x06 );
00872     // Resetear el FlipFlop del DMA para que reconozca al primer byte enviado como un LSB
00873     outportb ( 0xC, 0);
00874 
00875     // Enviar comando (DMA_READ, DMA_WRITE)
00876     outportb( DMA_CMD, comando );
00877 
00878     // Seteo de la direccion. No debera estar por encima de los 16MB
00879     outportb ( DMA_CH2_ADDR, (byte) dma_address);
00880     outportb ( DMA_CH2_ADDR, (byte) (dma_address >> 8) );
00881     outportb ( DMA_CH2_PAGE, (byte) (dma_address >> 16) );
00882 
00883     outportb ( DMA_CH2_COUNT, (byte) ( (BLOQUE_SIZE-1) & 0xff) );
00884     outportb ( DMA_CH2_COUNT, (byte) ( (BLOQUE_SIZE-1) >> 8) );
00885     outportb ( DMA_MASK, 2);
00886 }       
00887 
00888 
00889 
00890 
00892 // Acepta como operacion READ_SECTOR y WRITE_SECTOR (quiza pueda aceptar format).
00893 // Es la encargada de convertir un sector logico (o LBA) en el sector fisico (CHS) correspondiente.
00894 // Inicializa el controlador de floppy y enciende el motor. En caso de time outs, intenta hasta MAX_TRYS
00896 
00897 int leer_escribir(byte operacion, dword sector_logico, byte *buffer)
00898 {
00899     byte intentos=0;
00900     byte cara, cilindro, sector;
00901 
00902     
00903 intentar_nuevamente:    
00904     intentos++;
00905     if (intentos > MAX_FLOPPY_TRYS ) {
00906         //kprintf("No se puede leer el sector %d(superados %d intentos)\n", sector_logico, MAX_FLOPPY_TRYS);
00907         return ERR_MAX_TRYS;
00908     }
00909         
00910 
00911     if (motor_status==0) {
00912         init_floppy();
00913         motor_on();
00914     }
00915 
00916     
00917     if (floppy_calibrado==0)
00918         if ( recalibrate()!=OK )
00919             goto intentar_nuevamente;
00920 
00921     
00922     //Calcular el sector fisico (CHS) a traves del sector logico (LBA)
00923     cara = (sector_logico / SECTORES_POR_PISTA) % CARAS_POR_PISTA;
00924     cilindro = (sector_logico / SECTORES_POR_PISTA) /CARAS_POR_PISTA;
00925     sector = (sector_logico % SECTORES_POR_PISTA) + 1;
00926 
00927     // Esto no deberia ser necesario ya que configuramos el controlador con EIS (Implied Seek) 
00928     if ( seek(cara, cilindro) != OK) {
00929             goto intentar_nuevamente;
00930     }
00931   
00932     if (operacion == READ_SECTOR) {
00933         if ( leer_sec(cara, cilindro, sector, buffer)!=OK )
00934             goto intentar_nuevamente;
00935         return OK;
00936     }
00937 
00938     //No implementado
00939     if (operacion == WRITE_SECTOR)
00940                 return OK;
00941         else return -1;
00942 }       
00943 
00944 
00945 // Nueva funcion
00946 //
00947 // El proceso de lectura implica los siguientes pasos:
00948 //
00949 // 1. Encender el motor (si fuese necesario)
00950 //
00951 //      a. Setear el bit del motor correspondiente en el registro DOR
00952 //      b. Esperar 500 mseg aproximadamente de modo que se estabilice
00953 //         la velocidad de giro del motor
00954 //
00955 // 2. Recalibracion (si fuese necesario)
00956 //
00957 //      a. Enviar comando
00958 //      b. Esperar interrupcion
00959 //
00960 // 3. Seek en la cabeza, cilindro y sector correspondiente
00961 //
00962 //      a. Enviar comando
00963 //      b. Esperar interrupcion
00964 //
00965 // 4. Lectura del sector
00966 //
00967 //      a. Enviar comando
00968 //      b. Esperar interrupcion
00969 //
00970 // Bien, el problema ppal es que si uso el modelo tipo:
00971 //
00972 //  * envio comando
00973 //  * cambio el puntero de interrupcion de floppy
00974 //
00975 // se desestructura el codigo y pierdo las variables locales.
00976 //
00977 // Por ejemplo, en la funcion de lectura al llamar a la funcion de SEEK, 
00978 // se pierde la memoria de la funcion previa (lectura).
00979 //
00981 //
00982 // La primer solucion propuesta es la siguiente:
00983 //
00984 // Se guardará como un puntero la funcion base de ejecucion, en el ejemplo anterior sera
00985 // la de lectura, en el proceso de lectura se realizara:
00986 //
00987 // 1. El motor esta encendido ?
00988 //      NO: ejecutar motor_on()
00989 //
00990 // Si no estaba encendido, motor_on se ejecutara y devolver el control al kernel mientras espera
00991 // que se venza el timer de 500 mseg, la funcion de retorno de motor_on() establecera la variable
00992 // global motor_status como encendida y llamara nuevamente a la funcion de lectura, quien ahora
00993 // realizara los siguientes pasos:
00994 //
00995 // 1. El motor esta encendido ?
00996 //      SI: seguimos
00997 //      
00998 // 2. Esta Recalibrado ?
00999 //      NO: llamamos a recalibrate
01000 //
01001 // y el proceso continua de la misma forma
01002 //
01004 
01005 //int leer_escribir_new(byte operacion, dword sector_logico, byte *buffer)
01006 // Toma todos los argumentos necesarios de la variable global ACTUAL_REQUEST
01007 void leer_escribir_new()
01008 {
01009   byte cara, cilindro, sector;
01010   int cmdret;
01011 
01012   
01013         if ( getvar("debugfloppy")==1 )
01014                 kprintf("leer_escribir_new: motor=%d calibracion=%d\n",motor_status,floppy_calibrado);  
01015 
01016   // Motor apagado ?
01017   if (motor_status==MOTOR_OFF) {
01018                 if ( getvar("debugfloppy")==1 )
01019             kprintf("leer_escribir_new: Motor apagado, encendiendo\n");
01020     motor_on_new();
01021     return;
01022   }
01023 
01024   // Verificamos si existe un timer de apagado
01025   else if (timer_motor!=NULL) {
01026 
01027                 // Debemos eliminarlo
01028                 clean_timer(timer_motor);
01029 
01030     // No existe mas
01031     timer_motor = NULL;
01032 
01033         }
01034 
01035   if ( ! floppy_calibrado ) {
01036                 //kprintf("leer_escribir_new: Calibrando\n");
01037 
01038                 // Comando enviado oks?
01039                 if ( (cmdret=recalibrate_new()) == OK ) {
01040                  return;
01041                 }
01042 
01043                 // Retornamos el error
01044                 else {
01045                  error();
01046                  return;
01047                 }
01048         
01049   }
01050 
01051     
01052   //Calcular el sector fisico (CHS) a traves del sector logico (LBA)
01053   cara = (DRIVER_REQUEST_SECTOR(ACTUAL_REQUEST) / SECTORES_POR_PISTA) % CARAS_POR_PISTA;
01054   cilindro = (DRIVER_REQUEST_SECTOR(ACTUAL_REQUEST) / SECTORES_POR_PISTA) /CARAS_POR_PISTA;
01055   sector = (DRIVER_REQUEST_SECTOR(ACTUAL_REQUEST) % SECTORES_POR_PISTA) + 1;
01056 
01057         if ( getvar("debugfloppy")==1 )
01058         kprintf("leer_escribir: sector logico=%d ==> h=%d c=%d s=%d\n", DRIVER_REQUEST_SECTOR(ACTUAL_REQUEST), \
01059                                                                                                                                                                                                                                                                         cara, cilindro, sector);
01060   
01061   // Esto no deberia ser necesario ya que configuramos el controlador con EIS (Implied Seek) 
01062   if ( ! seek_status ) {
01063     //kprintf("leer_escribir_new: Posicionando (Seeking)\n");
01064 
01065                 // Comando enviado oks?
01066                 if ( (cmdret=seek_new(cara, cilindro)) == OK )
01067                         return;
01068 
01069           // Retornamos el error
01070                 else {
01071                         error();
01072                         return;
01073                 }
01074   }
01075   
01076   if ( DRIVER_REQUEST_OPERATION(ACTUAL_REQUEST) == IOREAD ) {
01077 
01078                 if ( getvar("debugfloppy")==1 )
01079                         kprintf("leer_escribir_new: Leyendo\n");
01080 
01081                 // Todavia no fue hecha la lectura
01082     if ( ! rw_status ) {
01083 
01084                         // Comando enviado oks?
01085                         if ( (cmdret=read_sector_new(cara, cilindro, sector)) == OK )
01086                                 return;
01087 
01088                         // Retornamos el error
01089                         else {
01090                                 error();
01091                                 return;
01092                         }
01093 
01094         
01095                 }
01096 
01097                 // Hicimos la lectura en un paso previo, veamos que resulto
01098                 else {
01099                         //kprintf("leer_escribir_new: Fase de lectura terminada, copiando al buffer\n");
01100 
01101                         word i;
01102 
01103                         byte *dma_block = (byte *) dma_address;
01104                         byte *buffer = DRIVER_REQUEST_BUFFER(ACTUAL_REQUEST);
01105 
01106                         for(i=0 ; i < BLOQUE_SIZE ; i++) 
01107                                 *buffer++ = *dma_block++;
01108 
01109                         // Oks, ya hicimos todo, resta colocar ok en el retorno del buffer block,       
01110                         // marcarlo como hecho, despertar a la tarea que genero todo esto y
01111                         // colocar un timer de apagado de motor
01112                         floppy_calibrado=0;
01113                         seek_status=0;
01114                         rw_status=0;
01115 
01116                         //  Bloque leido correctamente
01117                         DRIVER_REQUEST_RETURN(ACTUAL_REQUEST) = 1;
01118 
01119                 }
01120       
01121         }
01122 
01123         //No implementado
01124         else if ( DRIVER_REQUEST_OPERATION(ACTUAL_REQUEST) == IOWRITE ) {
01125                 //kprintf("WRITE: operacion no permitida\n");
01126   }
01127 
01128         // Indicamos al cache que terminamos nuestra operatoria
01129         endrequest(ACTUAL_REQUEST);
01130 
01131         // Liberamos al floppy
01132         ACTUAL_REQUEST=NULL;
01133         
01134         // En algunos segundos apagamos el motor
01135   timer_motor = create_timer(USECONDS_TO_TICKS(TIEMPO_APAGADO_MOTOR_POR_INACTIVIDAD), NULL, motor_off_new, NULL);
01136 
01137   return;
01138     
01139 }
01140 
01141 // Esta funcion es llamada si se vencio el tiempo de espera de interrupcion
01142 void error_por_timeout()
01143 {
01144   
01145   // El timer ya no existe
01146   timer_timeout = NULL;  
01147 
01148   // llamamos a la rutina de error
01149   error();
01150   
01151 }
01152 
01153 // Algun error, debemos actualizar el bloque indicando dicho error
01154 void error()
01155 {
01156 
01157   // Oks, hubo un error, resta colocarlo en el retorno del buffer block,
01158   // marcarlo como hecho, despertar a la tarea que genero todo esto y
01159   // colocar un timer de apagado de motor
01160   DRIVER_REQUEST_RETURN(ACTUAL_REQUEST) = -1;
01161         
01162   floppy_calibrado=0;
01163   seek_status=0;
01164   rw_status=0;
01165 
01166   // Liberamos al floppy
01167   ACTUAL_REQUEST=NULL;
01168         
01169         // Indicamos al cache que terminamos nuestra operatoria
01170         endrequest(ACTUAL_REQUEST);
01171 
01172   // En algunos segundos apagamos el motor
01173   timer_motor = create_timer(USECONDS_TO_TICKS(TIEMPO_APAGADO_MOTOR_POR_INACTIVIDAD), NULL, motor_off_new, NULL);
01174 
01175 }
01176 
01177 int leer_sec(byte cara, byte cilindro, byte sector , byte *buffer)
01178 {
01179     if ( read_sector(cara, cilindro , sector)!=OK )
01180         return ERR_NEED_RESET;
01181     
01182     word i;
01183 
01184     byte *dma_block = (byte *) dma_address;
01185     for( i=0 ; i < BLOQUE_SIZE ; i++) 
01186         *buffer++ = *dma_block++;
01187 
01188     return OK;
01189 }
01190 
01191 void dump_states()
01192 {
01193   int posicion;
01194 
01195   for (posicion=0; (posicion<sizeof(status)) && (status[posicion]!=NO_VALIDO); posicion++ )
01196     dump_status_register(posicion, status[posicion]);
01197 
01198 
01199 }
01200 
01201 
01202 static char *ic_codes[] = { "Terminacion Normal", "Terminacion erronea",
01203                             "Comando invalido"  , "Terminacion erronea causada por polling" };
01204 
01205 void dump_status_register(int numero, byte valor)
01206 {
01207   switch(numero) {
01208 
01209     // ST0 : 7-6:IC, 5:SE, 4:EC, 3:nada, 2:H, 1-0:DS
01210     case 0:
01211             //kprintf("ST0: 0x%x - ",valor);
01212             //kprintf(" IC = 0x%x (%s)\n", (valor&0xc0) >> 6, ic_codes[ (valor&0xc0) >> 6 ]);
01213             //kprintf(" SE = 0x%x (Seek end %s)\n", (valor&0x20)>>5, ( ( (valor&0x20) >> 5) == 0 ? "erroneo" : "ok") );
01214             //kprintf(" EC = 0x%x (Equipment Check)\n", (valor&0x10)>>4);
01215             //kprintf("  H = 0x%x (Head Address)\n", (valor&0x4)>>2);
01216             //kprintf(" DS = 0x%x (Drive Select)\n", valor&0x3);
01217             break;
01218  
01219     case 1:
01220             puts("ST1:");
01221             //kprintf(" EN = 0x%x (End of cylinder)\n", (valor&0x80)>>7);
01222             //kprintf(" DE = 0x%x (Data error - CRC)\n", (valor&0x20)>>5);
01223             //kprintf(" OR = 0x%x (Overrun / Underrun)\n", (valor&0x10)>>4);
01224             //kprintf(" ND = 0x%x (No Data)\n", (valor&0x4)>>2);
01225             //kprintf(" NW = 0x%x (Not Writable)\n", (valor&0x2)>>1);
01226             //kprintf(" MA = 0x%x (Missing Address Mark)\n", valor&0x1);
01227             break;
01228 
01229     case 2:
01230             puts("ST2:");
01231             //kprintf(" CM = 0x%x (Control Mark)\n", (valor&0x40)>>6);
01232             //kprintf(" DD = 0x%x (Data Error in data field)\n", (valor&0x20)>>5);
01233             //kprintf(" WC = 0x%x (Wrong Cylinder)\n", (valor&0x10)>>4);
01234             //kprintf(" BC = 0x%x (Bad cylinder)\n", (valor&0x2)>>1);
01235             //kprintf(" MD = 0x%x (Missing data address mark)\n", valor&0x1);
01236             break;
01237 
01238     case 3:
01239             puts("ST3:");
01240             //kprintf(" WP = 0x%x (Write Protect)\n", (valor&0x40)>>6);
01241             //kprintf(" T0 = 0x%x (Track 0)\n", (valor&0x10)>>4);
01242             //kprintf(" HD = 0x%x (Head Address)\n", (valor&0x4)>>2);
01243             //kprintf(" DS = 0x%x (Drive Select)\n", valor&0x3);
01244             break;
01245             
01246 
01247 
01248   }
01249 
01250 
01251 }
01252 
01253 
01254 
01255 // Rutinas de atencion de interrupcion
01256 
01257 // Bloqueo
01258 void Floppy (void)
01259 {
01260     // Fin de interrupcion
01261     endOfInterrupt();
01262 
01263     // Forma vieja
01264     if ( func == NULL ) {
01265       floppy_continuar=1;
01266     }
01267             
01268     // Forma nueva
01269     else {
01270       (*func)();
01271     }
01272     
01273 }       
01274 
01275 
01276 // Procesa los pedidos en el buffer cache
01277 void floppy_procesar_buffer(void)
01278 {
01279 
01280   // Estamos procesando algun otro pedido ?
01281   if ( ACTUAL_REQUEST != NULL )
01282     return;
01283 
01284   
01285   // Oks, veamos si hay algun pedido para nosotros
01286   if ( (ACTUAL_REQUEST=getrequest(fd0)) == NULL )
01287                 return;
01288 
01289   //kprintf("\nHay un bloque nuevo para procesar: 0x%x !!!\n",ACTUAL_REQUEST);
01290 
01291   leer_escribir_new();
01292 }

Generated on Sun May 30 18:38:34 2004 for Routix OS by doxygen 1.3.6