home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 5 / FreshFish_July-August1994.bin / new / disk / cdrom / amicdrom / cdrom.c < prev    next >
C/C++ Source or Header  |  1994-05-18  |  16KB  |  613 lines

  1. /* cdrom.c:
  2.  *
  3.  * Basic interaction with the CDROM drive.
  4.  *
  5.  * ----------------------------------------------------------------------
  6.  * This code is (C) Copyright 1993,1994 by Frank Munkert.
  7.  * All rights reserved.
  8.  * This software may be freely distributed and redistributed for
  9.  * non-commercial purposes, provided this notice is included.
  10.  * ----------------------------------------------------------------------
  11.  * History:
  12.  * 
  13.  * 18-May-94   fmu   New drive model: MODEL_CDU_8002 (= Apple CD 150).
  14.  * 17-May-94   fmu   Sense length 20 instead of 18 (needed by ALF controller).
  15.  * 17-Feb-94   fmu   Added support for Toshiba 4101.
  16.  * 06-Feb-94   dmb   - Fixed bug in Test_Unit_Ready() trackdisk support.
  17.  *                   - Fixed bug in Open_CDROM (size of request)
  18.  *                   - Added function Clear_Sector_Buffers().
  19.  * 01-Jan-94   fmu   Added function Data_Tracks() for multisession support.
  20.  * 11-Dec-93   fmu   - Memory type can now be chosen by the user.
  21.  *                   - Addional parameter p_direction for Do_SCSI_Command().
  22.  *                   - Start_Play_Audio() now plays all tracks.
  23.  *                   - Mode_Select() instead of Select_XA_Mode().
  24.  *                   - Support for CDROM drives with 512, 1024 or 2048 bytes
  25.  *                     per block.
  26.  * 06-Dec-93   fmu   New drive type DRIVE_SCSI_2.
  27.  * 09-Nov-93   fmu   Added Select_XA_Mode.
  28.  * 23-Oct-93   fmu   Open_CDROM now returns an error code that tell what
  29.  *                   went wrong.
  30.  * 09-Oct-93   fmu   SAS/C support added.
  31.  * 03-Oct-93   fmu   New buffering algorithm.
  32.  * 27-Sep-93   fmu   Added support for multi-LUN devices.
  33.  * 24-Sep-93   fmu   - SCSI buffers may now reside in fast or chip memory.
  34.  *                   - TD_CHANGESTATE instead of CMD_READ in Test_Unit_Ready
  35.  */
  36.  
  37. #include <string.h>
  38.  
  39. #include <clib/exec_protos.h>
  40. #include <clib/alib_protos.h>
  41.  
  42. #ifdef AZTEC_C
  43. #include <pragmas/exec_lib.h>
  44. #endif
  45. #ifdef LATTICE
  46. #include <pragmas/exec_pragmas.h>
  47. #endif
  48. #if defined (_DCC) && defined (REGISTERED)
  49. #include <pragmas/exec_pragmas.h>
  50. extern struct Library *SysBase;
  51. #endif
  52.  
  53. #include <devices/trackdisk.h>
  54.  
  55. #include <limits.h>
  56.  
  57. #include "cdrom.h"
  58.  
  59. int g_cdrom_errno;
  60. int g_ignore_blocklength = FALSE;
  61.  
  62. void Determine_Drive_Type (CDROM *p_cd)
  63. {
  64.   t_inquiry_data data;
  65.   char buf[33];
  66.   
  67.   p_cd->scsi_compliance = 1;
  68.   p_cd->model = MODEL_ANY;
  69.  
  70.   if (!Inquire (p_cd, &data))
  71.     return;
  72.  
  73.   if ((data.version & 0x7) >= 2)
  74.     p_cd->scsi_compliance = 2;
  75.  
  76.   if (strncmp (data.vendor, "TOSHIBA", 7) == 0) {
  77.     memcpy (buf, data.product, 32);
  78.     buf[32] = 0;
  79.     if (strstr (buf, "3401") || strstr (buf, "4101"))
  80.       p_cd->model = MODEL_TOSHIBA_3401;
  81.   } else if (strncmp (data.vendor, "SONY", 4) == 0) {
  82.     memcpy (buf, data.product, 32);
  83.     buf[32] = 0;
  84.     if (strstr (buf, "CDU-8002"))
  85.       p_cd->model = MODEL_CDU_8002;
  86.   }
  87. }
  88.  
  89. CDROM *Open_CDROM (char *p_device, int p_scsi_id, int p_use_trackdisk,
  90.            unsigned long p_memory_type,
  91.            int p_std_buffers, int p_file_buffers)
  92. {
  93.   CDROM *cd;
  94.   int i;
  95.   int bufs = p_std_buffers + p_file_buffers + 1;
  96.   
  97.   g_cdrom_errno = CDROMERR_NO_MEMORY;
  98.  
  99.   cd = AllocMem (sizeof (CDROM),
  100.                MEMF_PUBLIC | MEMF_CLEAR | p_memory_type);
  101.   if (!cd)
  102.     return NULL;
  103.  
  104.   cd->std_buffers = p_std_buffers;
  105.   cd->file_buffers = p_file_buffers;
  106.  
  107.   cd->buffer_data = AllocMem (SCSI_BUFSIZE * bufs + 15,
  108.                     MEMF_PUBLIC | p_memory_type);
  109.   if (!cd->buffer_data) {
  110.     Cleanup_CDROM (cd);
  111.     return NULL;
  112.   }
  113.  
  114.   cd->buffers = AllocMem (sizeof (unsigned char *) * bufs, MEMF_PUBLIC);
  115.   if (!cd->buffers) {
  116.     Cleanup_CDROM (cd);
  117.     return NULL;
  118.   }
  119.   
  120.   cd->current_sectors = AllocMem (sizeof (long) * bufs, MEMF_PUBLIC);
  121.   if (!cd->current_sectors) {
  122.     Cleanup_CDROM (cd);
  123.     return NULL;
  124.   }
  125.  
  126.   cd->last_used = AllocMem (sizeof (unsigned long) * p_std_buffers,
  127.                   MEMF_PUBLIC | MEMF_CLEAR);
  128.   if (!cd->last_used) {
  129.     Cleanup_CDROM (cd);
  130.     return NULL;
  131.   }
  132.   
  133.   /* make the buffer quad-word aligned. This greatly helps 
  134.    * performance on '040-powered systems with DMA SCSI
  135.    * controllers.
  136.    */
  137.  
  138.   cd->buffers[0] = (UBYTE *)(((ULONG)cd->buffer_data + 15) & ~15);
  139.  
  140.   for (i=1; i<bufs; i++)
  141.     cd->buffers[i] = cd->buffers[0] + i * SCSI_BUFSIZE;
  142.  
  143.   cd->port = CreateMsgPort ();
  144.   if (!cd->port) {
  145.     g_cdrom_errno = CDROMERR_MSGPORT;
  146.     Cleanup_CDROM (cd);
  147.     return NULL;
  148.   }
  149.  
  150.   cd->scsireq = CreateIORequest (cd->port, sizeof (struct IOExtTD));
  151.   if (!cd->scsireq) {
  152.     g_cdrom_errno = CDROMERR_IOREQ;
  153.     Cleanup_CDROM (cd);
  154.     return NULL;
  155.   }
  156.  
  157.   if (OpenDevice ((UBYTE *) p_device, p_scsi_id,
  158.                   (struct IORequest *) cd->scsireq, 0)) {
  159.     g_cdrom_errno = CDROMERR_DEVICE;
  160.     Cleanup_CDROM (cd);
  161.     return NULL;
  162.   }
  163.  
  164.   cd->device_open = TRUE;
  165.  
  166.   for (i=0; i<bufs; i++)
  167.     cd->current_sectors[i] = -1;
  168.  
  169.   cd->use_trackdisk = p_use_trackdisk;
  170.   cd->t_changeint = -1;
  171.   cd->t_changeint2 = -2;
  172.  
  173.   /* The LUN is the 2nd digit of the SCSI id number: */
  174.   cd->lun = (p_scsi_id / 10) % 10;
  175.  
  176.   /* 'tick' is incremented every time a sector is accessed. */
  177.   cd->tick = 0;
  178.  
  179.   g_cdrom_errno = 0;
  180.  
  181.   Determine_Drive_Type (cd);
  182.  
  183.   if (g_ignore_blocklength) {
  184.     cd->block_length = 0;
  185.     cd->blocking_factor = 0;
  186.   } else {
  187.     cd->block_length = Block_Length (cd);
  188.     switch (cd->block_length) {
  189.     case 2048:
  190.       cd->blocking_factor = 0;
  191.       break;
  192.     case 1024:
  193.       cd->blocking_factor = 1;
  194.       break;
  195.     case 512:
  196.       cd->blocking_factor = 2;
  197.       break;
  198.     case 0:
  199.       cd->blocking_factor = 0;
  200.       break;
  201.     default:
  202.       g_cdrom_errno = CDROMERR_BLOCKSIZE;
  203.       Cleanup_CDROM (cd);
  204.       return NULL;
  205.     }
  206.   }
  207.  
  208.   return cd;
  209. }
  210.  
  211. int Do_SCSI_Command (CDROM *p_cd, unsigned char *p_buf, long p_buf_length,
  212.              unsigned char *p_command, int p_length, int p_direction)
  213. {
  214.   int bufs = p_cd->std_buffers + p_cd->file_buffers + 1;
  215.  
  216.   p_cd->scsireq->io_Length   = sizeof (struct SCSICmd);
  217.   p_cd->scsireq->io_Data     = (APTR) &p_cd->cmd;
  218.   p_cd->scsireq->io_Command  = HD_SCSICMD;
  219.  
  220.   p_cd->cmd.scsi_Data        = (UWORD *) p_buf;
  221.   p_cd->cmd.scsi_Length      = p_buf_length;
  222.   p_cd->cmd.scsi_Flags       = SCSIF_AUTOSENSE | p_direction;
  223.   p_cd->cmd.scsi_SenseData   = (UBYTE *) p_cd->sense;
  224.   p_cd->cmd.scsi_SenseLength = 20;
  225.   p_cd->cmd.scsi_SenseActual = 0;
  226.   p_cd->cmd.scsi_Command     = (UBYTE *) p_command;
  227.   p_cd->cmd.scsi_CmdLength   = p_length;
  228.  
  229.   p_command[1] |= p_cd->lun << 5;
  230.  
  231.   DoIO ((struct IORequest *) p_cd->scsireq);
  232.   if (p_cd->cmd.scsi_Status) {
  233.     int i;
  234.     for (i=0; i<bufs; i++)
  235.       p_cd->current_sectors[i] = -1;
  236.     return 0;
  237.   } else
  238.     return 1;
  239. }
  240.  
  241. int Read_From_Drive (CDROM *p_cd, unsigned char *p_buf, long p_buf_length,
  242.              long p_sector, int p_number_of_sectors)
  243. {
  244.   static unsigned char cmd[10] = { 0x28, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  245.   int bufs = p_cd->std_buffers + p_cd->file_buffers + 1;
  246.  
  247. #ifdef DEBUG_SECTORS
  248.   extern void *dbprintf (char *, ...);
  249.  
  250.   if (p_number_of_sectors == 1)
  251.     dbprintf ("[%ld]", p_sector);
  252.   else
  253.     dbprintf ("[%ld-%ld]", p_sector, p_sector + p_number_of_sectors - 1);
  254. #endif
  255.  
  256.   if (p_cd->use_trackdisk) {
  257.     p_cd->scsireq->io_Length   = 2048 * p_number_of_sectors;
  258.     p_cd->scsireq->io_Data     = (APTR) p_buf;
  259.     p_cd->scsireq->io_Offset   = (ULONG) p_sector * 2048;
  260.     p_cd->scsireq->io_Command  = CMD_READ;
  261.  
  262.     DoIO ((struct IORequest *) p_cd->scsireq);
  263.     if (p_cd->scsireq->io_Error) {
  264.       int i;
  265.       for (i=0; i<bufs; i++)
  266.         p_cd->current_sectors[i] = -1;
  267.       return 0;
  268.     } else
  269.       return 1;
  270.   } else {
  271.     long sector = p_sector << p_cd->blocking_factor;
  272.     cmd[5] = sector & 0xff;
  273.     cmd[4] = (sector >> 8) & 0xff;
  274.     cmd[3] = (sector >> 16) & 0x1f;
  275.  
  276.     cmd[8] = p_number_of_sectors << p_cd->blocking_factor;
  277.  
  278.     return Do_SCSI_Command (p_cd, p_buf, p_buf_length, cmd, sizeof (cmd),
  279.                     SCSIF_READ);
  280.   }
  281. }
  282.  
  283. /* Read one sector from the CDROM drive.
  284.  */
  285.  
  286. int Read_Sector (CDROM *p_cd, long p_sector)
  287. {
  288.   int status;
  289.   int i;
  290.   int maxbuf = p_cd->std_buffers;
  291.   int loc;
  292.  
  293.   p_cd->tick++;
  294.  
  295.   for (i=0; i<maxbuf; i++)
  296.     if (p_cd->current_sectors[i] == p_sector) {
  297.       p_cd->buffer = p_cd->buffers[i];
  298.       p_cd->last_used[i] = p_cd->tick;
  299.