home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / MISC / scsiutil.lzh / SCSIUTIL / SCSIutil.c.org < prev    next >
Text File  |  1996-10-12  |  73KB  |  2,758 lines

  1. /*
  2.  *****    SCSIutil
  3.  *
  4.  *    A utility to do some low-level operations to a SCSI disk, e.g.
  5.  *
  6.  *        - start/stop motor
  7.  *        - read sectors
  8.  *        - read disk capacity info
  9.  *        - get inquiry info (manufacturers name etc)
  10.  *        - seek to a sector's cylinder (use to park heads)
  11.  *        - play audio tracks of a CD-DA
  12.  *        - eject/insert a medium
  13.  *        - read digital data off audio CDs (with Sony 8003 = Apple CD300
  14.  *          and Toshiba 3401)
  15.  *        - set output volume of a CD-ROM drive
  16.  *
  17.  *    NOTE:  this program is based on SCSI information taken from
  18.  *           the accompanying documentation of a NEC D3841 SCSI disk.
  19.  *           I don't know the extent to which SCSI standards are
  20.  *           supported by that disk.
  21.  *
  22.  *           These commands work on the above disk. But a seek to
  23.  *           sector -1 (park on the NEC disk) fails on my Quantum 105.D
  24.  *
  25.  *    Program returns:
  26.  *    1 - init didn't work (maybe allocmem failed, etc.)
  27.  *    2 - wrong parameter count
  28.  *    3 - wrong parameter
  29.  *
  30.  *****    Written by Gary Duncan
  31.  *
  32.  *    Bug reports etc via e-mail to gduncan@philips.oz.au) , or mail to
  33.  *
  34.  *    Gary Duncan
  35.  *    Philips PTS
  36.  *      23 Lakeside Dr
  37.  *    Tally-Ho Technology Park
  38.  *    Burwood East Vic 3151
  39.  *    Australia
  40.  *
  41.  * New features and rewrites by:
  42.  *
  43.  *    The Software Brewery
  44.  *    Heiko Rath
  45.  *    Raiffeisenstr.10a
  46.  *    D-64331 Weiterstadt
  47.  *    Germany
  48.  *
  49.  *    EMail: hr@brewhr.swb.de
  50.  *
  51.  *****    Freely distributable for non-commercial purposes
  52.  *
  53.  *    Compiles under Lattice 6.50
  54.  *    - needs AmigaDos 2.0  #includes
  55.  *
  56.  ***** Thanks to Markus Illenseer for some beta-testing.
  57.  *
  58.  *****    Function List :-
  59.  *
  60.  *    breakcheck()        by GD, modified by <HR>
  61.  *    __chkabort()        by <HR>
  62.  *    DoScsiCmd ()        by <HR>
  63.  *    err_str()        by GD
  64.  *    gcomp()            by GD
  65.  *    finddrivebrand()    by <HR>
  66.  *    GetDevName()        by GD
  67.  *    id2string ()        by <HR>
  68.  *    init ()            by GD, modified by <HR>
  69.  *    inquiry()        by GD, modified by <HR>
  70.  *    medium_removal()    by <HR>
  71.  *    mode_sense()        by <HR>
  72.  *    motor ()        by GD, modified by <HR>
  73.  *    play_audio ()        by <HR>
  74.  *    rawahexasciioutput()    by <HR>
  75.  *    rawhexoutput()        by <HR>
  76.  *    read_capacity()        by GD, modified by <HR>
  77.  *    read_cdblockheader()    by <HR>
  78.  *    read_cddaasync()    by <HR>
  79.  *    read_sec ()        by GD, modified by <HR>
  80.  *    read_sec_scsi ()    by GD, modified by <HR>
  81.  *    read_subchannel()    by <HR>
  82.  *    read_toc ()        by <HR>
  83.  *    seek ()            by GD, modified by <HR>
  84.  *    SendScsiCmd()        by <HR>
  85.  *    sense_errs()        by GD
  86.  *    set_volume()        by <HR>
  87.  *    usage()            by GD, modified by <HR>
  88.  *    WaitScsiCmd()        by <HR>
  89.  *
  90.  */
  91.  
  92. #define VERSION "2.02"
  93.  
  94. /*
  95.  **** Includes
  96.  */
  97. #include <stdio.h>
  98. #ifdef OSK
  99. #include <strings.h>
  100. #else
  101. #include <string.h>
  102. #endif
  103. #include <ctype.h>
  104. #ifndef OSK
  105. #include <exec/types.h>
  106. #include <exec/io.h>
  107. #include <exec/execbase.h>
  108. #include <exec/nodes.h>
  109. #include <exec/memory.h>
  110. #include <devices/trackdisk.h>
  111. #include <devices/scsidisk.h>
  112. #include <libraries/dos.h>
  113. #ifdef __SASC
  114. #include <proto/all.h>
  115. #else
  116. #include <clib/alib_protos.h>
  117. #include <clib/exec_protos.h>
  118. /* non-ANSI C macro isascii() */
  119. #define isascii(a) (((a) & 0x80) == 0)
  120. #endif
  121. #else
  122. #include <types.h>
  123. #endif
  124. #include "scsi_priv.h"
  125.  
  126. /*
  127.  * string for AmigaDOS Version Command 
  128.  */
  129. char A_vers[] = "\0$VER: SCSIutil " VERSION " (" __DATE__ " " __TIME__ ")";
  130.  
  131. /*
  132.  **** Global variables
  133.  */
  134. UBYTE *ip_buf = NULL;
  135. UBYTE *scsi_data = NULL;
  136. UBYTE *toc_buf = NULL;
  137.  
  138. UBYTE *dev = "";
  139.  
  140. int scsi_id = -1;        /* ID of the SCSI device to send commands to */
  141. UBYTE *pname;
  142. UBYTE buffer[LINE_BUF];
  143. int secno = -1;
  144. DRIVETYPE whatdrive = UNKNOWN;    /* what CD-ROM brand */
  145.  
  146. UBYTE *cdda_buf[NDBLBUF];
  147. MSGPORT *mp_ptr[NDBLBUF];
  148. IOSTDREQ *io_ptr[NDBLBUF];
  149. SCSICMD scsi_cmd[NDBLBUF];
  150. UBYTE *scsi_sense[NDBLBUF];
  151. UBYTE scsi_status[NDBLBUF];
  152. BYTE *mono_buf[NDBLBUF];
  153.  
  154. #ifdef USE8SVX
  155. BYTE write8svx = FALSE;        /* convert to 8SVX */
  156. #endif    /* USE8SVX */
  157.  
  158. /*
  159.  **** Function descr.
  160.  */
  161. int breakcheck (void);
  162. int DoScsiCmd (UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags);
  163. UBYTE *err_str (int err);
  164. void exit (int status);
  165. void finddrivebrand (void);
  166. int gcomp (char *p1, char *p2, int len);
  167. UBYTE *GetDevName (char *grep);
  168. UBYTE *id2string (int id, IDTOSTRING * idtable);
  169. BOOLEAN init (void);
  170. void inquiry (BOOLEAN parsedoutput);
  171. void medium_removal(int lock);
  172. void mode_sense (BOOLEAN parsed, UBYTE control, UBYTE page);
  173. void motor (int motorstatus);
  174. void play_audio (int starttrack, int startindex, int endtrack, int endindex);
  175. void rawhexasciioutput (UBYTE *p, UWORD numbytes, UBYTE leadspace);
  176. void rawhexoutput (UBYTE *p, UWORD numbytes);
  177. void read_capacity (BOOLEAN parsed);
  178. void read_cdblockheader (BOOLEAN parsed, ULONG block);
  179. #ifdef _DCC
  180. __stkargs
  181. #endif
  182. void read_cddaasync (ULONG startblock, ULONG numblocks, BYTE
  183.              whichchannel, BYTE use16bit, unsigned int subcode);
  184. void read_sec (void);
  185. void read_sec_scsi (void);
  186. void read_subchannel (BOOLEAN parsed, UBYTE subchannel, UBYTE subchannelformat, UBYTE track);
  187. void read_toc (int toclong);
  188. void seek (void);
  189. UBYTE *sense_errs (int req, int err);
  190. void set_volume (int vol0, int vol1, int vol2, int vol3);
  191. void usage (void);
  192.  
  193. int WaitScsiCmd (int req);
  194. void SendScsiCmd (int req, UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags);
  195.  
  196. #ifdef __SASC
  197. void __regargs __chkabort (void);
  198. #endif    /* __SASC */
  199. #ifdef _DCC
  200. #include <stdlib.h>
  201. typedef int (*brkfuncptr)();
  202. int brkhandler() { return(0); }
  203. #endif
  204.  
  205.  
  206.  
  207. /*********************************************************************
  208.  *
  209.  *    main
  210.  *
  211.  *
  212.  */
  213.  
  214. int
  215. main (int argc, char **argv)
  216. {
  217.   UBYTE *p;
  218.   int j = 0, i = 0;
  219.   int returnvalue = 0;
  220.  
  221. #ifdef _DCC
  222.   int (*oldbrkhandler)() = onbreak(brkhandler);
  223. #endif
  224.   if (argc == 1)
  225.     {
  226.       usage ();
  227.       exit (1);
  228.     }
  229. #ifndef OSK
  230.   /*
  231.    *      see if a SCSI.device specified
  232.    */
  233.   if (strncmp (argv[1], "-d", 2) == 0)
  234.     {
  235.       j = 1;
  236.       dev = argv[1] + 2;
  237.     }
  238.   else if ((dev = GetDevName (SCSI_STRING)) == NULL)
  239.     {
  240.       fprintf (stderr, "Error : no *scsi*.device in device list\n");
  241.       exit (1);
  242.     }
  243. #else
  244.    if ( *argv[1] == '/' ) {
  245.       j = 1;
  246.       dev = argv[1];
  247.    } else
  248.       dev = SCSI_STRING;
  249. #endif
  250.   pname = argv[0];
  251.   if (argc < (j + 2))
  252.     {
  253.       usage ();            /* help inquiry */
  254.       exit (1);
  255.     }
  256.  
  257.   if (argc < (j + 3))
  258.     {
  259.       fprintf (stderr, "Error : Not enough params\n");
  260.       exit (1);
  261.     }
  262. #ifndef OSK
  263.   /*
  264.    *    pick up SCSI id ; do a rough check
  265.    */
  266.   if (sscanf (argv[j + 1], "%d", &scsi_id) != 1 || scsi_id < 0)
  267.     {
  268.       fprintf (stderr, "Error : Bad scsi id\n");
  269.       exit (1);
  270.     }
  271. #endif
  272.   if (*(p = argv[j + 2]) != '-')
  273.     {
  274.       fprintf (stderr, "Error : bad option\n");
  275.       exit (1);
  276.     }
  277.  
  278.   /*
  279.    *    now set up structures etc for SCSI xfer
  280.    */
  281.   if (init () == FALSE)
  282.     {
  283.       returnvalue = 1;
  284.       goto error;
  285.     }
  286.  
  287.  
  288.   /*
  289.    **********************    now examine the options
  290.    */
  291.   if (argc == (j + 3))
  292.     /* commands without parameter */
  293.     {
  294.       switch (*++p)
  295.     {
  296.       /*
  297.            ****     read capacity
  298.            */
  299.     case 'c':
  300.       if (*++p == 'r')
  301.         {
  302.               read_capacity (FALSE);    /* output raw data */
  303.             }
  304.           else
  305.             {
  306.               read_capacity (TRUE);    /* output parsed data */
  307.             }
  308.       break;
  309.  
  310.       /*
  311.            ****     inquiry (raw)
  312.            */
  313.     case 'i':
  314.       if (*++p == 'r')
  315.         {
  316.               inquiry (FALSE);        /* output raw data */
  317.             }
  318.           else
  319.             {
  320.               inquiry (TRUE);        /* output parsed data */
  321.             }
  322.       break;
  323.  
  324.       /*
  325.            ****     read TOC
  326.            */
  327.     case 't':
  328.       if (*(p+1) == 'r')
  329.         {
  330.           read_toc(0);    /* output raw data */
  331.         }
  332.       else if (*(p+1) == 'l')
  333.         {
  334.           read_toc(2);    /* output long form */
  335.         }
  336.       else
  337.         {
  338.               read_toc(1);    /* output short form */
  339.         }
  340.       break;
  341.  
  342.       /*
  343.            ****     show volume settings
  344.            */
  345.     case 'v':
  346.       set_volume (-1, -1, -1, -1);
  347.       break;
  348.  
  349.     default:
  350.       fprintf (stderr, "Error : bad option\n");
  351.       returnvalue = 3;
  352.     }
  353.     }
  354.   else if (argc == (j + 4))
  355.     /* commands with one parameter */
  356.     {
  357.       switch (*++p)
  358.     {
  359.       /*
  360.            ****     change medium
  361.            */
  362.     case 'e':
  363.       {
  364.         int eject = -1;
  365.             
  366.             if (sscanf (argv[j + 3], "%d", &eject) != 1
  367.                 || ((eject != 0) && (eject != 1)))
  368.               {
  369.                 fprintf (stderr, "Error : eject/load control must be 0 or 1\n");
  370.                 returnvalue = 3;
  371.               }
  372.             else
  373.               {
  374.                 motor ((eject | 2));    /* eject/insert */
  375.               }
  376.       }
  377.       break;
  378.  
  379.       /*
  380.            ****     read CD-ROM data block address header
  381.            */
  382.     case 'h':
  383.       {
  384.         ULONG block;
  385.  
  386.         if (sscanf (argv[j + 3], "%lu", &block) != 1)
  387.           {
  388.             fprintf (stderr, "Error : Bad block no\n");
  389.             returnvalue = 3;
  390.           }
  391.         else
  392.           {
  393.             if (*++p == 'r')
  394.               {
  395.                 read_cdblockheader (FALSE, block);
  396.               }
  397.             else
  398.               {
  399.                 read_cdblockheader (TRUE, block);
  400.               }
  401.           }
  402.       }
  403.       break;
  404.  
  405.       /*
  406.            ****     prevent/allow medium removal
  407.            */
  408.     case 'l':
  409.       {
  410.         int lock = -1;
  411.  
  412.             if (sscanf (argv[j + 3], "%d", &lock) != 1
  413.                || ((lock != 0) && (lock != 1)) )
  414.               {
  415.                 fprintf (stderr, "Error : Medium removal control must be 0 or 1\n");
  416.                 returnvalue = 3;
  417.               }
  418.             else
  419.               {
  420.                 medium_removal (lock);    /* prevent/allow medium removal */
  421.               }
  422.       }
  423.       break;
  424.  
  425.       /*
  426.            ****     stop/start motor
  427.            */
  428.     case 'm':
  429.       {
  430.         int motoronoff = -1;
  431.  
  432.             if (sscanf (argv[j + 3], "%d", &motoronoff) != 1
  433.                || ((motoronoff != 0) && (motoronoff != 1)) )
  434.               {
  435.                 fprintf (stderr, "Error : motor control must be 0 or 1\n");
  436.                 returnvalue = 3;
  437.               }
  438.             else
  439.               {
  440.                 motor (motoronoff);    /* turn on/off motor */
  441.               }
  442.       }
  443.       break;
  444.  
  445.       /*
  446.            ****     read sectors
  447.            */
  448.  
  449.     case 'r':
  450.       /*
  451.            *        get sector #
  452.            */
  453.       if (sscanf (argv[j + 3], "%d", &secno) != 1)
  454.         {
  455.           fprintf (stderr, "Error : Bad sec no\n");
  456.           returnvalue = 3;
  457.         }
  458.       else
  459.         {
  460. #ifndef OSK
  461.           if (*++p == 't')
  462.             {
  463.                   read_sec ();    /* read sector with trackdisk.device */
  464.             }
  465.           else
  466. #endif
  467.             {
  468.                   read_sec_scsi ();    /* read sector with scsi */
  469.             }
  470.         }
  471.       break;
  472.  
  473.       /*
  474.            ****     seek to cylinder containing secno
  475.            */
  476.     case 's':
  477.       /*
  478.            *        get sector #
  479.            */
  480.       if (sscanf (argv[j + 3], "%d", &secno) != 1)
  481.         {
  482.           fprintf (stderr, "Error : Bad sec no\n");
  483.           returnvalue = 3;
  484.         }
  485.       else
  486.         {
  487.           seek ();
  488.         }
  489.       break;
  490.  
  491.     default:
  492.       fprintf (stderr, "Error : bad option\n");
  493.       returnvalue = 3;
  494.     }
  495.     }
  496.   else if (argc == (j + 5))
  497.     /* commands with two parameters */
  498.     {
  499.       ULONG startblock, numblocks;    /* used by the CDDA commands */
  500.       BYTE whichchannel = -1;        /* read left / right channel / stereo */
  501.  
  502.       switch (*++p)
  503.     {
  504.       /*
  505.            ****     read CD-DA (8 bit left|right mono)
  506.            */
  507.     case 'D':
  508.       if ((whichchannel = toupper (*(p + 1))) != 'L'
  509.           && whichchannel != 'R')
  510.         {
  511.           fprintf (stderr, "Error : must be either -DL or -DR\n");
  512.           returnvalue = 3;
  513.         }
  514.       else
  515.         {
  516.           if (sscanf (argv[j + 3], "%lu", &startblock) != 1
  517.               || sscanf (argv[j + 4], "%lu", &numblocks) != 1)
  518.             {
  519.               fprintf(stderr, "Error : invalid parameter for startblock of numblocks\n");
  520.               returnvalue = 3;
  521.             }
  522.           else
  523.             {
  524.                   read_cddaasync (startblock, numblocks, whichchannel,
  525.                   FALSE, 0);
  526.             }
  527.         }
  528.       break;
  529.  
  530. #ifdef USE8SVX
  531.       /*
  532.            ****     read CD-DA (output 8SVX 8 bit left|right|stereo)
  533.            */
  534.     case '8':
  535.       if ((whichchannel = toupper (*(p + 1))) != 'L' && whichchannel != 'R' && whichchannel != 'S')
  536.         {
  537.           fprintf (stderr, "Error : must be -8{L|R|S}\n");
  538.           returnvalue = 3;
  539.         }
  540.       else
  541.         {
  542.           if (sscanf (argv[j + 3], "%lu", &startblock) != 1
  543.               || sscanf (argv[j + 4], "%lu", &numblocks) != 1)
  544.             {
  545.               fprintf(stderr, "Error : invalid parameter for startblock of numblocks\n");
  546.             }
  547.           else
  548.             {
  549.                   write8svx = TRUE;
  550.                   read_cddaasync (startblock, numblocks, whichchannel,
  551.                   FALSE, 0);
  552.             }
  553.         }
  554.       break;
  555. #endif    /* USE8SVX */
  556.  
  557.       /*
  558.            ****     mode sense
  559.            */
  560.     case 'o':
  561.       {
  562.         int control, page;
  563.  
  564.             if (sscanf (argv[j + 3], "%d", &control) != 1 || control < 0 || control > 3)
  565.               {
  566.                 fprintf(stderr, "Error : invalid parameter for control (must be 0-4)\n");
  567.                 returnvalue = 3;
  568.               }
  569.             else
  570.               {
  571.                 if (sscanf (argv[j + 4], "%d", &page) != 1 || page < 0 || page > 0x3f)
  572.                   {
  573.                     fprintf(stderr, "Error : invalid parameter for page (must be 0-0x3f)\n");
  574.                     returnvalue = 3;
  575.                   }
  576.                 else
  577.                   {
  578.                     if (*++p == 'r')
  579.                       /* raw */
  580.                       {
  581.                         mode_sense (FALSE, control, page);
  582.                       }
  583.                     else
  584.                       /* parsed */
  585.                       {
  586.                         mode_sense (TRUE, control, page);
  587.                       }
  588.                   }
  589.               }
  590.       }
  591.           break;
  592.  
  593.  
  594.     default:
  595.       fprintf (stderr, "Error : bad option\n");
  596.       returnvalue = 3;
  597.     }
  598.     }
  599.   else if (argc == (j + 6))
  600.     /* commands with 3 parameters */
  601.     {
  602.       ULONG startblock, numblocks;    /* used by the CDDA commands */
  603.       BYTE whichchannel = -1;        /* read left / right channel / stereo */
  604.       unsigned int subcode = 0;
  605.  
  606.       switch (*++p)
  607.         {
  608.       /*
  609.            ****     read CD-DA (16 bit raw left|right|stereo)
  610.            */
  611.     case 'd':
  612.       if ((whichchannel = toupper (*(p + 1))) != 'L'
  613.           && whichchannel != 'R' && whichchannel != 'S')
  614.         {
  615.           fprintf (stderr, "Error : must be -d{L|R|S}\n");
  616.           returnvalue = 3;
  617.         }
  618.       else
  619.         {
  620.           if (sscanf (argv[j + 3], "%lu", &startblock) != 1
  621.               || sscanf (argv[j + 4], "%lu", &numblocks) != 1)
  622.             {
  623.               fprintf(stderr, "Error : invalid parameter for startblock of numblocks\n");
  624.               returnvalue = 3;
  625.             }
  626.           else
  627.             {
  628.           if (sscanf (argv[j + 5], "%u", &subcode) != 1)
  629.             {
  630.               fprintf(stderr, "Error : invalid parameter for subcode\n");
  631.               returnvalue = 3;
  632.             }
  633.           else
  634.             read_cddaasync (startblock, numblocks, whichchannel,
  635.                     TRUE, subcode);
  636.             }
  637.         }
  638.       break;
  639.  
  640.       /*
  641.            ****     read sub-channel information
  642.            */
  643.     case 'u':    /* raw */
  644.     case 'U':    /* parsed */
  645.       {
  646.         int trackno, subchannelformat, subchannel;
  647.  
  648.             /*
  649.              *        get sub-channel #
  650.              */
  651.             if (sscanf (argv[j + 3], "%d", &subchannel) != 1
  652.                 || subchannel < 0 || subchannel >255)
  653.               {
  654.                 fprintf (stderr, "Error : Sub-channel must be 0-255\n");
  655.                 returnvalue = 3;
  656.               }
  657.             /*
  658.              *        get sub-channel data format #
  659.              */
  660.             if (sscanf (argv[j + 4], "%d", &subchannelformat) != 1
  661.                 || subchannelformat < 0 || subchannelformat >255)
  662.               {
  663.                 fprintf (stderr, "Error : Sub-channel data format must be 0-255\n");
  664.                 returnvalue = 3;
  665.               }
  666.             /*
  667.              *        get track #
  668.              */
  669.             if (sscanf (argv[j + 5], "%d", &trackno) != 1 || trackno < 0
  670.                 || trackno > 99)
  671.               {
  672.                 fprintf (stderr, "Error : Bad track no (must be 1-99)\n");
  673.                 returnvalue = 3;
  674.               }
  675.             else
  676.               {
  677.                 if (*++p == 'r')
  678.                   {
  679.                     read_subchannel (FALSE,subchannel, subchannelformat, trackno);
  680.                   }
  681.                 else
  682.                   {
  683.                     read_subchannel (TRUE,subchannel, subchannelformat, trackno);
  684.                   }
  685.               }
  686.         }
  687.       break;
  688.  
  689.     default:
  690.       fprintf (stderr, "Error : bad option\n");
  691.       returnvalue = 3;
  692.     }
  693.  
  694.     }
  695.  
  696.   else if (argc == (j + 7))
  697.     /* commands with 4 parameters */
  698.     {
  699.       switch (*++p)
  700.     {
  701.       /*
  702.            ****     play audio
  703.            */
  704.     case 'p':
  705.       {
  706.         int starttrack, startindex, endtrack, endindex;
  707.  
  708.             if (sscanf (argv[j + 3], "%d", &starttrack) != 1
  709.                 || (starttrack < 1) || (starttrack > 99))
  710.               {
  711.                 fprintf (stderr, "Error : Starting audio track must be in the range 1-99\n");
  712.                 returnvalue = 3;
  713.                 goto error;
  714.               }
  715.             if (sscanf (argv[j + 4], "%d", &startindex) != 1
  716.                 || (startindex < 0) || (startindex > 99))
  717.               {
  718.                 fprintf (stderr, "Error : Starting audio track index must be in the range 1-99\n");
  719.                 returnvalue = 3;
  720.                 goto error;
  721.               }
  722.             if (sscanf (argv[j + 5], "%d", &endtrack) != 1
  723.                 || (endtrack < 1) || (endtrack > 99))
  724.               {
  725.                 fprintf (stderr, "Error : Ending audio track must be in the range 1-99\n");
  726.                 returnvalue = 3;
  727.                 goto error;
  728.               }
  729.             if (sscanf (argv[j + 6], "%d", &endindex) != 1
  730.                 || (endindex < 0) || (endindex > 99))
  731.               {
  732.                 fprintf (stderr, "Error : Ending audio track index must be in the range 1-99\n");
  733.                 returnvalue = 3;
  734.                 goto error;
  735.               }
  736.             play_audio (starttrack, startindex, endtrack, endindex);
  737.       }
  738.       break;
  739.  
  740.       /*
  741.            ****     change volume settings
  742.            */
  743.     case 'v':
  744.       {
  745.         int i;
  746.         int vol[4];
  747.  
  748.         for (i = 0; i < 4; i++)
  749.           {
  750.         if (sscanf (argv[j + 3 + i], "%d", &vol[i]) != 1
  751.             || (vol[i] < -1) || (vol[i] > 255))
  752.           {
  753.             fprintf (stderr, "Error : Volume %d must be in the range -1 - 255\n", i);
  754.             returnvalue = 3;
  755.             goto error;
  756.           }
  757.           }
  758.         set_volume (vol[0], vol[1], vol[2], vol[3]);
  759.       }
  760.       break;
  761.  
  762.     default:
  763.       fprintf (stderr, "Error : bad option\n");
  764.       returnvalue = 3;
  765.     }
  766.     }
  767.   else
  768.     {
  769.       fprintf (stderr, "Error : bad option\n");
  770.       returnvalue = 3;
  771.     }
  772.  
  773. error:
  774.  
  775.   for (i = 0; i < NDBLBUF; i++)
  776.     {
  777.       if (io_ptr[i])
  778.     {
  779.       CloseDevice ((struct IORequest *) io_ptr[i]);
  780.       DeleteStdIO (io_ptr[i]);
  781.     }
  782.  
  783.       if (cdda_buf[i])
  784.     FreeMem (cdda_buf[i], MAX_CDDALEN);
  785.  
  786.       if (mp_ptr[i])
  787.     DeletePort (mp_ptr[i]);
  788.  
  789.       if (scsi_sense[i])
  790.     FreeMem (scsi_sense[i], SENSE_LEN);
  791.  
  792.       if (mono_buf)
  793.     FreeMem (mono_buf[i], MAX_CDDALEN / 2);
  794.     }
  795.  
  796.   if (toc_buf)
  797.     FreeMem (toc_buf, MAX_TOC_LEN);
  798.  
  799.   if (ip_buf)
  800.     FreeMem (ip_buf, TD_SECTOR);
  801.  
  802.   if (scsi_data)
  803.     FreeMem (scsi_data, MAX_DATA_LEN);
  804.  
  805. #ifdef _DCC
  806.   onbreak(oldbrkhandler);
  807. #endif
  808.   exit (returnvalue);
  809. }
  810.  
  811. /*********************************************************************
  812.  *
  813.  *    Initialization function
  814.  *
  815.  */
  816. BOOLEAN
  817. init (void)
  818. {
  819.   int i;
  820.  
  821.   if ((scsi_data = (UBYTE *) AllocMem (MAX_DATA_LEN, MEMF_CHIP | MEMF_CLEAR)) == NULL)
  822.     {
  823.       fprintf (stderr, "AllocMem(0) Fail\n");
  824.       return FALSE;
  825.     }
  826.  
  827.   if ((ip_buf = (UBYTE *) AllocMem (TD_SECTOR, MEMF_CHIP)) == NULL)
  828.     {
  829.       fprintf (stderr, "AllocMem(2) Fail\n");
  830.       return FALSE;
  831.     }
  832.  
  833.   if ((toc_buf = (UBYTE *) AllocMem (MAX_TOC_LEN, MEMF_CHIP)) == NULL)
  834.     {
  835.       fprintf (stderr, "AllocMem(3) Fail\n");
  836.       return FALSE;
  837.     }
  838.  
  839.   for (i = 0; i < NDBLBUF; i++)
  840.     {
  841.       if ((scsi_sense[i] = (UBYTE *) AllocMem (SENSE_LEN, MEMF_CHIP || MEMF_CLEAR)) == NULL)
  842.     {
  843.       fprintf (stderr, "AllocMem (scsi_sense[%d]) Fail\n",i);
  844.       return FALSE;
  845.     }
  846.       if ((cdda_buf[i] = (UBYTE *) AllocMem (MAX_CDDALEN, 0)) == NULL)
  847.     {
  848.       fprintf (stderr, "AllocMem (cdda_buf[%d]) Fail\n",i);
  849.       return FALSE;
  850.     }
  851.  
  852.       if ((mp_ptr[i] = (MSGPORT *) CreatePort (NULL, 0)) == NULL)
  853.     {
  854.       fprintf (stderr, "CreatePort (mp_ptr[%d]) Fail\n",i);
  855.       return FALSE;
  856.     }
  857.       if ((io_ptr[i] = (IOSTDREQ *) CreateStdIO (mp_ptr[i])) == NULL)
  858.     {
  859.       fprintf (stderr, "CreateStdIO (io_ptr[%d]) Fail\n",i);
  860.       return FALSE;
  861.     }
  862.       if (OpenDevice (dev, scsi_id, (struct IORequest *) io_ptr[i], 0) != 0)
  863.     {
  864. #ifndef OSK
  865.       fprintf (stderr,
  866.            "Error %d while opening SCSI dev \"%s\", unit (%d)\n",
  867.            io_ptr[i]->io_Error, dev, scsi_id, i);
  868.       return FALSE;
  869. #else
  870.       fprintf (stderr,
  871.            "Error %d while opening SCSI dev \"%s\"\n", errno, dev);
  872.       return FALSE;
  873. #endif
  874.     }
  875.       if ((mono_buf[i] = (BYTE *) AllocMem (MAX_CDDALEN / 2, 0)) == NULL)
  876.     {
  877.       fprintf (stderr, "AllocMem (mono_buf[%d]) Fail\n",i);
  878.       return FALSE;
  879.     }
  880.  
  881.     }
  882.  
  883.   return TRUE;
  884. }
  885.  
  886. /*********************************************************************
  887.  *
  888.  *    function to read parameter pages from a device
  889.  */
  890.  
  891. void
  892. mode_sense (BOOLEAN parsed, UBYTE control, UBYTE page)
  893. {
  894.   static SCSICMD6 command =
  895.   {
  896.     SCSI_CMD_MSE,    /* 0x1a MODE SENSE scsi command */
  897.     PAD,        /* LUN | rsrvd. | DBD | rsrvd. */
  898.     0,            /* PC | Page Code */
  899.     PAD,        /* rsrvd. */
  900.     0,            /* allocation length */
  901.     PAD            /* control */
  902.   };
  903.  
  904.   static IDTOSTRING pagecontrolfield[] =
  905.   {
  906.     0x00, "Current Values",
  907.     0x01, "Changeable Values",
  908.     0x02, "Default Values",
  909.     0x03, "Saved Values",
  910.     -1, "Illegal value"
  911.   };
  912.  
  913.   UWORD i,j;
  914.   int err;
  915.  
  916.   command.b2 = (control<<6) | page;
  917.   command.b4 = MAX_DATA_LEN;
  918.  
  919.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  920.                         (UBYTE *) &command, sizeof (command),
  921.                         (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  922.     {
  923.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  924.     }
  925.   else
  926.     {
  927.       if (parsed == TRUE)
  928.         /* output parsed data */
  929.         {
  930.           printf ("%s\n", id2string(control, pagecontrolfield));
  931.           printf ("Mode Parameter Header:\n");
  932.           printf (" Mode Data Length: %hu\n", scsi_data[0]);
  933.           printf (" Medium Type: %hu\n", scsi_data[1]);
  934.           printf (" Device-Specific Parameter: %hu\n", scsi_data[2]);
  935.           printf (" Block Descriptor Length: %hu\n", scsi_data[3]);
  936.  
  937.       for (i = 0; i < scsi_data[3]; i +=8)    /* print block descriptors */
  938.         {
  939.           printf("Block Descriptor Density Code: %hu\n",scsi_data[(i)+4]);
  940.           printf(" Number of Blocks: %lu\n", (scsi_data[(i)+5]<<16) + (scsi_data[(i)+6]<<8) + (scsi_data[(i)+7]) );
  941.           printf(" Byte 4 (reserved): %hu\n", scsi_data[(i)+8]);
  942.           printf(" Block length: %lu\n", (scsi_data[(i)+9]<<16) + (scsi_data[(i)+10]<<8) + (scsi_data[(i)+11]) );
  943.         }
  944.  
  945.       for (j = (scsi_data[0]+1), i = scsi_data[3] + 4; i < j; i += scsi_data[i+1] + 2)
  946.         {
  947.           printf("Page Code: %hu\n",scsi_data[i] & 0x3f);
  948.           printf(" Page can%s be saved\n", (scsi_data[i] & 0x80) ? "" : " not");
  949.           printf(" Page Length: %hu\n", scsi_data[i+1]);
  950.           printf(" Mode Parameters:\n");
  951.           rawhexasciioutput(&scsi_data[i+2], scsi_data[i+1], 2);
  952.         }
  953.         }
  954.       else
  955.         /* output raw data */
  956.         {
  957.           rawhexasciioutput(scsi_data, scsi_data[0]+1, 0);
  958.         }
  959.     }
  960. }
  961.  
  962. /*********************************************************************
  963.  *
  964.  *    function to read CD-ROM data block address header
  965.  *    starting block and number of blocks.
  966.  */
  967.  
  968. void
  969. read_cdblockheader (BOOLEAN parsed, ULONG block)
  970. {
  971.   static SCSICMD10 command =
  972.   {
  973.     SCSI_CMD_READHEADER,    /* 0x44 READ HEADER scsi command */
  974.     0,                /* LUN | rsrvd. | MSF | rsrvd. */
  975.     0, 0, 0, 0,            /* Logical Block Address (ULONG) */
  976.     PAD,            /* reserved */
  977.     0,0,            /* allocated data length */
  978.     PAD                /* control */
  979.   };
  980.  
  981.   static IDTOSTRING udatafieldcont[] =
  982.   {
  983.     0x00, "All bytes zero",
  984.     0x01, "User Data",
  985.     0x02, "User Data",
  986.     -1, "Reserved"
  987.   };
  988.  
  989.   static IDTOSTRING auxfieldcont[] =
  990.   {
  991.     0x00, "All bytes zero",
  992.     0x01, "L-EC symbols",
  993.     0x02, "User Data",
  994.     -1, "Reserved"
  995.   };
  996.  
  997.   int err;
  998.  
  999.   command.b2 = block>>24;
  1000.   command.b3 = block>>16;
  1001.   command.b4 = block>>8;
  1002.   command.b5 = block;
  1003. #if MAX_CDDALEN > 65536
  1004.   command.b7 = 255;
  1005.   command.b8 = 255;
  1006. #else
  1007.   command.b7 = MAX_CDDALEN>>8;
  1008.   command.b8 = MAX_CDDALEN & 0xff;
  1009. #endif
  1010.   if ((err = DoScsiCmd ((UBYTE *) cdda_buf[0], MAX_CDDALEN,
  1011.                         (UBYTE *) &command, sizeof (command),
  1012.                         (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1013.     {
  1014.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1015.     }
  1016.   else
  1017.     {
  1018.       if (parsed == TRUE)
  1019.         {
  1020.           printf("User Data Field Contents (2048 bytes): %d = %s\n",
  1021.          (cdda_buf[0])[0], id2string ((cdda_buf[0])[0], udatafieldcont));
  1022.           printf("Auxiliary Field Contents ( 288 bytes): %d = %s\n",
  1023.          (cdda_buf[0])[0], id2string ((cdda_buf[0])[0], auxfieldcont));
  1024.           printf("Byte 1 (reserved): %d\n",(cdda_buf[0])[1]);
  1025.           printf("Byte 2 (reserved): %d\n",(cdda_buf[0])[2]);
  1026.           printf("Byte 3 (reserved): %d\n",(cdda_buf[0])[3]);
  1027.           printf("Absolute CD-ROM Address: %lu\n",
  1028.          ((cdda_buf[0])[4] << 24) | ((cdda_buf[0])[5] << 16) | ((cdda_buf[0])[6] << 8) | ((cdda_buf[0])[7]));
  1029.         }
  1030.       else
  1031.         {
  1032.           rawhexasciioutput(cdda_buf[0], 8, 0);
  1033.         }
  1034.     }
  1035. }
  1036.  
  1037. /*********************************************************************
  1038.  *
  1039.  *    function to read subchannel data audio from Sony CDROM with
  1040.  *    starting block and number of blocks.
  1041.  */
  1042.  
  1043. void
  1044. read_subchannel (BOOLEAN parsed, UBYTE subchannel, UBYTE subchannelformat, UBYTE track)
  1045. {
  1046.   static SCSICMD10 command =
  1047.   {
  1048.     SCSI_CMD_READSUBCHANNEL,    /* 0x42 READ SUB-CHANNEL scsi command */
  1049.     0,                /* LUN | rsrvd. | MSF | rsrvd. */
  1050.     0x40,            /* return Sub-Q Channel data */
  1051.     0,                /* Sub-channel Data Format */
  1052.     PAD,
  1053.     PAD,
  1054.     0,                /* Track Number 1-99 */
  1055.     0,0,            /* allocated data length */
  1056.     PAD                /* control */
  1057.   };
  1058.  
  1059.   static IDTOSTRING audiostatus[] =
  1060.   {
  1061.     0x00, "Audio status byte not supported or not valid",
  1062.     0x11, "Audio play operation in progress.",
  1063.     0x12, "Audio play operation paused.",
  1064.     0x13, "Audio play operation successfully completed.",
  1065.     0x14, "Audio play operation stopped due to error.",
  1066.     0x15, "No current audio status to return",
  1067.     -1, "Reserved, unknown or no audio status"
  1068.   };
  1069.  
  1070.   static IDTOSTRING Qfield[] =
  1071.   {
  1072.     0x00, "Sub-channel Q mode information not supplied.",
  1073.     0x01, "Sub-channel Q encodes current position data.",
  1074.     0x02, "Sub-channel Q encodes media catalog number.",
  1075.     0x03, "Sub-channel Q encodes ISRC.",
  1076.     -1, "Reserved"
  1077.   };
  1078.  
  1079.   int err;
  1080.  
  1081.   command.b2 = subchannel;
  1082.   command.b3 = subchannelformat;
  1083.   command.b6 = track;
  1084.  
  1085. #if MAX_CDDALEN > 65536
  1086.   command.b7 = 255;
  1087.   command.b8 = 255;
  1088. #else
  1089.   command.b7 = MAX_CDDALEN & 0xff;
  1090.   command.b8 = MAX_CDDALEN>>8;    /* Allocation length = max. data length */
  1091. #endif
  1092.  
  1093.   if ((err = DoScsiCmd ((UBYTE *) cdda_buf[0], MAX_CDDALEN,
  1094.                         (UBYTE *) &command, sizeof (command),
  1095.                         (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1096.     {
  1097.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1098.     }
  1099.   else
  1100.     {
  1101.       if (parsed == TRUE)
  1102.         /* parsed output */
  1103.         {
  1104.           if (subchannel == 0x40)
  1105.             {
  1106.               if (subchannelformat == 0)
  1107.                 {
  1108.     /* CHANGE - this doesn't work with my Apple CD300!!!!! */
  1109.           rawhexoutput(cdda_buf[0], ((cdda_buf[0])[2]*256 + (cdda_buf[0])[3])+4);
  1110.                 }
  1111.               else if (subchannelformat == 1)
  1112.                 {
  1113.           printf("Byte 0 (reserved): %02x\n",(cdda_buf[0])[0]);
  1114.           printf("Audio status: %s\n",id2string ((cdda_buf[0])[1],audiostatus));
  1115.           printf("Sub-Channel Data Length: %d\n",((cdda_buf[0])[2]*256 + (cdda_buf[0])[3]));
  1116.           printf("Sub-Channel Data Format code (should be 0x01!): %d\n",(cdda_buf[0])[4]);
  1117.           printf("ADR: %s\n",id2string(((cdda_buf[0])[5]>>4 & 0x0f), Qfield));
  1118.  
  1119.           printf("Audio with%s pre-emphasis.  ", ((cdda_buf[0])[5] & 0x01) ? "" : "out");
  1120.           printf("Digital copy %s\n", ((cdda_buf[0])[5] & 0x02) ? "permitted" : "prohibited");
  1121.           printf("%s track.  ", ((cdda_buf[0])[5] & 0x04) ? "Data" : "Audio");
  1122.           printf("%s channel audio.\n", ((cdda_buf[0])[5] & 0x08) ? "Four" : "Two");
  1123.  
  1124.           printf("Track Number: %d\n", (cdda_buf[0])[6]);
  1125.           printf("Index Number: %d\n", (cdda_buf[0])[7]);
  1126.           printf("Absolute CD-ROM Address: %lu\n", ((cdda_buf[0])[8] << 24) | ((cdda_buf[0])[9] << 16) | ((cdda_buf[0])[10] << 8) | ((cdda_buf[0])[11]));
  1127.           printf("Track Relative CD-ROM Address: %lu\n", ((cdda_buf[0])[12] << 24) | ((cdda_buf[0])[13] << 16) | ((cdda_buf[0])[14] << 8) | ((cdda_buf[0])[15]));
  1128.                 }
  1129.               else if (subchannelformat == 2)
  1130.                 {
  1131.           printf("Byte 0 (reserved): %02x\n",(cdda_buf[0])[0]);
  1132.           printf("Audio status %s\n",id2string ((cdda_buf[0])[1],audiostatus));
  1133.           printf("Sub-Channel Data Length %d\n",((cdda_buf[0])[2]*256 + (cdda_buf[0])[3]));
  1134.           printf("Sub-Channel Data Format code (should be 0x02!): %d\n",(cdda_buf[0])[4]);
  1135.           printf("Byte 5 (reserved): %02x\n",(cdda_buf[0])[5]);
  1136.           printf("Byte 6 (reserved): %02x\n",(cdda_buf[0])[6]);
  1137.           printf("Byte 7 (reserved): %02x\n",(cdda_buf[0])[7]);
  1138.           printf("Byte 8 (reserved): %02x\n",(cdda_buf[0])[8] & 0x7f);
  1139.           printf("MCVal is %s\n", ((cdda_buf[0])[8] & 0x80) ? "true" : "false");
  1140.           printf("Media Catalog Number (UPC/Bar Code):\n");
  1141.           rawhexasciioutput(&(cdda_buf[0])[9], 15, 1);
  1142.                 }
  1143.               else if (subchannelformat == 3)
  1144.                 {
  1145.           printf("Byte 0 (reserved): %02x\n",(cdda_buf[0])[0]);
  1146.           printf("Audio status %s\n",id2string ((cdda_buf[0])[1],audiostatus));
  1147.           printf("Sub-Channel Data Length %d\n",((cdda_buf[0])[2]*256 + (cdda_buf[0])[3]));
  1148.           printf("Sub-Channel Data Format code (should be 0x03!): %d\n",(cdda_buf[0])[4]);
  1149.           printf("ADR: %s\n",id2string(((cdda_buf[0])[5]>>4 & 0x0f) ,Qfield));
  1150.  
  1151.           printf("Audio with%s pre-emphasis.  ", ((cdda_buf[0])[5] & 0x01) ? "" : "out");
  1152.           printf("Digital copy %s\n", ((cdda_buf[0])[5] & 0x02) ? "permitted" : "prohibited");
  1153.           printf("%s track.  ", ((cdda_buf[0])[5] & 0x04) ? "Data" : "Audio");
  1154.           printf("%s channel audio.\n", ((cdda_buf[0])[5] & 0x08) ? "Four" : "Two");
  1155.  
  1156.           printf("Track Number: %d\n", (cdda_buf[0])[6]);
  1157.           printf("Byte 7 (reserved): %02x\n",(cdda_buf[0])[7]);
  1158.           printf("Byte 8 (reserved): %02x\n",(cdda_buf[0])[8] & 0x7f);
  1159.           printf("TCVal is %s\n", ((cdda_buf[0])[8] & 0x80) ? "true" : "false");
  1160.           printf("Track International-Standard-Recording-Code (ISRC):\n");
  1161.           rawhexasciioutput(&(cdda_buf[0])[9], 15, 1);
  1162.                 }
  1163.               else
  1164.                 {
  1165.                   rawhexasciioutput(cdda_buf[0], ((cdda_buf[0])[2]*256 + (cdda_buf[0])[3])+4, 0);
  1166.                 }
  1167.             }
  1168.           else
  1169.             {
  1170.               rawhexasciioutput(cdda_buf[0], ((cdda_buf[0])[2]*256 + (cdda_buf[0])[3])+4, 0);
  1171.             }
  1172.         }
  1173.       else
  1174.         /* raw output */
  1175.         {
  1176.       rawhexasciioutput(cdda_buf[0], ((cdda_buf[0])[2]*256 + (cdda_buf[0])[3])+4, 0);
  1177.         }
  1178.     }
  1179.  
  1180. }
  1181.  
  1182. /*********************************************************************
  1183.  *
  1184.  * subroutine used to printout raw hex data bytes
  1185.  *
  1186.  */
  1187. void
  1188. rawhexoutput (UBYTE *p, UWORD numbytes)
  1189. {
  1190.   UWORD i;
  1191.  
  1192.   for (i = 0; i < numbytes; i++)
  1193.     {
  1194.       printf (" %02x", p[i]);
  1195.     }
  1196.   printf ("\n");
  1197. }
  1198.  
  1199. /*********************************************************************
  1200.  *
  1201.  * subroutine used to printout raw hex data bytes with the
  1202.  * corresponding ASCII values and an index
  1203.  *
  1204.  */
  1205. void
  1206. rawhexasciioutput (UBYTE *p, UWORD numbytes, UBYTE leadspace)
  1207. {
  1208.   UWORD i, j;
  1209.   UBYTE *boff, *aoff;
  1210.   int xxxlen = strlen (" xx");            /* byte */
  1211.  
  1212.   buffer[5+leadspace] = '=';
  1213.  
  1214.   for (i = 0; i < numbytes; i += BYTES_PER_LINE)
  1215.     {
  1216.       memset (buffer, ' ', sizeof (buffer));    /* put spaces in buffer */
  1217.       boff = &buffer[7+leadspace];
  1218.       aoff = boff + (xxxlen * BYTES_PER_LINE) + 1;
  1219.  
  1220.       sprintf (buffer+leadspace, "%04X = ", i);        /* add offset */
  1221.  
  1222.       for (j = 0; (j < BYTES_PER_LINE && (i+j) < numbytes); j++, boff += xxxlen, p++, aoff++)
  1223.         {
  1224.           sprintf (boff, " %02X", *p);
  1225.           *aoff = (isascii (*p) && isprint (*p)) ? *p : '.';
  1226.         }
  1227.  
  1228.       buffer[strlen (buffer)] = ' ';
  1229.       *++aoff = '\n';
  1230.       *++aoff = '\0';
  1231.       printf ("%s", buffer);
  1232.     }
  1233. }
  1234.  
  1235. /*********************************************************************
  1236.  *
  1237.  *    function to read digital audio from Sony / Toshiba CD-ROM with
  1238.  *    starting block and number of blocks.
  1239.  *    This version uses asynchronous reads.
  1240.  *
  1241.  *    outputs LRLRLR pairs of 16 bit digital stereo audio samples,
  1242.  *    2352 / 2368 / 2448 / 96 bytes per CD-ROM block
  1243.  *
  1244.  *      or (depending on 'whichchannel')
  1245.  *
  1246.  *      8 bit digital audio samples, either the left or right channel.
  1247.  */
  1248.  
  1249. #ifdef _DCC
  1250. __stkargs
  1251. #endif
  1252. void
  1253. read_cddaasync (ULONG startblock, ULONG numblocks, BYTE whichchannel,
  1254.         BYTE use16bit, unsigned int subcode)
  1255. {
  1256. #ifndef OSK
  1257.   static struct CMD_RDCDDA
  1258.   {
  1259.     UBYTE cmd;            /* READ CD-DA scsi command 0xD8 */
  1260.     UBYTE pad_a;        /* Bits 7-5 Logical Unit Number | Bits 4-1 Reserved | Bit 0 EVPD */
  1261.     ULONG lba;            /* logical block address MSB, , ,LSB */
  1262.     ULONG lbn;            /* number of blocks to transfer MSB, , ,LSB */
  1263.     UBYTE subcode;        /* special sub code selector:
  1264.                       * 0: normal 2352
  1265.                  * 1: 2368
  1266.                  * 2: 2448
  1267.                  * 3: 96 bytes */
  1268.     UBYTE cntrl;        /* Control */
  1269.   } command[NDBLBUF];
  1270.  
  1271.   /*
  1272.    * TOSHIBA XM3401 specific
  1273.    */
  1274.   static SCSICMD6 modecommand;
  1275.   static struct cddamodedata
  1276.   {
  1277.     UWORD pad0;
  1278.     UBYTE pad1;
  1279.     UBYTE bdlength;
  1280.     ULONG density;   /* = densitycode << 24 */
  1281.     ULONG blocklen;
  1282.   } newmodedata;
  1283.  
  1284.  
  1285.   int err, i = 0, j = 0, k = 0, l = 0;
  1286.   ULONG nblocks = numblocks, xblocks;
  1287.  
  1288.   finddrivebrand();        /* determine CD-ROM drive */
  1289.  
  1290.   /*
  1291.    * TOSHIBA XM3401 specific
  1292.    */
  1293.   if (whatdrive == TOSHIBA3401)
  1294.     {
  1295.       /* Read old mode data */
  1296.       modecommand.opcode  = SCSI_CMD_MSE;
  1297.       modecommand.b1      = 0;
  1298.       modecommand.b2      = 1;
  1299.       modecommand.b3      = 0;
  1300.       modecommand.b4      = MAX_DATA_LEN;
  1301.       modecommand.control = 0;
  1302.       if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  1303.                 (UBYTE *) &modecommand, sizeof (modecommand),
  1304.                 (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1305.     {
  1306.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1307.       return;
  1308.     }
  1309.       /* Write new mode data */
  1310.       newmodedata.pad0     = 0;
  1311.       newmodedata.pad1     = 0;
  1312.       newmodedata.bdlength = 8;
  1313.       newmodedata.density  = 0x82L << 24;
  1314.       newmodedata.blocklen = 2352;
  1315.       modecommand.opcode = SCSI_CMD_MSL;
  1316.       modecommand.b1     = 0x10;
  1317.       modecommand.b2     = 0;
  1318.       modecommand.b4     = sizeof(struct cddamodedata);
  1319.       if ((err = DoScsiCmd ((UBYTE *) &newmodedata, sizeof(struct cddamodedata),
  1320.                 (UBYTE *) &modecommand, sizeof (modecommand),
  1321.                 (SCSIF_WRITE | SCSIF_AUTOSENSE))) != 0)
  1322.     {
  1323.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1324.       return;
  1325.     }
  1326.     } /* TOSHIBA */
  1327.  
  1328.   /* reset SCSI status to no command pending
  1329.    */
  1330.   for (i = 0; i < NDBLBUF; i++)
  1331.     scsi_status[i] = 0;
  1332.  
  1333.   for (i = 0; ; (++i >= NDBLBUF)? i = 0 : i)
  1334.     {
  1335.       if (breakcheck ())    /* ^C ? */
  1336.     {
  1337.       /* wait for pending SCSI commands
  1338.        */
  1339.       for (j = 0, i++; j < NDBLBUF; j++, (++i >= NDBLBUF)? i = 0 : i)
  1340.         {
  1341.           if (scsi_status[i] == 1)
  1342.         WaitScsiCmd(i);
  1343.         }
  1344.       return;
  1345.     }
  1346.       if (nblocks > 0)
  1347.     {
  1348.       if (scsi_status[i] == 1)    /* SCSI command pending? */
  1349.         {
  1350.           if ((err = WaitScsiCmd (i)) != 0)    /* read failed, reschedule */
  1351.         {
  1352.           scsi_status[i] = 0;
  1353.           do
  1354.             {
  1355.               fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1356.  
  1357.               if (breakcheck ())    /* ^C ? */
  1358.             {
  1359.               for (j = 0, i++; j < NDBLBUF; j++, (++i >= NDBLBUF)? i = 0 : i)
  1360.                 {
  1361.                   if (scsi_status[i] == 1)
  1362.                 WaitScsiCmd(i);
  1363.                 }
  1364.               return;
  1365.             }
  1366.               
  1367.               SendScsiCmd (i, (UBYTE *) cdda_buf[i], MAX_CDDALEN,
  1368.                    (UBYTE *) & command[i], sizeof (command[i]),
  1369.                    (SCSIF_READ | SCSIF_AUTOSENSE));
  1370.             }
  1371.           while ((err = WaitScsiCmd (i)) != 0);
  1372.         }
  1373.           scsi_status[i] = 0;    /* no SCSI command pending anymore */
  1374.  
  1375.           if (use16bit == TRUE && whichchannel == 'S')
  1376.         /* output 16 bit stereo samples */
  1377.         {
  1378.           fwrite (cdda_buf[i], scsi_cmd[i].scsi_Actual, 1, stdout);
  1379.         }
  1380.           else if (whichchannel == 'L')
  1381.         /* output left channel */
  1382.         {
  1383.           if (use16bit == FALSE)
  1384.             /* output raw 8 bit left channel */
  1385.             {
  1386.               for (j = 0; j < (scsi_cmd[i].scsi_Actual / 4); j++)
  1387.             {
  1388.               (mono_buf[i])[j] = (BYTE) (((cdda_buf[i])[(4 * j)] +
  1389.                               ((cdda_buf[i])[(4 * j) + 1] * 256)) / 256);
  1390.             }
  1391.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 4), 1, stdout);
  1392.             }
  1393.           else
  1394.             /* output raw 16 bit left channel */
  1395.             {
  1396.               for (j = 0, k = 0; j < (scsi_cmd[i].scsi_Actual); j += 4)
  1397.             {
  1398.               (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j]);
  1399.               (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 1]);
  1400.             }
  1401.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 2), 1, stdout);
  1402.             }
  1403.         }
  1404.           else
  1405.         /* output right channel */
  1406.         {
  1407.           if (use16bit == FALSE)
  1408.             /* output raw 8 bit left channel */
  1409.             {
  1410.               for (j = 0; j < (scsi_cmd[i].scsi_Actual / 4); j++)
  1411.             {
  1412.               (mono_buf[i])[j] = (BYTE) (((cdda_buf[i])[(4 * j) + 2] +
  1413.                               ((cdda_buf[i])[(4 * j) + 3] * 256)) / 256);
  1414.             }
  1415.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 4), 1, stdout);
  1416.             }
  1417.           else
  1418.             /* output raw 16 bit left channel */
  1419.             {
  1420.               for (j = 0, k = 0; j < (scsi_cmd[i].scsi_Actual); j += 4)
  1421.             {
  1422.               (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 2]);
  1423.               (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 3]);
  1424.             }
  1425.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 2), 1, stdout);
  1426.             }
  1427.         }
  1428.         }    /* (scsi_status[i] == 1) ? */
  1429.  
  1430.       if (whatdrive == TOSHIBA3401)
  1431.             {
  1432.               command[i].cmd = SCSI_CMD_READ12;   /* TOSHIBA XM3401 */
  1433.             }
  1434.       else
  1435.         {
  1436.               command[i].cmd = SCSI_CMD_READCDDA; /* Sony CDU-5*1 */
  1437.             }
  1438.           command[i].pad_a = 0;
  1439.           command[i].lba = startblock;
  1440.           command[i].lbn = xblocks = (nblocks > NUM_OF_CDDAFRAMES)? NUM_OF_CDDAFRAMES : nblocks;
  1441.       command[i].subcode = subcode;
  1442.       command[i].cntrl = 0;
  1443.  
  1444.       startblock += xblocks;
  1445.       nblocks -= xblocks;
  1446.  
  1447.       scsi_status[i] = 1;    /* Status: SCSI command pending */
  1448.  
  1449.       SendScsiCmd (i, (UBYTE *) cdda_buf[i], MAX_CDDALEN,
  1450.                (UBYTE *) & command[i], sizeof (command[i]),
  1451.                (SCSIF_READ | SCSIF_AUTOSENSE));
  1452.  
  1453.     }
  1454.       else    /* nblocks <= 0 */
  1455.     {
  1456.       /* wait for all pending requests */
  1457.       for (l = 0; l < NDBLBUF; l++)
  1458.         {
  1459.           if (scsi_status[i] == 1)    /* SCSI command pending ? */
  1460.         {
  1461.           if ((err = WaitScsiCmd (i)) != 0) /* SCSI command failed? */
  1462.             {
  1463.               scsi_status[i] = 0;
  1464.               do    /* reschedule SCSI command */
  1465.             {
  1466.               fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1467.  
  1468.               if (breakcheck ()) /* ^C ? */
  1469.                 {
  1470.                   /* wait for pending SCSI commands
  1471.                    */
  1472.                   for (j = 0, i++; j < NDBLBUF; j++, (++i >= NDBLBUF)? i = 0 : i)
  1473.                 {
  1474.                   if (scsi_status[i] == 1)
  1475.                     WaitScsiCmd(i);
  1476.                 }
  1477.                   return;
  1478.                 }
  1479.               
  1480.               SendScsiCmd (i, (UBYTE *) cdda_buf[i], scsi_cmd[i].scsi_Length,
  1481.                        (UBYTE *) & command[i], sizeof (command[i]),
  1482.                        (SCSIF_READ | SCSIF_AUTOSENSE));
  1483.               
  1484.             }
  1485.               while ((err = WaitScsiCmd (i)) != 0);
  1486.             }
  1487.           scsi_status[i] = 0;    /* Status: no SCSI command pending */
  1488.  
  1489.           if (use16bit == TRUE && whichchannel == 'S')
  1490.             /* output 16 bit stereo samples */
  1491.             {
  1492.               fwrite (cdda_buf[i], scsi_cmd[i].scsi_Actual, 1, stdout);
  1493.             }
  1494.           else if (whichchannel == 'L')
  1495.             /* output left channel */
  1496.             {
  1497.               if (use16bit == FALSE)
  1498.             /* output raw 8 bit left channel */
  1499.             {
  1500.               for (j = 0; j < (scsi_cmd[i].scsi_Actual / 4); j++)
  1501.                 {
  1502.                   (mono_buf[i])[j] = (BYTE) (((cdda_buf[i])[(4 * j)] +
  1503.                               ((cdda_buf[i])[(4 * j) + 1] * 256)) / 256);
  1504.                 }
  1505.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 4), 1, stdout);
  1506.             }
  1507.               else
  1508.             /* output raw 16 bit left channel */
  1509.             {
  1510.               for (j = 0, k = 0; j < (scsi_cmd[i].scsi_Actual); j += 4)
  1511.                 {
  1512.                   (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j]);
  1513.                   (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 1]);
  1514.                 }
  1515.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 2), 1, stdout);
  1516.             }
  1517.             }
  1518.           else
  1519.             /* output right channel */
  1520.             {
  1521.               if (use16bit == FALSE)
  1522.             /* output raw 8 bit left channel */
  1523.             {
  1524.               for (j = 0; j < (scsi_cmd[i].scsi_Actual / 4); j++)
  1525.                 {
  1526.                   (mono_buf[i])[j] = (BYTE) (((cdda_buf[i])[(4 * j) + 2] +
  1527.                               ((cdda_buf[i])[(4 * j) + 3] * 256)) / 256);
  1528.                 }
  1529.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 4), 1, stdout);
  1530.             }
  1531.               else
  1532.             /* output raw 16 bit left channel */
  1533.             {
  1534.               for (j = 0, k = 0; j < (scsi_cmd[i].scsi_Actual); j += 4)
  1535.                 {
  1536.                   (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 2]);
  1537.                   (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 3]);
  1538.                 }
  1539.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 2), 1, stdout);
  1540.             }
  1541.             }        /* output right channel */
  1542.  
  1543.           scsi_status[i] = 0;
  1544.  
  1545.         }    /* (scsi_status[i] == 1) ? */
  1546.  
  1547.           (++i >= NDBLBUF)? i = 0 : i;
  1548.  
  1549.         }  /* for (l = 0; l < NDBLBUF; l++) */
  1550.  
  1551.       break;
  1552.     }
  1553.     }
  1554.   if (whatdrive == TOSHIBA3401)
  1555.     {
  1556.       /*
  1557.        * TOSHIBA XM3401 specific
  1558.        */
  1559.       /* Write old mode data */
  1560.       newmodedata.density  = ((struct cddamodedata *) scsi_data)->density;
  1561.       newmodedata.blocklen = ((struct cddamodedata *) scsi_data)->blocklen;
  1562.       if ((err = DoScsiCmd ((UBYTE *) &newmodedata, sizeof(struct cddamodedata),
  1563.                 (UBYTE *) &modecommand, sizeof (modecommand),
  1564.                 (SCSIF_WRITE | SCSIF_AUTOSENSE))) != 0)
  1565.     {
  1566.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1567.     }
  1568.     }
  1569. #endif
  1570. }
  1571.  
  1572. /*********************************************************************
  1573.  *
  1574.  *    function to read sectors from a starting sector #
  1575.  *    - similar adjacent lines are suppressed on printout.
  1576.  *
  1577.  *    - uses trackdisk.device
  1578.  */
  1579. #ifndef OSK
  1580. void
  1581. read_sec (void)
  1582.  
  1583. {
  1584.   UBYTE *sec_click_ptr;        /* click = 16 bytes    */
  1585.   UBYTE *pref;
  1586.   UBYTE *p;
  1587.   UWORD j;
  1588.   UWORD k;
  1589.   int err;
  1590.  
  1591.   /*
  1592.    *  keep printing sectors until ^C , or until error
  1593.    */
  1594.   io_ptr[0]->io_Command = CMD_READ;
  1595.   io_ptr[0]->io_Length = TD_SECTOR;
  1596.   io_ptr[0]->io_Data = (APTR) ip_buf;
  1597.   io_ptr[0]->io_Offset = secno * TD_SECTOR;    /* will be updated... */
  1598.  
  1599.  
  1600.   /*
  1601.    *  keep reading sectors : stop on ^C on bad sector #
  1602.    */
  1603.   for (;; ++secno)
  1604.     {
  1605.       UBYTE *ss;
  1606.       UWORD m_sec_offs;
  1607.  
  1608.       if (breakcheck ())    /* ^C ? */
  1609.     break;
  1610.  
  1611.       io_ptr[0]->io_Offset = secno * TD_SECTOR;    /* sector offset */
  1612.  
  1613.       DoIO ((struct IORequest *) io_ptr[0]);
  1614.       if ((err = io_ptr[0]->io_Error) == 0)
  1615.     {
  1616.       printf ("\n");
  1617.       /*
  1618.        * scan this sector ...
  1619.         */
  1620.       for (sec_click_ptr = pref = ip_buf, m_sec_offs = 0;
  1621.            m_sec_offs < TD_SECTOR;
  1622.            m_sec_offs += BYTES_PER_LINE, sec_click_ptr += BYTES_PER_LINE)
  1623.         {
  1624.           int xxxlen = strlen (" xx");    /* byte */
  1625.  
  1626.           /*
  1627.            * don't print line if same contents as previous
  1628.            */
  1629.           if (gcomp (sec_click_ptr, pref, BYTES_PER_LINE) == TRUE)
  1630.         {
  1631.           if (m_sec_offs > 1)
  1632.             continue;    /* same */
  1633.         }
  1634.           memset (buffer, ' ', sizeof (buffer));    /* put spaces in buffer */
  1635.  
  1636.           sprintf (buffer, "%05X:%03X = ", secno, m_sec_offs);
  1637.  
  1638.           /* set up for loop */
  1639.  
  1640.           k = strlen (buffer);
  1641.           ss = buffer + k;
  1642.           k += (BYTES_PER_LINE * xxxlen) + 1;
  1643.           for (p = sec_click_ptr, j = 0;
  1644.            j < BYTES_PER_LINE;
  1645.            ss += xxxlen, ++j, ++k)
  1646.         {
  1647.           UBYTE dd = *p++;
  1648.           UBYTE que = (isascii (dd) && isprint (dd)) ? dd : '.';
  1649.           sprintf (ss, " %02X", dd);    /* 2 hex charas  */
  1650.           buffer[k] = que;
  1651.         }
  1652.  
  1653.           buffer[strlen (buffer)] = ' ';
  1654.           buffer[k++] = '\n';
  1655.           buffer[k++] = '\0';
  1656.  
  1657.           printf ("%s", buffer);
  1658.           pref = sec_click_ptr;
  1659.  
  1660.         }
  1661.     }
  1662.       else
  1663.     {
  1664.       /* else DoIO error */
  1665.  
  1666.       fprintf (stderr, "Error :  err = %ld , sec = %ld dec , $%lX , [%s]\n",
  1667.            err, secno, secno, sense_errs (0, err));
  1668.  
  1669.       return;
  1670.     }
  1671.     }
  1672. }
  1673. #endif
  1674.  
  1675. /*********************************************************************
  1676.  *
  1677.  *    function to read sectors from a starting sector #
  1678.  *    - similar adjacent lines are suppressed on printout.
  1679.  *
  1680.  *    - uses scsi device directly
  1681.  */
  1682.  
  1683. void
  1684. read_sec_scsi (void)
  1685. {
  1686.   static struct CMD_XREAD
  1687.   {
  1688.     UBYTE cmd;
  1689.     UBYTE lba[3];
  1690.     UBYTE numb_secs;
  1691.     UBYTE pad;
  1692.   } command =
  1693.   {
  1694.     SCSI_CMD_RD,
  1695.     0, 0, 0,
  1696.     0,
  1697.     PAD
  1698.   };
  1699.  
  1700.   UBYTE *sec_click_ptr;        /* click = 16 bytes    */
  1701.   UBYTE *pref;
  1702.   UBYTE *p;
  1703.   UWORD j;
  1704.   UWORD k;
  1705.   int err;
  1706.  
  1707.   /*
  1708.    *  keep printing sectors until ^C , or until error
  1709.    */
  1710.  
  1711.  
  1712.   /*
  1713.    *  keep reading sectors : stop on ^C on bad sector #
  1714.    */
  1715.   for (;; ++secno)
  1716.     {
  1717.       UBYTE *ss;
  1718.       UWORD m_sec_offs;
  1719.  
  1720.       command.lba[2] = secno;
  1721.       command.lba[1] = secno >> 8;
  1722.       command.lba[0] = (secno >> 8) & 0x1F;
  1723.  
  1724.       command.numb_secs = 1;
  1725.  
  1726.       if (breakcheck ())    /* ^C ? */
  1727.     break;
  1728.  
  1729.       io_ptr[0]->io_Offset = secno * TD_SECTOR;    /* sector offset */
  1730.  
  1731.       if ((err = DoScsiCmd ((UBYTE *) ip_buf, 512,
  1732.                 (UBYTE *) & command, sizeof (command),
  1733.                 (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  1734.     {
  1735.       printf ("\n");
  1736.       /*
  1737.        * scan this sector ...
  1738.         */
  1739.       for (sec_click_ptr = pref = ip_buf, m_sec_offs = 0;
  1740.            m_sec_offs < TD_SECTOR;
  1741.            m_sec_offs += BYTES_PER_LINE, sec_click_ptr += BYTES_PER_LINE)
  1742.         {
  1743.           int xxxlen = strlen (" xx");    /* byte */
  1744.  
  1745.           /*
  1746.            * don't print line if same contents as previous
  1747.            */
  1748.           if (gcomp (sec_click_ptr, pref, BYTES_PER_LINE) == TRUE)
  1749.         {
  1750.           if (m_sec_offs > 1)
  1751.             continue;    /* same */
  1752.         }
  1753.           memset (buffer, ' ', sizeof (buffer));    /* put spaces in buffer */
  1754.  
  1755.           sprintf (buffer, "%05X:%03X = ", secno, m_sec_offs);
  1756.  
  1757.           /* set up for loop */
  1758.  
  1759.           k = strlen (buffer);
  1760.           ss = buffer + k;
  1761.           k += (BYTES_PER_LINE * xxxlen) + 1;
  1762.           for (p = sec_click_ptr, j = 0;
  1763.            j < BYTES_PER_LINE;
  1764.            ss += xxxlen, ++j, ++k)
  1765.         {
  1766.           UBYTE dd = *p++;
  1767.           UBYTE que = (isascii (dd) && isprint (dd)) ? dd : '.';
  1768.           sprintf (ss, " %02X", dd);    /* 2 hex charas  */
  1769.           buffer[k] = que;
  1770.         }
  1771.  
  1772.           buffer[strlen (buffer)] = ' ';
  1773.           buffer[k++] = '\n';
  1774.           buffer[k++] = '\0';
  1775.  
  1776.           printf ("%s", buffer);
  1777.           pref = sec_click_ptr;
  1778.  
  1779.         }
  1780.     }
  1781.       else
  1782.     {
  1783.       /* else DoIO error */
  1784.  
  1785.       fprintf (stderr, "Error :  sec = %ld dec , $%lX , [%s]\n",
  1786.            secno, secno, sense_errs (0, err));
  1787.       return;
  1788.     }
  1789.     }
  1790. }
  1791.  
  1792. /*********************************************************************
  1793.  *
  1794.  *    function to prevent/allow allow medium removal
  1795.  *
  1796.  */
  1797.  
  1798. void
  1799. medium_removal(int lock)
  1800. {
  1801.   static SCSICMD6 command =
  1802.   {
  1803.     SCSI_CMD_PAMR,        /* 0x1E SCSI Prevent Allow Medium Removal */
  1804.     0,                /* Bit 765 = LUN */
  1805.     PAD,            /* reserved */
  1806.     PAD,            /* reserved */
  1807.     0,                /* Bit 0 = prevent */
  1808.     PAD,            /* reserved */
  1809.   };
  1810.  
  1811.   int err;
  1812.  
  1813.   command.b4 = lock;
  1814.  
  1815.   if ((err = DoScsiCmd (0, 0,
  1816.             (UBYTE *) & command, sizeof (command),
  1817.             (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1818.     {
  1819.       fprintf (stderr, "Error :   err=%ld , [%s]\n", err, sense_errs (0, err));
  1820.     }
  1821. }
  1822.  
  1823. /*********************************************************************
  1824.  *
  1825.  *    function to stop/start motor on SCSI device
  1826.  *    or eject/insert a medium
  1827.  *
  1828.  */
  1829.  
  1830. void
  1831. motor (int motorstatus)
  1832. {
  1833.   static SCSICMD6 command =
  1834.   {
  1835.     SCSI_CMD_SSU,        /* 0x1B SCSI Start / Stop Unit */
  1836.     0,
  1837.     PAD,
  1838.     PAD,
  1839.     0,                /* start/stop eject/insert */
  1840.     PAD,
  1841.   };
  1842.  
  1843.   int err;
  1844.  
  1845.   command.b4 = motorstatus;
  1846.  
  1847.   if ((err = DoScsiCmd (0, 0,
  1848.             (UBYTE *) & command, sizeof (command),
  1849.             (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1850.     {
  1851.       fprintf (stderr, "Error :   err=%ld , [%s]\n", err, sense_errs (0, err));
  1852.     }
  1853. }
  1854.  
  1855. /*********************************************************************
  1856.  *
  1857.  *    function to seek to a cylinder
  1858.  *
  1859.  */
  1860.  
  1861. void
  1862. seek (void)
  1863.  
  1864. {
  1865.   static struct CMD_SEEK
  1866.   {
  1867.     UBYTE cmd;
  1868.     UBYTE pad_a;
  1869.     ULONG lba;
  1870.     UBYTE pad[4];
  1871.   } command =
  1872.   {
  1873.     SCSI_CMD_SKX,
  1874.     PAD,
  1875.     0,
  1876.     PAD, PAD, PAD, PAD
  1877.   };
  1878.  
  1879.   int err;
  1880.   /*
  1881.    *    load sector # (log block addr)
  1882.    */
  1883.  
  1884.   command.lba = secno;
  1885.  
  1886.   if ((err = DoScsiCmd (0, 0,
  1887.             (UBYTE *) & command, sizeof (command),
  1888.             (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1889.     {
  1890.       fprintf (stderr, "Error :  err = %ld , sec = %ld dec , $%lX , [%s]\n",
  1891.            err, secno, secno, sense_errs (0, err));
  1892.     }
  1893. }
  1894.  
  1895. /*********************************************************************
  1896.  *
  1897.  *    what CD-ROM drive?
  1898.  *
  1899.  */
  1900.  
  1901. void
  1902. finddrivebrand (void)
  1903. {
  1904.   static SCSICMD6 command =
  1905.   {
  1906.     SCSI_CMD_INQ,        /* 0x12 INQUIRY */
  1907.     PAD,            /* Bits 7-5 Logical Unit Number | Bits 4-1 Reserved | Bit 0 EVPD */
  1908.     PAD,            /* Page Code */
  1909.     PAD,            /* Reserved */
  1910.     0,                /* Allocation length */
  1911.     PAD                /* Control */
  1912.   };
  1913.  
  1914.   int err;
  1915.  
  1916.   command.b4 = MAX_DATA_LEN;    /* Allocation length = max. data length */
  1917.  
  1918.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  1919.             (UBYTE *) & command, sizeof (command),
  1920.             (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  1921.     {
  1922.       int rem = scsi_cmd[0].scsi_Actual;
  1923.  
  1924.       if (rem >= 8)
  1925.     {
  1926.       if (!memcmp("SONY    CD-ROM CDU-8003",
  1927.                &scsi_data[8], strlen("SONY    CD-ROM CDU-8003")))
  1928.         {
  1929.           whatdrive = APPLECD300;
  1930.         }
  1931.       else if (!memcmp("SONY    CD-ROM CDU-8002",
  1932.                 &scsi_data[8], strlen("SONY    CD-ROM CDU-8002")))
  1933.         {
  1934.           whatdrive = APPLECD150;
  1935.         }
  1936.       else if (!memcmp("TOSHIBA",
  1937.                 &scsi_data[8], strlen("TOSHIBA")))
  1938.         {
  1939.           whatdrive = TOSHIBA3401;
  1940.         }
  1941.     }
  1942.       else
  1943.     whatdrive = UNKNOWN;
  1944.     }
  1945.   else
  1946.     /* error */
  1947.     {
  1948.       fprintf (stderr, "Error : err=%ld , %s\n", err, sense_errs (0, err));
  1949.     }
  1950. }
  1951.  
  1952. /*********************************************************************
  1953.  *
  1954.  *    function to set the output volume of a CD-ROM drive
  1955.  *
  1956.  *    if (vol0 = vol1 = vol2 = vol3) == -1
  1957.  *     display current volume settings, don't change anything
  1958.  *
  1959.  */
  1960.  
  1961. void
  1962. set_volume (int vol0, int vol1, int vol2, int vol3)
  1963. {
  1964.   static int err, i, j;
  1965.   static SCSICMD6 modecommand;
  1966.   static struct volmodedata
  1967.     {
  1968.       UBYTE head[4];
  1969.       UBYTE page;    /* page code 0x0E */
  1970.       UBYTE plength;    /* page length */
  1971.       UBYTE b2;        /* bit 2: Immed, bit 1: SOTC */
  1972.       UBYTE b3;        /* reserved */
  1973.       UBYTE b4;        /* reserved */
  1974.       UBYTE b5;        /* bit 7: APRVal, bit 3-0: format of LBAs / Sec. */
  1975.       UWORD bps;    /* logical blocks per second audio playback */
  1976.       UBYTE out0;    /* lower 4 bits: output port 0 channel selection */
  1977.       UBYTE vol0;    /* output port 0 volume */
  1978.       UBYTE out1;    /* lower 4 bits: output port 1 channel selection */
  1979.       UBYTE vol1;    /* output port 1 volume */
  1980.       UBYTE out2;    /* lower 4 bits: output port 2 channel selection */
  1981.       UBYTE vol2;    /* output port 2 volume */
  1982.       UBYTE out3;    /* lower 4 bits: output port 3 channel selection */
  1983.       UBYTE vol3;    /* output port 3 volume */
  1984.     } modedata;
  1985.  
  1986.   for (i = 0; i < 4; i++)
  1987.     modedata.head[i] = 0;
  1988.  
  1989.   modecommand.opcode    = SCSI_CMD_MSE;
  1990.   modecommand.b1    = 0;
  1991.   modecommand.b2    = 0x0E;
  1992.   modecommand.b3    = 0;
  1993.   modecommand.b4    = MAX_DATA_LEN;
  1994.   modecommand.control    = 0;
  1995.  
  1996.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  1997.             (UBYTE *) &modecommand, sizeof (modecommand),
  1998.             (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1999.     {
  2000.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  2001.       return;
  2002.     }
  2003.  
  2004.   for (j = (scsi_data[0]+1), i = scsi_data[3] + 4; i < j; i += scsi_data[i+1] + 2)
  2005.     {
  2006.       if (vol0 == -1 && vol1 == -1 && vol2 == -1 && vol3 == -1)
  2007.     {
  2008.       if ((scsi_data[i] & 0x3f) == 0x0e)
  2009.         {
  2010.           printf ("Immed    : %s\n", (scsi_data[i+2] & 4)? "yes" : "no");
  2011.           printf ("SOTC     : %s\n", (scsi_data[i+2] & 2)? "yes" : "no");
  2012.           printf ("APRVal   : %svalid\n", (scsi_data[i+5] & 0x80)? "" : "in");
  2013.           if (scsi_data[i+5] & 0x80)
  2014.         {
  2015.           printf ("LBA Format: ");
  2016.           if ((scsi_data[i+5] & 0x0f) == 0)
  2017.             printf ("1 second\n");
  2018.           else if ((scsi_data[i+5] & 0x0f) == 8)
  2019.             printf ("1/256 second\n");
  2020.           else
  2021.             printf ("%hu (reserved)\n", scsi_data[i+5] & 0x0f);
  2022.           printf ("LBPS      : %u\n", scsi_data[i+6]<<8 + scsi_data[i+7]);
  2023.         }
  2024.         }
  2025.       if (scsi_data[i+8] & 0x0f)
  2026.         printf ("Output 0 : %hu\n", scsi_data[i+8] & 0x0f);
  2027.       else
  2028.         printf ("Output 0 : muted\n");
  2029.       printf ("Volume 0 : %hu\n", scsi_data[i+9]);
  2030.       if (scsi_data[i+10] & 0x0f)
  2031.         printf ("Output 1 : %hu\n", scsi_data[i+10] & 0x0f);
  2032.       else
  2033.         printf ("Output 1 : muted\n");
  2034.       printf ("Volume 1 : %hu\n", scsi_data[i+11]);
  2035.       if (scsi_data[i+12] & 0x0f)
  2036.         printf ("Output 2 : %hu\n", scsi_data[i+12] & 0x0f);
  2037.       else
  2038.         printf ("Output 2 : muted\n");
  2039.       printf ("Volume 2 : %hu\n", scsi_data[i+13]);
  2040.       if (scsi_data[i+14] & 0x0f)
  2041.         printf ("Output 3 : %hu\n", scsi_data[i+14] & 0x0f);
  2042.       else
  2043.         printf ("Output 3 : muted\n");
  2044.       printf ("Volume 3 : %hu\n", scsi_data[i+15]);
  2045.     }
  2046.       
  2047.       /* should be 16 bytes */
  2048.       memcpy (&modedata.page, &scsi_data[i], 16);
  2049.     }
  2050.   if (vol0 > -1 || vol1 > -1 || vol2 > -1 || vol3 > -1)
  2051.     {
  2052.       modedata.page = 0x0e;
  2053.       modedata.plength = 0x0e;
  2054.  
  2055.       if (vol0 >= 0)
  2056.     modedata.vol0 = vol0;
  2057.       if (vol1 >= 0)
  2058.     modedata.vol1 = vol1;
  2059.       if (vol2 >= 0)
  2060.     modedata.vol2 = vol2;
  2061.       if (vol3 >= 0)
  2062.     modedata.vol3 = vol3;
  2063.  
  2064.       modecommand.opcode    = SCSI_CMD_MSL;
  2065.       modecommand.b1        = 0x10;
  2066.       modecommand.b2        = 0;
  2067.       modecommand.b3        = 0;
  2068.       modecommand.b4        = sizeof (modedata);
  2069.       modecommand.control    = 0;
  2070.  
  2071.       if ((err = DoScsiCmd ((UBYTE *) &modedata, sizeof(modedata),
  2072.                 (UBYTE *) &modecommand, sizeof (modecommand),
  2073.                 (SCSIF_WRITE | SCSIF_AUTOSENSE))) != 0)
  2074.     {
  2075.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  2076.       return;
  2077.     }
  2078.     }
  2079. }
  2080.  
  2081. /*********************************************************************
  2082.  *
  2083.  *    function to make an inquiry
  2084.  *
  2085.  */
  2086.  
  2087. void
  2088. inquiry (BOOLEAN parsedoutput)
  2089. {
  2090.   static SCSICMD6 command =
  2091.   {
  2092.     SCSI_CMD_INQ,        /* 0x12 INQUIRY */
  2093.     PAD,            /* Bits 7-5 Logical Unit Number | Bits 4-1 Reserved | Bit 0 EVPD */
  2094.     PAD,            /* Page Code */
  2095.     PAD,            /* Reserved */
  2096.     0,                /* Allocation length */
  2097.     PAD                /* Control */
  2098.   };
  2099.   static int err;
  2100.  
  2101.   command.b4 = MAX_DATA_LEN;    /* Allocation length = max. data length */
  2102.  
  2103.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  2104.             (UBYTE *) & command, sizeof (command),
  2105.             (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  2106.     {
  2107.       int rem = scsi_cmd[0].scsi_Actual;
  2108.  
  2109.       if (parsedoutput == FALSE)
  2110.     {
  2111.       rawhexasciioutput (scsi_data, rem, 0);
  2112.     }
  2113.       else
  2114.     /* parsed output */
  2115.     {
  2116.       static IDTOSTRING devicetype[] =
  2117.       {
  2118.         0x00, "Direct-access device (e.g., magnetic disk)",
  2119.         0x01, "Sequential-access device (e.g., magnetic tape)",
  2120.         0x02, "Printer device",
  2121.         0x03, "Processor device",
  2122.         0x04, "Write-once device (e.g., some optical disks)",
  2123.         0x05, "CD-ROM device",
  2124.         0x06, "Scanner device",
  2125.         0x07, "Optical memory device (e.g., some optical disks)",
  2126.         0x08, "Medium Changer device (e.g., jukeboxes)",
  2127.         0x09, "Communications device",
  2128.         0x0A, "Defined by ASC IT8 (Graphic Arts Pre-Press Devices)",
  2129.         0x0B, "Defined by ASC IT8 (Graphic Arts Pre-Press Devices)",
  2130.         -1, "Reserved, unknown or no device type"
  2131.       };
  2132.  
  2133.       static IDTOSTRING ansiversion[] =
  2134.       {
  2135.         0x00, "The device might or might not comply to an ANSI-approved standard.",
  2136.         0x01, "The device complies to ANSI X3.131-1986 (SCSI-1).",
  2137.         0x02, "The device complies to (SCSI-2).",
  2138.         -1, "Reserved",
  2139.       };
  2140.  
  2141.       static IDTOSTRING responseformat[] =
  2142.       {
  2143.         0x00, "SCSI-1",
  2144.         0x01, "CCS",
  2145.         0x02, "SCSI-2",
  2146.         -1, "Reserved",
  2147.       };
  2148.  
  2149.       printf ("Peripherial qualifier: %ld\n", (scsi_data[0] & 0xE0) >> 5);
  2150.       printf ("Peripherial device type: $%lx, %s\n", (scsi_data[0] & 0x1F), id2string ((scsi_data[0] & 0x1F), devicetype));
  2151.  
  2152.       printf ("Removable medium: %s\n", (scsi_data[1] & 0x80) ? "yes" : "no");
  2153.       printf ("Device type modifier: %lx\n", scsi_data[1] & 0x7F);
  2154.       printf ("ISO Version: %lx\n", (scsi_data[2] & 0xC0) >> 6);
  2155.       printf ("ECMA Version: %lx\n", (scsi_data[2] & 0x38) >> 3);
  2156.  
  2157.       printf ("ANSI-Approved Version: %ld, %s\n", scsi_data[2] & 0x07, id2string ((scsi_data[2] & 0x07), ansiversion));
  2158.  
  2159.       printf ("AENC: %s\n", (scsi_data[3] & 0x80) ? "yes" : "no");
  2160.       printf ("TrmIOP: does%s support TERMINATE I/O PROCESs message\n", (scsi_data[3] & 0x40) ? "" : "n't");
  2161.  
  2162.       printf ("Response data format: $%lx, conforms to %s\n", scsi_data[3] & 0x0F, id2string ((scsi_data[3] & 0x0F), responseformat));
  2163.       printf ("Additional length: $%lx\n", scsi_data[4]);
  2164.       printf ("INQUIRY[5-6] (Reserved): $%lx, $%lx\n", scsi_data[5], scsi_data[6]);
  2165.       printf ("RelAdr: does%s support relative addressing\n", (scsi_data[7] & 0x80) ? "" : "n't");
  2166.       printf ("WBus32: does%s support 32 wide data transfers\n", (scsi_data[7] & 0x40) ? "" : "n't");
  2167.       printf ("WBus16: does%s support 16 wide data transfers\n", (scsi_data[7] & 0x20) ? "" : "n't");
  2168.       printf ("Sync: does%s support synchronous transfers\n", (scsi_data[7] & 0x10) ? "" : "n't");
  2169.       printf ("Linked: does%s support linked commands\n", (scsi_data[7] & 0x08) ? "" : "n't");
  2170.       printf ("CmdQue: does%s support tagged command queueing\n", (scsi_data[7] & 0x02) ? "" : "n't");
  2171.       printf ("SftRe: responds to RESET condition with %s RESET alternative\n", (scsi_data[7] & 0x01) ? "soft" : "hard");
  2172.       printf ("Vendor identification: %.8s\n", &scsi_data[8]);
  2173.       printf ("Product identification: %.16s\n", &scsi_data[16]);
  2174.       printf ("Product revision level: %.4s\n", &scsi_data[32]);
  2175.       printf ("Vendor specific: %.20s\n", &scsi_data[36]);
  2176.       printf ("Reserved: %.35s\n", &scsi_data[56]);
  2177.     }
  2178.     }
  2179.   else
  2180.     /* error */
  2181.     {
  2182.       fprintf (stderr, "Error : err=%ld , %s\n", err, sense_errs (0, err));
  2183.     }
  2184. }
  2185.  
  2186. /*********************************************************************
  2187.  *
  2188.  *    function to read disk capacity
  2189.  *
  2190.  */
  2191.  
  2192. void
  2193. read_capacity (BOOLEAN parsed)
  2194. {
  2195.   static struct CMD_READ_CAPACITY
  2196.   {
  2197.     UBYTE cmd;
  2198.     UBYTE pad_a;
  2199.     ULONG lba;
  2200.     UBYTE pad_b[2];
  2201.     UBYTE pmi;
  2202.     UBYTE pad_c;
  2203.   } command =
  2204.   {
  2205.     SCSI_CMD_RCP,    /* READ CAPACITY = READ CD-ROM CAPACITY */
  2206.     PAD,        /* LUN | rsrvd. | RelAddr */
  2207.     0,            /* start from sec 0 */
  2208.     PAD, PAD,
  2209.     0,            /* PMI */
  2210.     PAD
  2211.   };
  2212.  
  2213.   int err;
  2214.  
  2215.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  2216.             (UBYTE *) & command, sizeof (command),
  2217.             (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  2218.     {
  2219.       if (parsed == TRUE)
  2220.         /* output parsed data */
  2221.         {
  2222.           ULONG sec_no = *((ULONG *) & scsi_data[0]);
  2223.           ULONG sec_size = *((ULONG *) & scsi_data[4]);
  2224.  
  2225.           printf ("Max Sec = %7ld , sec size = %4ld (capacity = %7ld KB)\n",
  2226.                   sec_no, sec_size, (sec_no * sec_size) / 1024);
  2227.         }
  2228.       else
  2229.         /* output raw data */
  2230.         {
  2231.           rawhexasciioutput (scsi_data, 8, 0);
  2232.         }
  2233.     }
  2234.   else
  2235.     {
  2236.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  2237.     }
  2238. }
  2239.  
  2240. /*********************************************************************
  2241.  *
  2242.  *    function to read audio CD TOC (table of contents)
  2243.  *
  2244.  */
  2245.  
  2246. void
  2247. read_toc (int toclong)
  2248. {
  2249.   static IDTOSTRING Qfield[] =
  2250.   {
  2251.     0x00, "Sub-channel Q mode information not supplied.",
  2252.     0x01, "Sub-channel Q encodes current position data.",
  2253.     0x02, "Sub-channel Q encodes media catalog number.",
  2254.     0x03, "Sub-channel Q encodes ISRC.",
  2255.     -1, "Reserved"
  2256.   };
  2257.  
  2258.   static IDTOSTRING Qfieldshort[] =
  2259.   {
  2260.     0x00, "not.suppl.",
  2261.     0x01, "cur.posdt.",
  2262.     0x02, "med.cat.#.",
  2263.     0x03, "ISRC",
  2264.     -1, "reserved"
  2265.   };
  2266.  
  2267.   static SCSICMD10 command =
  2268.   {
  2269.     SCSI_CMD_READTOC,        /* SCSI command read table of contents */
  2270.     0,
  2271.     PAD, PAD, PAD, PAD,
  2272.     0,                /* starting track */
  2273.     0x03, 0x24,            /* max. TOC data length on current CD-ROMs 804 bytes
  2274.                    or 100 TOC track descriptors */
  2275.     PAD
  2276.   };
  2277.  
  2278.   int err, tocsize;
  2279.   UBYTE *tocptr;
  2280.  
  2281.   if ((err = DoScsiCmd ((UBYTE *) toc_buf, MAX_TOC_LEN,
  2282.             (UBYTE *) & command, sizeof (command),
  2283.             (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  2284.     {
  2285.       tocsize = (toc_buf[0] << 8) | toc_buf[1];        /* first word encodes length */
  2286.  
  2287.       if (toclong == 0)
  2288.         /* display TOC raw form */
  2289.         {
  2290.           rawhexasciioutput(toc_buf, (toc_buf[0]<<8 | toc_buf[1]), 0);
  2291.         }
  2292.       else if (toclong == 1)
  2293.     /* display TOC short form */
  2294.     {
  2295.           printf ("TOC len: %d\n", tocsize);
  2296.           printf ("First/last track: %d, %d\n", toc_buf[2], toc_buf[3]);
  2297.  
  2298.       if (tocsize >= 2)    /* TOC Data Length - FTN - LTN */
  2299.         tocsize -= 2;
  2300.  
  2301.       for (tocptr = &toc_buf[4]; tocptr < (&toc_buf[4] + tocsize); tocptr += 8)
  2302.         {
  2303.           printf ("#%3.3d: ADR:%10.10s %-15.15s Dig.copy.%5.5s. %-9.9s %cChan. %ld\n",
  2304.               tocptr[2],
  2305.               id2string (((tocptr[1] >> 4) & 0x0F), Qfieldshort),
  2306.               (tocptr[1] & 0x01) ? "pre-emphasis" : "no-pre-emphasis",
  2307.               (tocptr[1] & 0x02) ? "prmtd" : "prohb.",
  2308.               (tocptr[1] & 0x04) ? "Data tr." : "Audio tr.",
  2309.               (tocptr[1] & 0x08) ? '4' : '2',
  2310.               ((tocptr[4] << 24) | (tocptr[5] << 16) | (tocptr[6] << 8) | (tocptr[7]))
  2311.         );
  2312.         }
  2313.     }
  2314.       else if (toclong == 2)
  2315.     /* display TOC long form */
  2316.     {
  2317.           printf ("TOC len: %d\n", tocsize);
  2318.           printf ("First/last track: %d, %d\n", toc_buf[2], toc_buf[3]);
  2319.  
  2320.       if (tocsize >= 2)    /* TOC Data Length - FTN - LTN */
  2321.         tocsize -= 2;
  2322.  
  2323.       for (tocptr = &toc_buf[4]; tocptr < (&toc_buf[4] + tocsize); tocptr += 8)
  2324.         {
  2325.  
  2326.           printf ("Track number: %d\n", tocptr[2]);
  2327.  
  2328.           printf (" ADR: $%lx: %s\n", ((tocptr[1] >> 4) & 0x0F), id2string (((tocptr[1] >> 4) & 0x0F), Qfield));
  2329.  
  2330.           printf (" Audio with%s pre-emphasis.  ", (tocptr[1] & 0x01) ? "" : "out");
  2331.           printf (" Digital copy %s\n", (tocptr[1] & 0x02) ? "permitted" : "prohibited");
  2332.           printf (" %s track.  ", (tocptr[1] & 0x04) ? "Data" : "Audio");
  2333.           printf (" %s channel audio.  ", (tocptr[1] & 0x08) ? "Four" : "Two");
  2334.  
  2335.           printf (" Absolute address: %ld\n", ((tocptr[4] << 24) | (tocptr[5] << 16) | (tocptr[6] << 8) | (tocptr[7])));
  2336.         }
  2337.     }
  2338.       else
  2339.     /* toclong is neither 0,1 or 2 - this should never happen! */
  2340.     {
  2341.       fprintf (stderr, "Error : internal error in read_toc!\n");
  2342.     }
  2343.     }
  2344.   else
  2345.     {
  2346.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  2347.     }
  2348. }
  2349.  
  2350. /*********************************************************************
  2351.  *
  2352.  *    function to play audio
  2353.  *
  2354.  */
  2355.  
  2356. void
  2357. play_audio (int starttrack, int startindex, int endtrack, int endindex)
  2358. {
  2359.   static SCSICMD10 command =
  2360.   {
  2361.     SCSI_CMD_PLAYAUDIOTRACKINDEX,    /* Play audio track */
  2362.     PAD,            /* LUN */
  2363.     PAD,            /* Reserved */
  2364.     PAD,            /* Reserved */
  2365.     0,                /* Starting Track */
  2366.     0,                /* Starting Index */
  2367.     PAD,            /* Reserved */
  2368.     0,                /* Ending Track */
  2369.     0,                /* Ending Index */
  2370.     PAD                /* Control */
  2371.   };
  2372.  
  2373.   int err;
  2374.  
  2375.   command.b4 = starttrack;    /* set audio track to play */
  2376.   command.b5 = startindex;
  2377.   command.b7 = endtrack;    /* ending track */
  2378.   command.b8 = endindex;
  2379.  
  2380.   finddrivebrand ();        /* figure out drivetype */
  2381.  
  2382.   if (whatdrive == APPLECD150)
  2383.     {
  2384.       command.opcode = 0xC9;    /* Apple CD-150 / Pioneer Opcode for playing audio tracks */
  2385.     }
  2386.  
  2387.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  2388.             (UBYTE *) & command, sizeof (command),
  2389.             (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  2390.     {
  2391.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  2392.     }
  2393. }
  2394.  
  2395. /*********************************************************************
  2396.  *
  2397.  *    function to compare two binary strings
  2398.  *
  2399.  *    returns FALSE if different
  2400.  */
  2401.  
  2402. int
  2403. gcomp (char *p1, char *p2, int len)
  2404. {
  2405.   while (len--)
  2406.     {
  2407.       if (*p1++ != *p2++)
  2408.     return (FALSE);
  2409.     }
  2410.   return (TRUE);
  2411. }
  2412.  
  2413. /*********************************************************************
  2414.  *
  2415.  * searches DeviceList for a device name with a given string in it.
  2416.  * - if found returns with a pointer to it, else NULL
  2417.  */
  2418.  
  2419. extern struct ExecBase *SysBase;
  2420.  
  2421. UBYTE *
  2422. GetDevName (char *grep)
  2423. {
  2424.   LIST *lh = (LIST *) SysBase->DeviceList.lh_Head;
  2425.   NODE *ln;
  2426.  
  2427.   for (ln = lh->lh_Head; ln->ln_Succ; ln = ln->ln_Succ)
  2428.     {
  2429.       UBYTE *p = ln->ln_Name;
  2430.  
  2431.       while (*p != '.')
  2432.     {
  2433.       if (strncmp (p, grep, 4) == 0)
  2434.         {
  2435.           return (ln->ln_Name);
  2436.         }
  2437.       ++p;
  2438.     }
  2439.     }
  2440.  
  2441.   return (NULL);        /* not found */
  2442. }
  2443. #ifndef OSK
  2444.  
  2445. /*********************************************************************
  2446.  *
  2447.  *    Break (^C) function
  2448.  *
  2449.  */
  2450.  
  2451. int
  2452. breakcheck (void)
  2453. {
  2454.   int zz = SetSignal (0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C;
  2455.   if (zz)
  2456.     {
  2457.       fprintf (stderr, "\n***BREAK: ^C\n");
  2458.     }
  2459.   return (zz);
  2460. }
  2461. #endif
  2462.  
  2463. #ifdef __SASC
  2464. /*********************************************************************
  2465.  *
  2466.  *  tell SAS to turn of CTRL-C checking
  2467.  */
  2468. void __regargs
  2469. __chkabort (void)
  2470. {
  2471. }
  2472.  
  2473. #endif
  2474.  
  2475. #ifndef OSK
  2476. /*********************************************************************
  2477.  *
  2478.  *    function to send a scsi command (uses asynchronous I/O)
  2479.  *
  2480.  */
  2481. void
  2482. SendScsiCmd (int req, UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags)
  2483. {
  2484.  
  2485.   io_ptr[req]->io_Length = sizeof (SCSICMD);
  2486.   io_ptr[req]->io_Data = (APTR) & scsi_cmd[req];
  2487.   io_ptr[req]->io_Command = HD_SCSICMD;
  2488.  
  2489.   scsi_cmd[req].scsi_Data = (APTR) data;
  2490.   scsi_cmd[req].scsi_Length = datasize;
  2491.   scsi_cmd[req].scsi_SenseActual = 0;
  2492.   scsi_cmd[req].scsi_SenseData = scsi_sense[req];
  2493.   scsi_cmd[req].scsi_SenseLength = SENSE_LEN;
  2494.   scsi_cmd[req].scsi_Command = cmd;
  2495.   scsi_cmd[req].scsi_CmdLength = cmdsize;
  2496.   scsi_cmd[req].scsi_Flags = flags;
  2497.  
  2498.   (void) SendIO ((struct IORequest *) io_ptr[req]);
  2499.  
  2500. }
  2501.  
  2502. /*********************************************************************
  2503.  *
  2504.  *    function to wait for an asynchronous scsi command
  2505.  *
  2506.  */
  2507. int
  2508. WaitScsiCmd (int req)
  2509. {
  2510.   int i;
  2511.  
  2512.   WaitIO ((struct IORequest *) io_ptr[req]);
  2513.  
  2514.   if (scsi_cmd[req].scsi_SenseActual)
  2515.     {
  2516.       fprintf (stderr, "SENSE_DATA:");
  2517.       for (i = 0; i < scsi_cmd[req].scsi_SenseActual; i++)
  2518.     {
  2519.       fprintf (stderr, " %02x", scsi_cmd[req].scsi_SenseData[i]);
  2520.     }
  2521.       fprintf (stderr, "\n");
  2522.     }
  2523.   return (io_ptr[req]->io_Error);
  2524. }
  2525.  
  2526. /*********************************************************************
  2527.  *
  2528.  *    function to use a scsi command
  2529.  *
  2530.  */
  2531. int
  2532. DoScsiCmd (UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags)
  2533. {
  2534.   int i;
  2535.  
  2536.   io_ptr[0]->io_Length = sizeof (SCSICMD);
  2537.   io_ptr[0]->io_Data = (APTR) & scsi_cmd[0];
  2538.   io_ptr[0]->io_Command = HD_SCSICMD;
  2539.  
  2540.   scsi_cmd[0].scsi_Data = (APTR) data;
  2541.   scsi_cmd[0].scsi_Length = datasize;
  2542.   scsi_cmd[0].scsi_SenseActual = 0;
  2543.   scsi_cmd[0].scsi_SenseData = scsi_sense[0];
  2544.   scsi_cmd[0].scsi_SenseLength = SENSE_LEN;
  2545.   scsi_cmd[0].scsi_Command = cmd;
  2546.   scsi_cmd[0].scsi_CmdLength = cmdsize;
  2547.   scsi_cmd[0].scsi_Flags = flags;
  2548.  
  2549.   (void) DoIO ((struct IORequest *) io_ptr[0]);
  2550.  
  2551.   if (scsi_cmd[0].scsi_SenseActual)
  2552.     {
  2553.       fprintf (stderr, "SENSE_DATA:");
  2554.       for (i = 0; i < scsi_cmd[0].scsi_SenseActual; i++)
  2555.     {
  2556.       fprintf (stderr, " %02x", scsi_cmd[0].scsi_SenseData[i]);
  2557.     }
  2558.       fprintf (stderr, "\n");
  2559.     }
  2560.   return (io_ptr[0]->io_Error);
  2561. }
  2562. #endif
  2563.  
  2564. /*********************************************************************
  2565.  *
  2566.  *    function to return an error string
  2567.  *
  2568.  *
  2569.  */
  2570.  
  2571. UBYTE *
  2572. err_str (int err)
  2573. {
  2574.  
  2575.   static UBYTE *errors[] =
  2576.   {
  2577.     " cannot issue SCSI command to self ",
  2578.     " DMA error ",
  2579.     " illegal or unexpected SCSI phase ",
  2580.     " SCSI parity error ",
  2581.     " Select timed out ",
  2582.     " status and/or sense error "
  2583.   };
  2584.  
  2585.   err -= 40;
  2586.  
  2587.   if ((err < 0) || (err > 5))
  2588.     return ("Error out-of-range");
  2589.   else
  2590.     return (errors[err]);
  2591. }
  2592.  
  2593. /*********************************************************************
  2594.  *
  2595.  *    usage function
  2596.  *
  2597.  *
  2598.  */
  2599.  
  2600. void
  2601. usage (void)
  2602. {
  2603.   static char *zz[] =
  2604.   {
  2605.     "Usage: SCSIutil [-dscsi_dev] <scsi_id> <command>\n",
  2606.     " -c[r]                 : Read capacity [raw]\n",
  2607.     " -d<l|r|s> sec blks sc : Read 16 bit digital audio(start sector/# blocks)(2)\n",
  2608.     " -D<l|r> sec blks      : Read  8 bit digital audio(left or right channel)(3)\n",
  2609.     " -e <0|1>              : Change medium (0=eject, 1=load)\n",
  2610.     " -i[r]                 : Inquiry [raw]\n",
  2611.     " -h[r] blk             : Read CD-ROM data block address header\n",
  2612.     " -l <0|1>              : Allow/Prevent medium removal\n",
  2613.     " -m <0|1>              : Stop/Start motor {0=stop, 1=start}\n",
  2614.     " -o[r] contr page      : Mode sense (contr = 0-3))\n",
  2615.     " -p st si et ei        : Play audio CD track (1-99), index (1-99)\n",
  2616.     " -r[t] sec_no          : Read sectors [use trackdisk.device]\n",
  2617.     " -s sec_no             : Seek to sector (5)\n",
  2618.     " -t[r|l]               : Display TOC of an audio CD [raw|long]\n",
  2619.     " -u[r] chan fmt track  : Read CD sub-channel information [raw] (6)\n",
  2620.     " -v [vl0 vl1 vl2 vl3]  : Set output volume channels 0-3 (7)\n",
  2621. #ifdef USE8SVX
  2622.     " -8<l|r|s> sec blks   : Read digital audio -> 8SVX (left, right or stereo) (7)\n",
  2623. #endif    /* USE8SVX */
  2624.     "\n",
  2625.     "Note 1: usually scsi_id = (BOARD * 100) + (LUN * 10) + SCSI_TARGET_ID\n",
  2626.     "     2: with 's' returns LRLRLR pairs of stereo audio, 2352 bytes per block\n",
  2627.     "        sc = Apple subcode (0=2352, 1=2368, 2=2448, 3=96 byte/block)\n",
  2628.     "     3: converted to 8 bit audio (-d and -D work with Sony CDU 561 & 8003)\n",
  2629.     "     4: contr 0: current, 1: changeable, 2: default, 3: saved values\n",
  2630.     "     5: to park heads, try sec_no of -1\n",
  2631.     "     6: Q-channel = 64, fmt: 0=Sub-Q Channel data,1=current CD-ROM pos.,\n",
  2632.     "        2=Media Catalog Number (UPC/Bar Code),3=Track ISRC\n",
  2633.     "     7: use -1 to leave volume of channel as it is, without argument shows\n",
  2634.     "        current volume settings\n",
  2635. #ifdef USE8SVX
  2636.     "     8: output 8SVX IFF (in case of stereo needs to read the CD twice)\n",
  2637. #endif    /* USE8SVX */
  2638.     ""                /* TERM */
  2639.   };
  2640.  
  2641.   int j = 0;
  2642.  
  2643.   fprintf (stderr, "SCSIutil V%s [%s : %s] - written by Gary Duncan\n",
  2644.        VERSION, __DATE__, __TIME__, pname);
  2645.   fprintf (stderr, "         (gduncan@philips.oz.au) and Heiko Rath (hr@brewhr.swb.de)\n");
  2646.  
  2647.   while (*zz[j++])
  2648.     fprintf (stderr, "%s", zz[j - 1]);
  2649. }
  2650.  
  2651. /*********************************************************************
  2652.  *
  2653.  *    sense_errs function ; prints sense errors
  2654.  *
  2655.  *
  2656.  */
  2657.  
  2658. UBYTE *
  2659. sense_errs (int req, int err)
  2660. {
  2661.   typedef struct
  2662.   {
  2663.     BYTE code;
  2664.     BYTE sense;
  2665.     UBYTE *ptr;
  2666.   } S_ERRS;
  2667.  
  2668. /*
  2669.  *    only the likely, interesting ones filled in, e.g media errors
  2670.  */
  2671.   static S_ERRS x[] =
  2672.   {
  2673.     0x00, 0x00, "No error",
  2674.     0x01, 0x04, "?",
  2675.     0x02, 0x04, "?",
  2676.     0x03, 0x04, "?",
  2677.     0x04, 0x02, "?",
  2678.     0x06, 0x04, "?",
  2679.     0x09, 0x04, "?",
  2680.     0x10, 0x03, "?",
  2681.     0x10, 0x04, "?",
  2682.     0x11, 0x03, "?",
  2683.     0x12, 0x03, "?",
  2684.     0x13, 0x03, "?",
  2685.     0x14, 0x03, "?",
  2686.     0x15, 0x04, "Seek error ",
  2687.     0x17, 0x01, "?",
  2688.     0x18, 0x01, "?",
  2689.     0x19, 0x03, "?",
  2690.     0x1A, 0x05, "?",
  2691.     0x20, 0x05, "Invalid command op code",
  2692.     0x21, 0x05, "Illegal sector address",
  2693.     0x24, 0x05, "?",
  2694.     0x25, 0x05, "Invalid LUN",
  2695.     0x26, 0x05, "Invalid field in parameter list",
  2696.     0x29, 0x06, "?",
  2697.     0x2A, 0x06, "?",
  2698.     0x31, 0x03, "?",
  2699.     0x32, 0x01, "?",
  2700.     0x32, 0x03, "?",
  2701.     0x40, 0x04, "?",
  2702.     0x41, 0x04, "?",
  2703.     0x42, 0x04, "Power-on diagnostic failure",
  2704.     0x43, 0x04, "?",
  2705.     0x45, 0x04, "Select / reselect failure ",
  2706.     0x47, 0x04, "SCSI Interface Parity Error",
  2707.     0x48, 0x0B, "?",
  2708.     0x49, 0x0B, "Illegal message drive can't support",
  2709.     -1, -1, "ILLEGAL sense!!"
  2710.   };
  2711.  
  2712.   int j = 0;
  2713.   UBYTE *p;
  2714.   char sense;
  2715.   char code;
  2716.  
  2717.   /*
  2718.    *    verify that sense data looks valid
  2719.    */
  2720.   if (((scsi_cmd[req].scsi_Status & 2) == 0) ||
  2721.       (scsi_cmd[req].scsi_SenseActual < OFFS_KEY))
  2722.     {
  2723.       return ("");
  2724.     }
  2725.   sense = scsi_cmd[req].scsi_SenseData[OFFS_KEY] & 0xF;
  2726.   code = scsi_cmd[req].scsi_SenseData[OFFS_CODE];
  2727.  
  2728.   do
  2729.     {
  2730.       p = x[j].ptr;
  2731.       if ((x[j].code == code) && (x[j].sense == sense))
  2732.     break;
  2733.   } while (x[j++].code != -1);
  2734.  
  2735.   return (p);
  2736. }
  2737.  
  2738. /*********************************************************************
  2739.  *
  2740.  *    id2string function ; return pointer to string for matching id
  2741.  *
  2742.  */
  2743.  
  2744. UBYTE *
  2745. id2string (int id, IDTOSTRING * idtable)
  2746. {
  2747.   int j = 0;
  2748.   UBYTE *p;
  2749.  
  2750.   do
  2751.     {
  2752.       p = idtable[j].ptr;
  2753.       if (idtable[j].code == id)
  2754.     break;
  2755.   } while (idtable[j++].code != -1);
  2756.   return p;
  2757. }
  2758.