/*  lbaconv.cpp
    LBA <> CHS conversion functions.

    29.08.2001: tk, initial implementation. All formulas are derived
                    from Hale Landis' "How it works" documents.

    tk: thomas.kindler@gmx.de
    tg: thorsten.godau@tz-mikroelektronik.de

    Copyright (c)2001 by Thomas Kindler, Thorsten Godau

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of
    the License, or (at your option) any later version. Read the
    full License at http://www.gnu.org/copyleft for more details.
*/

// include files
//
#include <assert.h>
#include "lbaconv.h"

// physical chs parameters for LBA_to_PCHS
//
static unsigned pchsHeads;
static unsigned pchsSectors;


/**
 * Convert a LBA address to CHS.
 * \param  lba     logical block address
 * \param  c,h,s   pointer to Cylinder, Head and Sector
 * \param  heads   total number of heads
 * \param  sectors total number of cylinders
 */
void LBA_to_CHS( unsigned long lba,
                 unsigned *c, unsigned *h, unsigned *s,
                 unsigned  heads, unsigned  sectors )
{
  unsigned tmp;
  *c   = (unsigned)(lba / (heads * sectors));
   tmp = (unsigned)(lba % (heads * sectors));
  *h   = tmp / sectors;
  *s   = tmp % sectors+1;
}


/**
 * Convert a CHS address to LBA.
 * \param  c,h,s      Cylinder, Head and Sector
 * \param  lba        pointer to LBA address
 * \param  heads   total number of heads
 * \param  sectors total number of cylinders
 */
unsigned long CHS_to_LBA( unsigned c, unsigned h, unsigned s,
                          unsigned heads, unsigned sectors)
{
  unsigned long lba;
  lba  = (unsigned long)c * heads * sectors;
  lba += (unsigned long)h * sectors;
  lba += s - 1;
  return lba;
}


/**
 * Convert a LBA address to a physical CHS address.
 * The translation parameters must be set by
 * SetCHSTranslation() first.
 *
 * \param  lba     logical block address
 * \param  c,h,s   pointer to Cylinder, Head and Sector
 */
void  LBA_to_PCHS(unsigned long lba, unsigned *c, unsigned *h, unsigned *s)
{
  assert(pchsHeads   != 0);
  assert(pchsSectors != 0);
  LBA_to_CHS( lba, c, h, s, pchsHeads, pchsSectors);
}


/**
 * Set physical CHS drive geometry. These settings will
 * be used for LBA_to_PCHS()
 */
void  SetPCHSTranslation(unsigned heads, unsigned sectors)
{
  pchsHeads   = heads;
  pchsSectors = sectors;
}


