home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / zip / diskutil / noahdi.lzh / NOAHDI / HD_INST.C < prev    next >
C/C++ Source or Header  |  1993-08-05  |  24KB  |  626 lines

  1. /*
  2.     File: HD_INST.C       Harddisk Driver Installer. AHDI Compatible.
  3. */
  4. /*
  5. Copyright (c) 1988 - 1991 by Ted Schipper.
  6.  
  7. Permission to use, copy, modify, and distribute this software and its
  8. documentation for any purpose and without fee is hereby granted,
  9. provided that the above copyright notice appear in all copies and that
  10. both that copyright notice and this permission notice appear in
  11. supporting documentation.
  12.  
  13. This software is provided AS IS with no warranties of any kind.  The author
  14. shall have no liability with respect to the infringement of copyrights,
  15. trade secrets or any patents by this file or any part thereof.  In no
  16. event will the author be liable for any lost revenue or profits or
  17. other special, indirect and consequential damages.
  18. */
  19.  
  20. #include "bootsec.h"
  21. #include "hddriver.h"
  22. #include "system.h"
  23. #include <osbind.h>
  24. #include <bios.h>
  25.  
  26.  
  27. /***************************************************************************
  28.  
  29.                             Installer
  30.                            -----------
  31.  HISTORY
  32. ---------
  33.  Feb 1989. THS. Started. Tested ppu, pread, getbpb. Made some corrections
  34.                 to bootsector structure (allignment). Added a dirty
  35.                 vector installer with hd debug messages.
  36.  Mar 1989. THS. Added pool_install.
  37.  Apr 1989. THS. Removed dirty vector installer. Added normal installer,
  38.                 exec_res, exec_auto stuff.
  39.  May 1989. THS. Added some extra stuff to pread. Pread now generates an
  40.                 error when a non existing drive is selected on a
  41.                 existing controller. Can be done better.
  42.  Jun 1989. THS. Runs nice (still from auto folder). Added assembly startup
  43.                 code to get it compatible Atari HD boot. Seems to work OK.
  44.                 V0.00
  45.  
  46. ***************************************************************************/
  47.  
  48. /***************************************************************************
  49.  
  50.                           Global Variables
  51.  
  52. ***************************************************************************/
  53.  
  54. extern short  puns;
  55. extern struct bpb bpbs[];
  56. extern struct hd_drv pun[];
  57. extern func   o_init;
  58. extern func   o_bpb;
  59. extern func   o_rw;
  60. extern func   o_mediach;
  61. extern short  hd_boot_flg;
  62. extern long   base_pg_addr;
  63.  
  64. /* Initialize variables to get them into the driver code */
  65.  
  66. short  clun = 0;                /* current logical unit */
  67. short  cpun = 0;                /* current physical unit */
  68. short  installed = 0;           /* number of installed partitions */
  69. long   cdbit = 0;               /* current drive bit */
  70. struct hd_boot pbuf, lbuf;      /* sector buffers */
  71.  
  72. char *copy_msg =
  73. "----------------------------\r\n\
  74.  ASCI/SCSI Hard Disk Driver\r\n\
  75.  NOAHDI V0.00 Sept-26-1989\r\n\
  76.  by T.Schipper Installed\r\n\
  77. ----------------------------\r\n";
  78.  
  79. char *env_str = "PATH=\0C:\\\0";  /* enviroment string */
  80. char *nothing = "\0";             /* empry string */
  81. char *auto_path = "C:\\AUTO\\*.PRG"; /* search string for Fsfirst */
  82. char *command = "COMMAND.PRG";    /* prg to execute if comload is true */
  83. long auto_base_pg = 0L;           /* temp storage for basepage addr */
  84.  
  85. char dta[44] = {0,0};             /* DTA buffer */
  86. char exec_path[32] = {0,0};       /* filename build string */
  87.  
  88. char   *dvr_nld =
  89. "Hard disk driver not loaded; hit RETURN\r\nkey to continue:\r\n";
  90.  
  91. char   *dsk_bsd = "*** WARNING ***\r\n\a\
  92. This hard disk driver may not work with\r\n\a\\
  93. a disk-based version of TOS; files on\r\n\a\
  94. your hard disk may be damaged.\r\n\a\r\n\a";
  95.  
  96. char   *unf_rel = "*** WARNING ***\r\n\a\
  97. You are using an unofficial ROM release\r\n\a\
  98. of the operating system. This driver\r\n\a\
  99. may not work correctly with it. Files\r\n\a\
  100. on your hard disk may be damaged.\r\n\a\r\n\a";
  101.  
  102. struct rom_rev {
  103.                 long rel_date;   /* ROM release date */
  104.                 long pool_list;  /* free list addr of release */
  105.                };
  106.  
  107. struct rom_rev revtable[4] = { 0x11201985L, 0x000056FAL,
  108.                                0x02061986L, 0x000056FAL,
  109.                                0x04241986L, 0x000056FAL,
  110.                                0x00000000L, 0x00000000L
  111.                             };
  112.  
  113. /***************************************************************************
  114.  
  115.                                Installer
  116.  
  117. ***************************************************************************/
  118.  
  119. /***************************************************************************
  120.  *
  121.  * Function name : exec_res. Execute memory resident programs.
  122.  * Parameters    : None
  123.  * Returns       : None
  124.  * Description   : Check physical memory every 512 bytes for a long magic
  125.  *                 number. If magic number found, check if next long points
  126.  *                 to magic number. If pointer to magic number is valid,
  127.  *                 calculate the checksum of the first 256 words. If the
  128.  *                 check is magic too, execute memory resident program at
  129.  *                 the address specified in the 3rd long.
  130.  * Comments      : 
  131.  */
  132.  
  133. void exec_res()
  134. {
  135.  func res_prg;
  136.  unsigned short checksum;
  137.  short *chksum_ptr, i;
  138.  long  *mem_ptr;
  139.  
  140.  mem_ptr = (long *)PHYSTOP;         /* get end of memory */
  141.  while ((mem_ptr -= 0x80) > (long *)0x0400L)
  142.  {                                  /* dec 512 bytes, untill 0x600, then */
  143.     if (*mem_ptr == 0x12123456L)    /* magic long word at 512b boundary */
  144.     {
  145.        if (*(mem_ptr + 1) == (long)mem_ptr) /* pointer to magic OK */
  146.        {
  147.           checksum = 0;             /* clear checksum */
  148.           chksum_ptr = (short *)mem_ptr; /* set pointer to first word */
  149.           for (i=0; i<256; i++)     /* calc checksum from 256 words */
  150.              checksum += *chksum_ptr++;
  151.           if (checksum == 0x5678)   /* is the checksum magic */
  152.           {
  153.              res_prg = (func)*(mem_ptr + 2); /* set pointer to entry point */
  154.              (*res_prg)();          /* execute memory resident programm */
  155.           }
  156.        }
  157.     }
  158.  }
  159. }
  160.  
  161.  
  162. /***************************************************************************
  163.  *
  164.  * Function name : exec_auto_prg. Start auto-folder execute process.
  165.  * Parameters    : None
  166.  * Returns       : None
  167.  * Description   : Create a basepage for, and start the auto-folder program
  168.  *                 which executes all the programs in the auto folder.
  169.  * Comments      : Since we can't read the micro registers, the basepage
  170.  *                 address is stored in a global variable. This variable
  171.  *                 is used by the auto-folder executer to find its basepage.
  172.  */
  173.  
  174. void exec_auto_prg()
  175. {
  176.  void auto_prg();
  177.  long *basepage;
  178.  
  179.  basepage = (long *)Pexec(5,nothing,nothing,nothing); /* create a basepage */
  180.  *(basepage + 2) = (long)auto_prg;            /* set process start address */
  181.  auto_base_pg = (long)basepage;               /* save basepage address */
  182.  Pexec(4,nothing,basepage,nothing);       /* execute auto_prg as a process */
  183. }
  184.  
  185.  
  186. /***************************************************************************
  187.  *
  188.  * Function name : auto_prg. Auto folder search and execute program.
  189.  * Parameters    : None
  190.  * Returns       : None
  191.  * Description   : Search the auto folder for programs. Execute each found
  192.  *                 program. Set SYSBASE variable. Check if command load
  193.  *                 flag is set, and execute command.prg if set. Else build
  194.  *                 a basepage and execute the AES.
  195.  * Comments      : 
  196.  */
  197.  
  198. void auto_prg()
  199. {
  200.  char *ptr_s, *ptr_d, *ptr_m;
  201.  long  *base_page;
  202.  func  reset;
  203.  
  204.  Dsetdrv(2);                    /* set the default drive to C: */
  205.  Super(auto_base_pg + 0x100L);  /* supervisor mode, stack at end of basepage */
  206.  if (Mshrink(auto_base_pg,0x100L) == 0); /* return unused memory */
  207.  {
  208.      Fsetdta(dta);              /* set disk transfer address */
  209.      if (Fsfirst(auto_path,7) == 0) /* check for auto prg's */
  210.      {
  211.         do
  212.         {
  213.            ptr_s = auto_path;
  214.            ptr_d = exec_path;
  215.            ptr_m = &auto_path[8];
  216.            while (ptr_s != ptr_m)  /* copy C:\AUTO\ to exec filename string */
  217.               *ptr_d++ = *ptr_s++;
  218.            ptr_s = &dta[30];       /* ptr to found program filename */
  219.            while(*ptr_s != 0)      /* copy filename from dta buffer */
  220.               *ptr_d++ = *ptr_s++;
  221.            Pexec(0,exec_path,nothing,nothing); /* load and execute prog */
  222.            Fsetdta(dta);
  223.         } while (Fsnext() == 0);   /* find next auto prg */
  224.      }
  225.  }
  226.  reset = (func) RESET;             /* set pointer to reset routine */
  227.  SYSBASE = 0xFC0000L;              /* set OS entry back to ROM's */
  228.  if (COMLOAD)                      /* command load flag set */
  229.     Pexec(0,command,nothing,nothing); /* load and execute command.prg */
  230.  else                              /* start AES */
  231.  {
  232.     base_page = (long *)Pexec(5,nothing,nothing,env_str);
  233.                                         /* create a basepage */
  234.     *(base_page + 2) = EXEC_OS;         /* set the AES entry point */
  235.     Pexec(4,nothing,base_page,env_str); /* start AES */
  236.  }
  237.  (*reset)();                 /* should never return from AES or COMMAND, */
  238.                              /* but if it may happen, jump to reset vector */
  239. }
  240.  
  241.  
  242. /***************************************************************************
  243.  *
  244.  * Function name : pool_install. Extend the OS pool buffer.
  245.  * Parameters    : none.
  246.  * Returns       : short. Number of bytes used to install pool.
  247.  * Description   : Try to extend the OS pool buffer with 128 directory
  248.  *                 control blocks. Check if the right ROM's are used.
  249.  * Comments      : 
  250.  */
  251.  
  252. short pool_install()
  253. {
  254.  long   *rel;
  255.  long   *pool;
  256.  struct DCB *dcb, *tmp;
  257.  short  *dos_date;
  258.  short  i;
  259.  char   *txt;
  260.  
  261.  if (SYSBASE >= 0x800000L) /* ROM based OS */
  262.  {
  263.     i = 0;
  264.     rel = (long *)(SYSBASE + 0x18); /* pointer to ROM release date */
  265.     while (revtable[i].rel_date != 0x0L)
  266.     {
  267.           if (*rel == revtable[i].rel_date) /* compare with known releases */
  268.           {
  269.              pool = (long *)(revtable[i].pool_list + 16);
  270.              dcb = (struct DCB *) dvr_nld; /* get addr of end of program */
  271.              for (i=0; i<128; i++)         /* install 128 DCB's into pool */
  272.              {
  273.                 dcb->size = 4;          /* DCB size in paragraphs */
  274.                 tmp = dcb + 1;          /* pointer to next DCB */
  275.                 dcb->next = &tmp->next; /* put it in current DCB */
  276.                 dcb = tmp;              /* make next current */
  277.              }
  278.              dcb--;                     /* point to last DCB */
  279.              dcb->next = (struct DCB *) *pool; /* chain in old DCB's */
  280.              return(128 * 66);          /* return bytes used for pool */
  281.           }
  282.           i++;
  283.     }
  284.     txt = unf_rel; /* assume unofficial ROM Release */
  285.  }
  286.  else
  287.     txt = dsk_bsd;           /* assume disk based OS */
  288.  dos_date = (short *)(SYSBASE + 0x1E); /* pointer to ROM dos date */
  289.  if (*dos_date >= 0xCA1)               /* new release ? */
  290.     return(0);               /* assume new release with no folder problems */
  291.  Cconws(txt);                /* print message if not 'new release' */
  292.  Cconws(dvr_nld);            /* print driver not loaded */
  293.  while (Bconin(2) != '\r');  /* wait for a CR */
  294.  return(0);                  /* return with zero bytes pool installed */
  295. }
  296.  
  297.  
  298. /***************************************************************************
  299.  *
  300.  * Function name : i_sasi1. Normal entry point.
  301.  * Parameters    : None
  302.  * Returns       : int. 0xE0. Should not return.
  303.  * Description   : Scans all ASCI devices by trying to read there boot
  304.  *                 sectors. When a PUN is found, its partitioned and the
  305.  *                 LUN is installed. If a LUN is found, the driver vectors
  306.  *                 are installed. If the driver was executed from the
  307.  *                 hard disk boot program, memory resident programs are
  308.  *                 executed and the auto folder execute process is started.
  309.  * Comments      : 
  310.  */
  311.  
  312.  i_sasi1()
  313. {
  314.  short i;
  315.  long  size;
  316.  long savssp;
  317.  void exec_auto_prg();
  318.  extern char _start[];            /* start of driver */
  319.  
  320.  if (!hd_boot_flg)                /* not called from HD boot */
  321.     savssp = Super(0L);           /* then go into SUPERVISOR mode */
  322.  
  323.  for (i=0; i < MAX_UNITS; i++)    /* clear all physical units */
  324.     pun[i].dev_addr = -1;
  325.  
  326.  clun = 2;                        /* set current logical unit number (C) */
  327.  cdbit = 4;                       /* set current drive bit (C) */
  328.  cpun = 0;                        /* set current physical unit number */
  329.  installed = 0;                   /* nothing installed yet */
  330.  puns = 0;                        /* no physical units found yet */
  331.  
  332.  do
  333.  {
  334.     if (pread(0L,1,&pbuf,cpun) != 0L) /* read boot sector of each physical unit */
  335.        continue;                      /* next physical unit */
  336. /*       break; */                       /* stop scanning if error */
  337.     puns ++;                         /* found a physical unit */
  338.     ppu();                           /* partition it */
  339. /*    cpun ++;*/                         /* next physical unit number */
  340.  } while (++cpun < MAX_UNITS);
  341.  
  342.  if (puns)                      /* if a drive and partitions where found */
  343.  {
  344.     o_bpb = (func) HDV_BPB;     /* store pointers to old functions */
  345.     o_rw  = (func) HDV_RW;
  346.     o_mediach = (func) HDV_MEDI;
  347.     HDV_BPB = (long) hbpb;      /* store pointer to new functions */
  348.     HDV_RW  = (long) hrw;
  349.     HDV_MEDI = (long) hmediach;
  350.     PUN_PTR  = (long) &puns;
  351.  
  352.     i = pool_install();         /* install extra folders, get used bytes */
  353.  
  354.     if (!hd_boot_flg)           /* called from HD boot */
  355.        Super(savssp);           /* no go into USER mode again */
  356.  
  357.     size = (long)((long)dvr_nld - (long)&_start[0]) + 0x100 + i;
  358.                                 /* calc driver size */
  359.  
  360.     if (!hd_boot_flg)           /* not called from HD boot */
  361.        Ptermres(size,0);        /* terminate and stay resident */
  362.  
  363.     Cconws(copy_msg);           /* print copy-right message */
  364.     BOOTDEV = 2;                /* set boot device */
  365.     Mshrink(base_pg_addr,size); /* shrink allocated memory to size bytes */
  366.     exec_res();                 /* execute memory resident programs */
  367.     exec_auto_prg();            /* start auto folder executer process */
  368.  /* we should never come back here */
  369.  }
  370.  else
  371.  {
  372.     if (!hd_boot_flg)           /* not called by HD boot */
  373.     {
  374.        Super(savssp);           /* back to user mode */
  375.        Pterm(-1);               /* and quit */
  376.     }
  377.     else                        /* called by HD boot */
  378.     {
  379.        Mfree(base_pg_addr);     /* free allocated memory */
  380.        return(0xE0);            /* return highest ASCI unit number to stop */
  381.                                 /* BIOS DMA boot loop */
  382.     }
  383.  }
  384. }
  385.  
  386.  
  387. /***************************************************************************
  388.  *
  389.  * Function name : pread. Read physical sectors from harddisk with retries.
  390.  * Parameters    : long  sector number. 21 bits address.
  391.  *                 short sector count.   8 bits count.
  392.  *                 long  buffer addr.   32 bits address.
  393.  *                 short device number.  4 bits: bit 0   = drive # (0 or 1)
  394.  *                                               bit 1-3 = controller # (0-7)
  395.  * Returns       : long OK    = sectors are read.
  396.  *                      ERROR = (-1) timeout, sectors (drive) does not exist.
  397.  *                      >0    = read error on sector.
  398.  * Description   : Try to read a physical sector(s) from harddisk. If a read
  399.  *                 error occurded, try again. Used to test if a drive is
  400.  *                 present on the ASCI bus.
  401.  * Comments      : Assumes processor is in supervisor mode. A workaround
  402.  *                 for the HAC bug has been added to generate an error when
  403.  *                 a sector is read on a non existing drive.
  404.  */
  405.  
  406. long pread(sect_nr,sect_cnt,buf_addr,dev)
  407.  
  408.  long  sect_nr;
  409.  short sect_cnt;
  410.  long  buf_addr;
  411.  short dev;
  412.  
  413. {
  414.  short retrycnt = NRETRIES;
  415.  long  status;
  416.  char  *ptr;
  417.  short cnt;
  418.  
  419.  ptr = (char *)buf_addr;        /* get pointer to transfer buffer */
  420.  for (cnt=0; cnt < 512; cnt++)  /* zap it */
  421.     *ptr++ = 0;
  422.  do
  423.  {
  424.     status = hread(sect_nr,sect_cnt,buf_addr,dev);  /* read sectors */
  425.  } while ((status > 0L) && ((retrycnt --) > 0)) ;   /* try again if read error */
  426.  if (status < 0L)                                   /* timeout, return */
  427.     return(status);
  428.  ptr = (char *)buf_addr;        /* get pointer to tranfer buffer */
  429.  for (cnt=0; cnt < 512; cnt++)  /* check if still zapped */
  430.  {
  431.     if (*ptr++ != 0)            /* no, return */
  432.        return(status);
  433.  }
  434.  return(ERROR);                 /* still zapped, return timeout error */
  435.  
  436.  
  437. /***************************************************************************
  438.  *
  439.  * Function name : ppu. Partition physical unit.
  440.  * Parameters    : None
  441.  * Returns       : None
  442.  * Description   : Check a boot sector for valid partition data. When OK
  443.  *                 build BPB's and record the PUN and start sector of each
  444.  *                 partition. If no partition is found, assume harddisk is
  445.  *                 one big partition.
  446.  * Comments      : 
  447.  */
  448.  
  449. void ppu()
  450. {
  451.  short i, npart;
  452.  
  453.  npart = 0;                     /* reset partition count */
  454.  if (pbuf.hi_size)              /* HD size > 0 */
  455.  {
  456. /*    printf("HD size unit %d = %ld\n",cpun,pbuf.hi_size); */
  457.     for (i=0; i < 4; i++)       /* check the 4 partitions */
  458.     {
  459.        if (pbuf.p[i].pi_flag)   /* active partition */
  460.        {
  461. /*          printf("Part %d is active: %d\n",i,pbuf.p[i].pi_flag); */
  462.           npart ++;             /* count number of partitions on drive */
  463.           if (pbuf.p[i].pi_id[0] == 'G') /* check for valid partition name */
  464.           {
  465. /*             printf("found %c\n",pbuf.p[i].pi_id[0]); */
  466.              if (pbuf.p[i].pi_id[1] == 'E')
  467.              {
  468. /*                printf("found %c\n",pbuf.p[i].pi_id[1]); */
  469.                 if (pbuf.p[i].pi_id[2] == 'M')
  470.                 {
  471. /*                   printf("found %c\n",pbuf.p[i].pi_id[2]); */
  472.                    if (pbuf.p[i].pi_size)  /* partition size OK */
  473.                    {
  474. /*                      printf("Part %d size = %ld\n",i,pbuf.p[i].pi_size); */
  475.                       if (nxtdrv() >= 0)    /* add partition to TOS, check */
  476.                       {
  477. /*                         printf("next Part OK\n"); */
  478.                          if (getbpb(pbuf.p[i].pi_start) == 0L) /* build BPB */
  479.                          {
  480. /*                            printf("Part %d BPB build\n",i); */
  481.                             pun[clun].dev_addr = cpun; /* set dev addr */
  482.                             pun[clun].part_start = pbuf.p[i].pi_start; /* set start sector */
  483.                             clun ++;
  484.                             installed ++; /* actually installed a harddisk */
  485. /*                            printf("partition %d found\n",clun-1);*/
  486. /*                            Cconws("Partition found\r\n");*/
  487.                          }
  488.                       }
  489.                    }
  490.                 }
  491.              }
  492.           }
  493.        }
  494.     }
  495.  }
  496.  
  497.  if (npart)       /* did we find any partitions */
  498.  {
  499.     return;       /* yes, then return */
  500.  }
  501.  else             /* no, so build one BPB */
  502.  {
  503. /*    printf("No Partitions found\n");*/
  504. /*    Cconws("No Partitions found\r\n");*/
  505.     nxtdrv();              /* no valid partitions found, assume the whole */
  506.     pun[clun].dev_addr = cpun;      /* thing is one big GEM disk */
  507.     pun[clun].part_start = 0L;      /* starts at 0 */
  508.     bpbs[clun].bp_recsiz = 512;     /* build BPB for GEM disk */
  509.     bpbs[clun].bp_clsiz = 2;
  510.     bpbs[clun].bp_clsizb = 1024;
  511.     bpbs[clun].bp_rdlen = 16;
  512.     bpbs[clun].bp_fsiz = 41;
  513.     bpbs[clun].bp_fatrec = 42;
  514.     bpbs[clun].bp_datrec = 99;
  515.     bpbs[clun].bp_numcl = 10300;
  516.     bpbs[clun].bp_flags = 1;
  517.     clun ++;
  518.     installed ++;
  519.  }
  520. }
  521.  
  522.  
  523. /***************************************************************************
  524.  *
  525.  * Function name : nxtdrv. Set TOS logical drive, check next drive.
  526.  * Parameters    : None
  527.  * Returns       : short >= 0 : Next Current Logical Unit (CLUN).
  528.  *                       ERROR: To many TOS drives installed already.
  529.  * Description   : Check if clun is not overranged. If not, set drivebit
  530.  *                 in TOS variable, make mask for next drivebit and return
  531.  *                 clun.
  532.  * Comments      : 
  533.  */
  534.  
  535. short nxtdrv()
  536. {
  537.  if (clun >= MAX_UNITS)     /* have we already hit the maximum */
  538.     return(ERROR);          /* yes, so signal error */
  539.  
  540.  DRVBITS |= cdbit;          /* tell TOS we have the drive */
  541.  cdbit = (cdbit << 1);      /* set next drive bit */
  542.  return(clun);
  543. }
  544.  
  545.  
  546. /***************************************************************************
  547.  *
  548.  * Function name : getbpb. Build a BPB block for a partition.
  549.  * Parameters    : long partition sector number.
  550.  * Returns       : long OK : always went OK.
  551.  * Description   : Read the partition root sector. Build from root sector
  552.  *                 data a TOS BPB block.
  553.  * Comments      : 
  554.  */
  555.  
  556. long getbpb(sectorno)
  557.  
  558.  long sectorno;
  559.  
  560. {
  561.  short i,res_cnt,sec_cnt;
  562.  
  563.  if (pread(sectorno,1,&lbuf,cpun) == OK)  /* read partition boot sector */
  564.  {
  565.     bpbs[clun].bp_recsiz = getlhw(&lbuf,0x0B); /* sector size in H/L */
  566. /*    printf("CLUN %d: recsiz = %d\n",clun,bpbs[clun].bp_recsiz); */
  567.     bpbs[clun].bp_clsiz  = lbuf.bp_spc;        /* sectors per cluster */
  568. /*    printf("CLUN %d: clsiz = %d\n",clun,bpbs[clun].bp_clsiz); */
  569.     bpbs[clun].bp_clsizb = bpbs[clun].bp_recsiz * bpbs[clun].bp_clsiz; /* bytes per cluster */
  570. /*    printf("CLUN %d: clsizb = %d\n",clun,bpbs[clun].bp_clsizb); */
  571.     i = getlhw(&lbuf,0x11) * 32;               /* bytes needed for root dir */
  572.     if (i % bpbs[clun].bp_recsiz)              /* part of sector needed */
  573.        sec_cnt  = i / bpbs[clun].bp_recsiz + 1; /* sectors for dir */
  574.     else
  575.        sec_cnt  = i / bpbs[clun].bp_recsiz;   /* sectors for dir */
  576.     bpbs[clun].bp_rdlen  = sec_cnt;           /* sectors for dir */
  577. /*    printf("CLUN %d: rd_len = %d\n",clun,bpbs[clun].bp_rdlen); */
  578.     i = getlhw(&lbuf,0x16);                   /* get FAT size in sectors */
  579.     bpbs[clun].bp_fsiz = i;                   /* store FAT size in sectors */
  580. /*    printf("CLUN %d: fsiz = %d\n",clun,bpbs[clun].bp_fsiz); */
  581.     res_cnt = i;                              /* count reserved sectors */
  582.     i = getlhw(&lbuf,0x0E);                   /* get reserved sectors */
  583.     bpbs[clun].bp_fatrec = res_cnt + i;       /* start of 2nd FAT */
  584. /*    printf("CLUN %d: fatrec = %d\n",clun,bpbs[clun].bp_fatrec); */
  585.     sec_cnt += (res_cnt * 2 + i);             /* total reserved sectors */
  586.     bpbs[clun].bp_datrec = sec_cnt;           /* set start of data sector */
  587. /*    printf("CLUN %d: datrec = %d\n",clun,bpbs[clun].bp_datrec); */
  588.     i = getlhw(&lbuf,0x13);                   /* get total # sectors */
  589.     i -= sec_cnt;                             /* calc remaining # sectors */
  590.     i /= lbuf.bp_spc;                         /* calc remaining # clusters */
  591.     bpbs[clun].bp_numcl = i;                  /* set # data clusters */
  592. /*    printf("CLUN %d: numcl = %d\n",clun,bpbs[clun].bp_numcl); */
  593.     bpbs[clun].bp_flags = 1;                  /* set 16-bit FAT's */
  594.     return(OK);
  595.  }
  596. }
  597.  
  598.  
  599. /***************************************************************************
  600.  *
  601.  * Function name : getlhw. Swop short from INTEL to MOTOROLA format.
  602.  * Parameters    : char  *start. pointer to start boot sector.
  603.  *                 short offset.  offset into boot sector where short is.
  604.  * Returns       : short. Motorola format.
  605.  * Description   : Swop the 2 bytes, beginning at address + offset. return
  606.  *                 the swopped bytes.
  607.  * Comments      : 
  608.  */
  609.  
  610. short getlhw(addr,offset)
  611.  
  612.  char  *addr;
  613.  short offset;
  614.  
  615. {
  616.  char  *ptr;
  617.  short temp;
  618.  
  619.  ptr = (char *) &temp;                 /* get pointer to temporary short */
  620.  ptr[1] = addr[offset];                /* swop short bytes to MOTOROLA short */
  621.  ptr[0] = addr[offset+1];
  622.  return(temp);                         /* return swopt short */
  623. }
  624.  
  625.