[Kos-dev] Few questions about CHS and LBA

kos-dev@enix.org kos-dev@enix.org
05 Feb 2002 08:45:28 +0100


--=-=-=

Hi,

Again me with a few questions concerning CHS and LBA.

1) There's seems to be two CHS configuration for a hard drive. A
   Physical CHS configuration (used by the ATA device, where head<15,
   cylinder up to 65536, and up to 63 sectors/track). And a logical
   CHS configuration, which can be found in the values returned by a
   IDENTIFY DRIVE command. 
   For instance on my harddirve (a Quantum 810Mb), I have the
   following configurations :
        - Logicial : 822 cylinders, 32 heads, 63 sectors/track
        - Physical : 1644 cylinders, 16 heads, 63 sectors/track
   At the beginning of my test, I tried to directly address the disk
   using the Logical CHS configuration, but that's not possible :
   there's 32 heads, and the space for Head is 4 bit (in the
   register). So I looked at my drive and saw the Physical CHS
   configuration. ANd it worked. But now THE QUESTION : how can I
   detect this Physical CHS configuration ?
   On this drive, the conversion is pretty easy (too much head =>
   multiply the number of cylinders), but on other harddrives ? For
   instance I can see a harddrive which is 1010/16/51 (51
   sectors/track). How can I know that without looking directly inside
   the computer.
   In some documentations I saw it is not possible to get this
   information without calling INT 13 (which actually uses Physical
   CHS translation for adressing the disk, and can returns this
   configuration).
   I'm sure you're doing in an other way. But I looked at the code,
   and couldn't find anything about it.

2) My second question is about LBA. On my Quantum 810 Mb, LBA seems to
   be present : it's configured in the BIOS, and the information
   returned by the IDENTIFY DRIVE Command says that LBA is activated.
   But when I try the following piece of code :

for(i = 1; i < 1002; i++)
{
  memset(buffer2, 0xBB, 512);
if(add_ide_op_polled_mode(harddisk, /* the harddrive */
                          READ,     /* type of operation */
                          (i>>8)&0xffff, /* cylinder */
                          ((i>>24)&0xf)|0x40, /* head | 0x40 (LBA) */
                          i&0xff, /* sector number */
                          buffer2) < 0)
    break;
}

   It fails for sector 64. So just the sector after the sectors/track
   limit, just as if I had to increment head by one. But this
   harddrive should be LBA compliant (and says it is !). I activate
   LBA, and use this mode, but nothing works !

   For a long time, I thought my code was very wrong. So I tried on a
   more recent PC : a laptop (Fujitsu). And this code worked. It
   didn't failed at reading the 1001 first sectors using LBA
   addressing.

   So what's the deal ? It is possible to have a harddrive which
   claims to be LBA Compliant, and which is not LBA compliant ? That
   would sucks a lot !

3) Last question, for the detection of hard drives and CD-ROMs I used
   your code taken from FreeBSD. It works fine on every machine I
   tried it, except onmy laptop. On my laptop there's a CD-ROM on hdc
   (secondary master), and your code detects it on Secondary Master
   AND on Secondary Slave.

   So it seems that there's something to do in this code :

   /* check what is the type of the device */
   outb(ATA_D_IBM | ATA_MASTER, ctrl->ioaddr + ATA_DRIVE);
   usleep(10);
  
   if(inb(ctrl->ioaddr + ATA_CYL_LSB) == ATAPI_MAGIC_LSB &&
      inb(ctrl->ioaddr + ATA_CYL_MSB) == ATAPI_MAGIC_MSB)
     {
       ctrl->devices |= ATA_ATAPI_MASTER;
     }
  
   /* MAYBE WE SHOULD DO SOMETHING HERE TO RESET THE REGISTER TO
   ANOTHER VALUE ? (0 for instance). So I suggest :
            outb(0, ctrl->ioaddr + ATA_CYL_LSB);
            outb(0, ctrl->ioaddr + ATA_CYL_MSB); */
   outb(ATA_D_IBM | ATA_SLAVE, ctrl->ioaddr + ATA_DRIVE);
   usleep(10);
  
   if(inb(ctrl->ioaddr + ATA_CYL_LSB) == ATAPI_MAGIC_LSB &&
      inb(ctrl->ioaddr + ATA_CYL_MSB) == ATAPI_MAGIC_MSB)
     {
       ctrl->devices |= ATA_ATAPI_SLAVE;
     }

   What do you think about it ?
       
Well if you want to look at my code more precisely, I included it in
this mail. It's pretty ugly in some places because it's in heavy
development.

The loop test used to test LBA is in get_partition_table. And the
function used to read is add_ide_op_polled_mode. I don't use
add_ide_op_with_irq for the moment (I don't want to care about locking
and so on).

Thank for all your help

Thomas
--=-=-=
Content-Type: application/octet-stream
Content-Disposition: attachment; filename=_ide.c

#include <kos/asm.h>
#include <lib/stdio.h>
#include <scheduler/scheduler.h>
#include <idt/irq.h>
#include <ide/_ide.h>
#include <liblist/liblist.h>
#include <kos/spinlock.h>
#include <lib/string.h>
#include <kmem/kmem.h>


#define ATA_MASTER                      0x00
#define ATA_SLAVE                       0x10

/* Registers */
#define ATA_DATA                        0x00    /* Data register */

#define ATA_ERROR                       0x01    /* (R) error register */

#define ATA_PRECOMP                     0x01    /* (W) precompensation */

#define ATA_SECTOR_COUNT                0x02    /* sector count register */

#define ATA_SECTOR_NUMBER               0x03    /* sector number register */

#define ATA_CYL_LSB                     0x04    /* cylinder# LSB */

#define ATA_CYL_MSB                     0x05    /* cylinder# MSB */

#define ATA_DRIVE                       0x06
#define         ATA_D_IBM               0xa0

#define ATA_STATUS                      0x07    /* status register */
#define         ATA_S_ERROR             0x01    /* error */
#define         ATA_S_INDEX             0x02    /* index */
#define         ATA_S_CORR              0x04    /* data corrected */
#define         ATA_S_DRQ               0x08    /* data request */
#define         ATA_S_DSC               0x10    /* drive Seek Completed */
#define         ATA_S_DWF               0x20    /* drive write fault */
#define         ATA_S_DRDY              0x40    /* drive ready */
#define         ATA_S_BSY               0x80    /* busy */

#define ATA_CMD                         0x07    /* command register */
#define         ATA_C_ATA_IDENTIFY      0xec    /* get ATA params */
#define         ATA_C_ATAPI_IDENTIFY    0xa1    /* get ATAPI params*/
#define         ATA_C_READ              0x20    /* read command */
#define         ATA_C_WRITE             0x30    /* write command */
#define         ATA_C_READ_MULTI        0xc4    /* read multi command */
#define         ATA_C_WRITE_MULTI       0xc5    /* write multi command */
#define         ATA_C_SET_MULTI         0xc6    /* set multi size command */
#define         ATA_C_PACKET_CMD        0xa0    /* set multi size command */

#define ATA_ALTPORT                     0x206   /* alternate Status register */

#define ATA_DEVICE_CONTROL               0x206
#define         ATA_A_nIEN              0x02    /* disable interrupts */
#define         ATA_A_RESET             0x04    /* RESET controller */
#define         ATA_A_4BIT              0x08    /* 4 head bits */


/* Devices types */
#define ATA_ATA_MASTER                  0x01
#define ATA_ATA_SLAVE                   0x02
#define ATA_ATAPI_MASTER                0x04
#define ATA_ATAPI_SLAVE                 0x08

#define ATAPI_MAGIC_LSB                 0x14
#define ATAPI_MAGIC_MSB                 0xeb

typedef struct partition_entry 
{
  k_ui8_t active;
  k_ui8_t start_dl;
  k_ui16_t start_cylinder;
  k_ui8_t type;
  k_ui8_t end_dl;
  k_ui16_t end_cylinder;
  k_ui32_t lba;
  k_ui32_t size;
} partition_entry_t;

#define PRIMARY_CONTROLLER 0
#define SECONDARY_CONTROLLER 1
#define MASTER 0
#define SLAVE 1
#define NB_CONTROLLERS 2

typedef struct partition
{
  enum { PRIMARY, EXTENDED } type;
  enum { ACTIVE, NOT_ACTIVE } is_active;
  k_ui8_t  fs_type;
  k_ui8_t  start_dl;
  k_ui16_t start_cylinder;
  k_ui8_t  end_dl;
  k_ui16_t end_cylinder;
  k_ui32_t lba;
  k_ui32_t size;
  int      number;

  struct partition *next;
} partition_t;


typedef struct controller
{
  k_ui16_t ioaddr;
  k_ui16_t irq;
  enum { ATA_NOT_PRESENT, ATA_IDLE, ATA_WAIT_INTR } state;
  int ctrl;
  int devices;
  void *device[2];
} controller_t;

typedef struct harddisk
{
  k_ui16_t general_configuration_info;
  k_ui16_t logical_cylinder_nb;
  k_ui16_t logical_head_nb;
  k_ui16_t unformatted_bytes_per_track;
  k_ui16_t unformatted_bytes_per_sector;
  k_ui16_t logical_sector_per_track;
  k_ui16_t vendor;
  k_ui16_t controller_type;
  k_ui16_t buffer_size;
  k_ui32_t lba_capacity;
  char serial_number[21];
  char firmware_revision[9];
  char model_number[41];
  controller_t *ctrl;
  int size;
  int device;
  partition_t *partition_list;
} harddisk_t;

typedef struct cdrom
{
  controller_t *ctrl;
} cdrom_t;

typedef struct ide_op
{
  enum { READ, WRITE } type;
  enum { IDE_OP_WAITING, IDE_OP_IN_PROGRESS } status;
  harddisk_t *harddisk;
  int cyl;
  int sector;
  int head;
  char *buffer;
  struct ide_op *next, *prev;
} ide_op_t;

ide_op_t *ide_op_list;




controller_t controllers[NB_CONTROLLERS] =
{
  { 0x1F0, 14, ATA_NOT_PRESENT, PRIMARY_CONTROLLER, 0, { NULL, NULL }},
  { 0x170, 15, ATA_NOT_PRESENT, SECONDARY_CONTROLLER, 0, { NULL, NULL }}
};

static int init_ide(controller_t *ctrl)
{
  int status0, status1;
  int mask = 0;
  int timeout;

  outb(ATA_D_IBM | ATA_MASTER, ctrl->ioaddr + ATA_DRIVE);
  usleep(1);
  status0 = inb(ctrl->ioaddr + ATA_STATUS);
  
  outb(ATA_D_IBM | ATA_SLAVE, ctrl->ioaddr + ATA_DRIVE);
  usleep(1);
  status1 = inb(ctrl->ioaddr + ATA_STATUS);
  
  if((status0 & 0xf8) != 0xf8)
    mask |= 0x01;
  if((status1 & 0xf8) != 0xf8)
    mask |= 0x02;

  /* If both BSY bit are set => leave */
  if((status0 & ATA_S_BSY) && (status1 & ATA_S_BSY))
    return 0;

  /* no device present */
  if(!mask)
    return 0;
  
  /* select the master */
  outb(ATA_D_IBM | ATA_MASTER, ctrl->ioaddr + ATA_DRIVE);
  usleep(1);
  /* send reset */
  outb(ATA_A_nIEN | ATA_A_RESET, ctrl->ioaddr + ATA_ALTPORT);
  usleep(1000);
  outb(ATA_A_nIEN, ctrl->ioaddr + ATA_ALTPORT);
  usleep(1000);
  inb(ctrl->ioaddr + ATA_ERROR);
  outb(ATA_A_4BIT, ctrl->ioaddr + ATA_ALTPORT);
  usleep(1);
  
  /* wait busy */
  for(timeout = 0; timeout < 300000; timeout++)
    {
      /* select master and get status register */
      outb(ATA_D_IBM | ATA_MASTER, ctrl->ioaddr + ATA_DRIVE);
      usleep(1);
      status0 = inb(ctrl->ioaddr + ATA_STATUS);
      
      /* select slave and get status register */
      outb(ATA_D_IBM | ATA_SLAVE, ctrl->ioaddr + ATA_DRIVE);
      usleep(1);
      status1 = inb(ctrl->ioaddr + ATA_STATUS);
      
      if(mask == 0x01)
	if(!(status0 & ATA_S_BSY))
	  break;
      if(mask == 0x02)
	if(!(status1 & ATA_S_BSY))
	  break;
      if(mask == 0x03)
	if(!(status0 & ATA_S_BSY) && !(status1 & ATA_S_BSY))
	  break;
      usleep(100);
    }
  if(status0 & ATA_S_BSY)
    mask &= ~0x01;
  if(status1 & ATA_S_BSY)
    mask &= ~0x02;
  
  /* no device */
  if(!mask)
    return 0;

  /* there's at least one device, initialize state */
  ctrl->state = ATA_IDLE;
  
  /* check what is the type of the device */
  outb(ATA_D_IBM | ATA_MASTER, ctrl->ioaddr + ATA_DRIVE);
  usleep(10);
  
  if(inb(ctrl->ioaddr + ATA_CYL_LSB) == ATAPI_MAGIC_LSB &&
     inb(ctrl->ioaddr + ATA_CYL_MSB) == ATAPI_MAGIC_MSB)
    {
      ctrl->devices |= ATA_ATAPI_MASTER;
    }
  
  outb(ATA_D_IBM | ATA_SLAVE, ctrl->ioaddr + ATA_DRIVE);
  usleep(10);
  
  if(inb(ctrl->ioaddr + ATA_CYL_LSB) == ATAPI_MAGIC_LSB &&
     inb(ctrl->ioaddr + ATA_CYL_MSB) == ATAPI_MAGIC_MSB)
    {
      ctrl->devices |= ATA_ATAPI_SLAVE;
    }

  if(status0 != 0x00 && !(ctrl->devices & ATA_ATAPI_MASTER))
    {
      outb(ATA_D_IBM | ATA_MASTER, ctrl->ioaddr + ATA_DRIVE);
      usleep(1);
      outb(0x58, ctrl->ioaddr + ATA_ERROR);
      outb(0xa5, ctrl->ioaddr + ATA_CYL_LSB);
      if(inb(ctrl->ioaddr + ATA_ERROR) != 0x58 &&
	 inb(ctrl->ioaddr + ATA_CYL_LSB) == 0xa5)
	{
	  ctrl->devices |= ATA_ATA_MASTER;
	}
    }
  
  if(status1 != 0x00 && !(ctrl->devices & ATA_ATAPI_SLAVE))
    {
      outb(ATA_D_IBM | ATA_SLAVE, ctrl->ioaddr + ATA_DRIVE);
      usleep(1);
      outb(0x58, ctrl->ioaddr + ATA_ERROR);
      outb(0xa5, ctrl->ioaddr + ATA_CYL_LSB);
      if(inb(ctrl->ioaddr + ATA_ERROR) != 0x58 &&
	 inb(ctrl->ioaddr + ATA_CYL_LSB) == 0xa5)
	{
	  ctrl->devices |= ATA_ATA_SLAVE;
	}
    }
  
  return 0;
}

static int convert_to_ascii(char *src, char *dst, int len)
{
  int i;
  
  for(i = 0; i < len; i=i+2)
    {
      dst[i] = (src[i+1] & 0xff);
      dst[i+1] = (src[i] & 0xff);
    }

  dst[len] = '\0';
  for(i = len; i > 0; i--)
    {
      if(dst[i] == 0)
	continue;
      else if(dst[i] == ' ')
	dst[i] = '\0';
      else
	break;
    }
  
  return 0;
}




/* Will be used for IRQ mode */
static int do_op_first_step(ide_op_t *op)
{
  controller_t *ctrl;

  ctrl = op->harddisk->ctrl;
  ctrl->state = ATA_WAIT_INTR;

  outb(ATA_A_4BIT, ctrl->ioaddr + ATA_ALTPORT);

  /* select drive */
  outb(ATA_D_IBM 
       | (op->harddisk->device == MASTER) ? ATA_MASTER : ATA_SLAVE
       | op->head, 
       ctrl->ioaddr + ATA_DRIVE);
  usleep(1);
  
  outb(1, ctrl->ioaddr + ATA_SECTOR_COUNT);
  outb(op->sector, ctrl->ioaddr + ATA_SECTOR_NUMBER);
  outb((op->cyl & 0xff), ctrl->ioaddr + ATA_CYL_LSB);
  outb(((op->cyl & 0xff00) >> 8), ctrl->ioaddr + ATA_CYL_MSB);

  /* FOR THE MOMENT WE DON'T CARE ABOUT THE OPERATION TYPE ... ALWAYS
     READ ... */
  op->status = IDE_OP_IN_PROGRESS;
  outb(ATA_C_READ, ctrl->ioaddr + ATA_CMD);

  return 0;
}


static int add_ide_op_with_irq(harddisk_t *harddisk, int type, int cyl, int head, int sector, char *buffer)
{
  ide_op_t *new;

  new = kmalloc(sizeof(ide_op_t));
  if(new == NULL)
    {
      printk("Memory allocation error\n");
      return -1;
    }

  if(type != READ && type != WRITE)
    return -1;

  new->status = IDE_OP_WAITING;
  new->harddisk = harddisk;
  new->cyl = cyl;
  new->sector = sector;
  new->head = head;
  new->buffer = buffer;
  new->type = type;
  
  list_add_tail(ide_op_list, new);
  
  if(harddisk->ctrl->state == ATA_IDLE)
    do_op_first_step(new);

  return 0;
}

static int add_ide_op_polled_mode(harddisk_t *harddisk, int type, 
				  k_ui16_t cyl, k_ui8_t head, k_ui8_t sector, char *buffer)
{
  int timeout, status = 0;
  int i, tmp;
  controller_t *ctrl = harddisk->ctrl;

  if(type != READ && type != WRITE)
    {
      printk("Unknown type of operation\n");
      return -1;
    }

  ctrl->state = ATA_IDLE;

  for(timeout = 0; timeout < 30000; timeout++)
    {
      status = inb(ctrl->ioaddr + ATA_STATUS);
      if(!(status & ATA_S_BSY))
	break;
      
      usleep(1);
    }

  outb(ATA_A_nIEN | ATA_A_4BIT, ctrl->ioaddr + ATA_ALTPORT);

  printk("Cyl low 0x%x, cyl high 0x%x, head 0x%x sector 0x%x\n",
	 cyl & 0xff, (cyl >> 8) & 0xff, head, sector);
  outb(0, ctrl->ioaddr + ATA_PRECOMP);
  outb(1, ctrl->ioaddr + ATA_SECTOR_COUNT);
  outb(sector, ctrl->ioaddr + ATA_SECTOR_NUMBER);
  outb(cyl & 0xff, ctrl->ioaddr + ATA_CYL_LSB);
  outb((cyl & 0xff00) >> 8, ctrl->ioaddr + ATA_CYL_MSB);
  /* select drive */
  outb(ATA_D_IBM 
       | (harddisk->device == MASTER) ? ATA_MASTER : ATA_SLAVE
       | head, 
       ctrl->ioaddr + ATA_DRIVE);

  /* FOR THE MOMENT WE DON'T CARE ABOUT THE OPERATION TYPE ... ALWAYS
     READ ... */
  outb(ATA_C_READ, ctrl->ioaddr + ATA_CMD);

  for(timeout = 0; timeout < 30000; timeout++)
    {
      status = inb(ctrl->ioaddr + ATA_STATUS);
      if(!(status & ATA_S_BSY))
	break;
      
      usleep(1);
    }

  if(!(status & ATA_S_DRQ))
    {
      printk("Error (0x%x)\n", inb(ctrl->ioaddr + ATA_ERROR));
      return -1;
    }
  
  for(i = 0; i < 512; i++)
    {
      tmp = inw(ctrl->ioaddr);
      buffer[i] = (tmp & 0xff);      
      buffer[++i] = (tmp & 0xff00) >> 8;
    }

  return 0;
}

static int get_partition_table (harddisk_t *harddisk)
{
  int i,j,k;
  partition_entry_t *p;
  char c;
  int sectnum;
  k_ui8_t buffer[512];
  k_ui8_t buffer2[512];

  add_ide_op_polled_mode(harddisk, READ, 0, 0, 1, buffer);

  switch(harddisk->ctrl->ctrl)
    {
    case PRIMARY_CONTROLLER:
      c = 'a';
      break;
    case SECONDARY_CONTROLLER:
      c = 'c';
      break;
    default:
      printk("Unknown controller\n");
      return -1;
    }

  for (p = (partition_entry_t *) (buffer+446), i=0; 
       i < 4; 
       p++, i++)
    {
      if (p->size == 0)
	continue;

      printk("hd%c%d : ", (harddisk->device == MASTER) ? c : c+1, i+1);
      printk("type=");
      
      switch(p->type)
	{
	case 0xc:
	  printk("FAT32 ");
	  break;
	case 0xe:
	  printk("FAT16 ");
	  break;
	case 0x82:
	  printk("Linux Swap ");
	  break;
	case 0x83:
	  printk("Linux Native ");
	  break;
	case 0x5:
	  printk("Extended ");
	  printk("start_sector = %d, start_cylinder = %d (0x%x) (%d)\n", 
		 (p->start_cylinder & 0x3f), 
		 ((p->start_cylinder & 0xff00) >> 8) | ((p->start_cylinder & 0xc0) << 2),
		 p->start_cylinder,
		 p->start_dl);
	  /*
	  for (i = (((p->start_cylinder & 0xff00) >> 8) | ((p->start_cylinder & 0xc0) << 2))-5;
	       i < (((p->start_cylinder & 0xff00) >> 8) | ((p->start_cylinder & 0xc0) << 2))+5;
	       i++)
	  */
	  memset(buffer2, 0xBB, 512);
	  add_ide_op_polled_mode(harddisk, READ, 
				 970,
				 /* (p->start_dl & 0xf) */ 0,
				 1,
				 buffer2);
	  for(i = 446; i < 446+32; i++)
	    printk("%x ", buffer2[i]);
	  printk("end : %x %x\n", buffer2[510], buffer2[511]);

	  for(i = 1; i < 1002; i++)
	    {
	      memset(buffer2, 0xBB, 512);
	      if(add_ide_op_polled_mode(harddisk, READ, (i>>8)&0xffff,((i>>24)&0xf)|0x40,i&0xff,buffer2) < 0)
		break;
	    }
	  printk("failure noticed at sector %d\n", i);
	  
	      //	      for(i = 446; i < 446+32; i++)
	      //printk("%x ", buffer2[i]);
	      //	  printk("end : %x %x\n", buffer2[510], buffer2[511]);
	  

	  
	      //	      printk("(%d) END : %x %x || ", i, buffer2[510], buffer2[511]);
	  break;
	default:
	  printk("N/A ");
	}

      printk("size=%dM", (p->size)>>11);
      printk("\n");
      
    }
  
  return 0;
}


/* this function set the command "Identify Drive". For this command,
   we don't wait for an IRQ, we just wait for BSY bit to be
   cleared. (polled mode) */

static int get_drv_infos(controller_t *ctrl, int device)
{ 
  int timeout, status=0;
  harddisk_t *harddisk;
  k_ui16_t buffer[256];
  int i;

  /* On met nIEN a 1 dans device control */
  outb(ATA_A_nIEN | ATA_A_4BIT, ctrl->ioaddr + ATA_DEVICE_CONTROL);
  usleep(1);

  /* on selectionne le device */
  outb(ATA_D_IBM | (device == 0) ? ATA_MASTER : ATA_SLAVE, ctrl->ioaddr + ATA_DRIVE);

  /* sencind command */
  outb(ATA_C_ATA_IDENTIFY, ctrl->ioaddr + ATA_CMD);
  

  for(timeout = 0; timeout < 30000; timeout++)
    {
      status = inb(ctrl->ioaddr + ATA_STATUS);
      if(!(status & ATA_S_BSY))
	break;
      
      usleep(1);
    }
  
  if(!(status & ATA_S_DRQ))
    {
      printk("Error\n");
      return -1;
    }
  
  for(i = 0; i < 256; i++)
    buffer[i] = inw(ctrl->ioaddr);

  harddisk = (harddisk_t *) ctrl->device[device];
  harddisk->ctrl = ctrl;
  harddisk->device = device;
  harddisk->general_configuration_info   = buffer[0];
  harddisk->logical_cylinder_nb          = buffer[1];
  harddisk->logical_head_nb              = buffer[3];
  harddisk->unformatted_bytes_per_track  = buffer[4];
  harddisk->unformatted_bytes_per_sector = buffer[5];
  harddisk->logical_sector_per_track     = buffer[6];
  harddisk->lba_capacity =
    (buffer[60] & 0xffff) | ((buffer[61] & 0xffff) << 16);
  printk("IS LBA CAPABLE ??? : %s\n", ( ((buffer[49] >> 8) & 1) == 1) ? "YES" : "NO");

  if(harddisk->logical_head_nb == 16 &&
     harddisk->logical_sector_per_track == 63 &&
     harddisk->logical_cylinder_nb == 16383)
    harddisk->size = harddisk->lba_capacity;
  else
    harddisk->size = 
      harddisk->logical_cylinder_nb * 
      harddisk->logical_sector_per_track *
      harddisk->logical_head_nb;
  
  convert_to_ascii((unsigned char *) (buffer + 0x1b), harddisk->model_number,40);
  convert_to_ascii((unsigned char *) (buffer + 0xa), harddisk->serial_number,20);  
  convert_to_ascii((unsigned char *) (buffer + 0x17), harddisk->firmware_revision,8);  

  get_partition_table(harddisk);

  return 0;
}



static void ide_handler(int nb, cpu_state_t *state)
{
  UNUSED(state);
  if(controllers[PRIMARY_CONTROLLER].state == ATA_WAIT_INTR)
    {
      printk("Got an IRQ %d !\n", nb);
      printk("The job was of type : %d\n", ide_op_list->type);
      controllers[PRIMARY_CONTROLLER].state = ATA_IDLE;
    }
}

static int initialize_devices(int controller)
{
  char c;
  controller_t *ctrl;

  if(controller == PRIMARY_CONTROLLER)
    {
      c = 'a';
      ctrl = &controllers[PRIMARY_CONTROLLER];
    }
  else if(controller == SECONDARY_CONTROLLER)
    {
      c = 'c';
      ctrl = &controllers[SECONDARY_CONTROLLER];
    }
  else
    {
      printk("Unknow controller !\n");
      return -1;
    }

  if(ctrl->state != ATA_NOT_PRESENT)
    {
      if(ctrl->devices & ATA_ATA_MASTER)
	{
	  harddisk_t *harddisk;
	  ctrl->device[MASTER] = kmalloc(sizeof(harddisk_t));
	  if(ctrl->device[MASTER] == NULL)
	    {
	      printk("[test_ide] memory allocation error\n");
	      return -1;
	    }
	  harddisk = (harddisk_t *) ctrl->device[MASTER];
	  get_drv_infos(ctrl, MASTER);
	  printk("hd%c: (%s = %d Mb) ", c, harddisk->model_number, harddisk->size>>11);
	}
      if(ctrl->devices & ATA_ATA_SLAVE)
	{
	  harddisk_t *harddisk;
	  ctrl->device[SLAVE] = kmalloc(sizeof(harddisk_t));
	  if(ctrl->device[SLAVE] == NULL)
	    {
	      printk("[test_ide] memory allocation error\n");
	      return -1;
	    }
	  harddisk = (harddisk_t *) ctrl->device[SLAVE];
	  get_drv_infos(ctrl, SLAVE);
	  printk("hd%c: (%s = %d Mb) ", c+1, harddisk->model_number, harddisk->size>>11);
	}
      if(ctrl->devices & ATA_ATAPI_MASTER)
	{
	  cdrom_t *cdrom;
	  ctrl->device[MASTER] = kmalloc(sizeof(cdrom_t));
	  if(ctrl->device[MASTER] == NULL)
	    {
	      printk("[test_ide] memory allocation error\n");
	      return -1;
	    }
	  cdrom = (cdrom_t *) ctrl->device[MASTER];
	  printk("hd%c (CD-ROM) ", c);
	}
      if(ctrl->devices & ATA_ATAPI_SLAVE)
	{
	  cdrom_t *cdrom;
	  ctrl->device[SLAVE] = kmalloc(sizeof(cdrom_t));
	  if(ctrl->device[SLAVE] == NULL)
	    {
	      printk("[test_ide] memory allocation error\n");
	      return -1;
	    }
	  cdrom = (cdrom_t *) ctrl->device[SLAVE];
	  printk("hd%c (CD-ROM) ", c+1);
	}
    }
  else
    printk("no controller found");

  printk("\n");

  return 0;
}


int test_ide(void)
{
  printk("Primary : ");
  init_ide(&controllers[PRIMARY_CONTROLLER]);
  initialize_devices(PRIMARY_CONTROLLER);
  
  printk("Secondary : ");
  init_ide(&controllers[SECONDARY_CONTROLLER]);
  initialize_devices(SECONDARY_CONTROLLER);

  register_irq_handler(14, ide_handler);

  return 0;
}




--=-=-=


-- 
PETAZZONI Thomas - thomas.petazzoni@enix.org - UIN : 34937744
(Perso)      http://www.enix.org/~thomas/
(KOS)        http://kos.enix.org/ 
(Club LinUT) http://club-linut.enix.org

--=-=-=--