Logo Search packages:      
Sourcecode: cdrkit version File versions  Download package

drv_7501.c

/*
 * This file has been modified for the cdrkit suite.
 *
 * The behaviour and appearence of the program code below can differ to a major
 * extent from the version distributed by the original author(s).
 *
 * For details, see Changelog file distributed with the cdrkit package. If you
 * received this file from another source then ask the distributing person for
 * a log of modifications.
 *
 */

/* @(#)drv_7501.c 1.16 05/05/16 Copyright 2003-2005 J. Schilling */
/*
 *    Device driver for the Masushita CW-7501
 *
 *    Copyright (c) 2003-2005 J. Schilling
 *
 * Mode Pages:
 *    0x01  error recovery          Seite 100
 *    0x02  disconnect/reconnect    Seite 107
 *    0x0D  CD-ROM device parameter Seite 110
 *    0x0E  CD-ROM Audio control    Seite 112
 *    0x20  Speed & Tray position   Seite 115
 *    0x21  Media catalog number    Seite 124
 *    0x22  ISRC              Seite 125
 *    0x23  Dummy/Write Information Seite 126
 *    0x24  CD-R disk information   Seite 127
 */
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; see the file COPYING.  If not, write to the Free Software
 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#ifndef     DEBUG
#define     DEBUG
#endif
#include <mconfig.h>

#include <stdio.h>
#include <standard.h>
#include <stdxlib.h>
#include <unixstd.h>
#include <errno.h>
#include <strdefs.h>
#include <timedefs.h>

#include <utypes.h>
#include <btorder.h>
#include <intcvt.h>
#include <schily.h>

#include <usal/usalcmd.h>
#include <usal/scsidefs.h>
#include <usal/scsireg.h>
#include <usal/scsitransp.h>

#include <libport.h>

#include "wodim.h"

extern      int   silent;
extern      int   debug;
extern      int   verbose;
extern      int   lverbose;
extern      int   xdebug;

#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */

struct cw7501_mode_page_20 {  /* Speed control */
            MP_P_CODE;        /* parsave & pagecode */
      Uchar p_len;                  /* 0x02 = 2 Bytes */
      Uchar speed;
      Ucbit res         : 7;
      Ucbit traypos           : 1;
};

#else                   /* Motorola byteorder */

struct cw7501_mode_page_20 {  /* Speed control */
            MP_P_CODE;        /* parsave & pagecode */
      Uchar p_len;                  /* 0x02 = 2 Bytes */
      Uchar speed;
      Ucbit traypos           : 1;
      Ucbit res         : 7;
};
#endif

#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */

struct cw7501_mode_page_21 {  /* MCN */
            MP_P_CODE;        /* parsave & pagecode */
      Uchar p_len;                  /* 0x12 = 20 Bytes */
      Ucbit control           : 4;
      Ucbit addr        : 4;
      Uchar res_3;
      Uchar res_4;
      Uchar mcn[15];
};

#else                   /* Motorola byteorder */

struct cw7501_mode_page_21 {  /* MCN */
            MP_P_CODE;        /* parsave & pagecode */
      Uchar p_len;                  /* 0x12 = 20 Bytes */
      Ucbit addr        : 4;
      Ucbit control           : 4;
      Uchar res_3;
      Uchar res_4;
      Uchar mcn[15];
};
#endif


#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */

struct cw7501_mode_page_22 {  /* ISRC */
            MP_P_CODE;        /* parsave & pagecode */
      Uchar p_len;                  /* 0x12 = 20 Bytes */
      Ucbit control           : 4;
      Ucbit addr        : 4;
      Uchar trackno;
      Uchar res_4;
      Uchar isrc[15];
};

#else                   /* Motorola byteorder */

struct cw7501_mode_page_22 {  /* ISRC */
            MP_P_CODE;        /* parsave & pagecode */
      Uchar p_len;                  /* 0x12 = 20 Bytes */
      Ucbit addr        : 4;
      Ucbit control           : 4;
      Uchar trackno;
      Uchar res_4;
      Uchar isrc[15];
};
#endif

#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */

struct cw7501_mode_page_23 {  /* Dummy / Write information */
            MP_P_CODE;        /* parsave & pagecode */
      Uchar p_len;                  /* 0x02 = 2 Bytes */
      Uchar res;
      Ucbit autopg            : 1;
      Ucbit dummy       : 1;
      Ucbit res3_72           : 6;
};

#else                   /* Motorola byteorder */

struct cw7501_mode_page_23 {  /* Dummy / Write information */
            MP_P_CODE;        /* parsave & pagecode */
      Uchar p_len;                  /* 0x02 = 2 Bytes */
      Uchar res;
      Ucbit res3_72           : 6;
      Ucbit dummy       : 1;
      Ucbit autopg            : 1;
};
#endif

struct cw7501_mode_page_24 {  /* CD-R Disk information */
            MP_P_CODE;        /* parsave & pagecode */
      Uchar p_len;                  /* 0x0A = 12 Bytes */
      Uchar disktype;
      Uchar res;
      Uchar appl_code[4];
      Uchar disk_id[4];
};

struct cw7501_mode_data {
      struct scsi_mode_header header;
      union cdd_pagex   {
            struct cw7501_mode_page_20    page20;
            struct cw7501_mode_page_21    page21;
            struct cw7501_mode_page_22    page22;
            struct cw7501_mode_page_23    page23;
            struct cw7501_mode_page_24    page24;
      } pagex;
};

/*
 * Mode for read track information
 */
#define     TI_TRACKINFO_R    0
#define     TI_NWA            1
#define     TI_PMA            2
#define     TI_TRACKINFO      3

struct cw7501_nwa {
      Uchar nwa_length[2];
      Uchar nwa_res;
      Uchar nwa_trackno;
      Uchar nwa_nwa[4];
      Uchar nwa_freeblocks[4];
};

struct cw7501_cue {
      Uchar cs_ctladr;        /* CTL/ADR for this track     */
      Uchar cs_tno;                 /* This track number          */
      Uchar cs_index;         /* Index within this track    */
      Uchar cs_dataform;            /* Data form                  */
                              /* Bit 0..3 Physical Format   */
                              /* Bit 4 Alt Copy (SCMS)      */
                              /* Bit 5 SubC Audio + RAW96 sub */
      Uchar cs_extension;           /* Reserved or MCN/ISRC       */
      Uchar cs_min;                 /* Absolute time minutes      */
      Uchar cs_sec;                 /* Absolute time seconds      */
      Uchar cs_frame;         /* Absolute time frames       */
};


static      int   cw7501_attach(SCSI *usalp, cdr_t *dp);
static      int   cw7501_init(SCSI *usalp, cdr_t *dp);
static      int   cw7501_getdisktype(SCSI *usalp, cdr_t *dp);
static      int   cw7501_speed_select(SCSI *usalp, cdr_t *dp, int *speedp);
static      int   cw7501_next_wr_addr(SCSI *usalp, track_t *trackp, long *ap);
static      int   cw7501_write(SCSI *usalp, caddr_t bp, long sectaddr, long size, 
                                                       int blocks, BOOL islast);
static      int   cw7501_write_leadin(SCSI *usalp, cdr_t *dp, track_t *trackp);
static      int   cw7501_open_track(SCSI *usalp, cdr_t *dp, track_t *trackp);
static      int   cw7501_close_track(SCSI *usalp, cdr_t *dp, track_t *trackp);
static      int   cw7501_open_session(SCSI *usalp, cdr_t *dp, track_t *trackp);
static      int   cw7501_gen_cue(track_t *trackp, void *vcuep, BOOL needgap);
static      void  fillcue(struct cw7501_cue *cp, int ca, int tno, int idx, 
                                            int dataform, int scms, msf_t *mp);
static      int   cw7501_send_cue(SCSI *usalp, cdr_t *dp, track_t *trackp);
static      int   cw7501_fixate(SCSI *usalp, cdr_t *dp, track_t *trackp);
static      int   cw7501_rezero(SCSI *usalp, int reset, int dwreset);
static      int   cw7501_read_trackinfo(SCSI *usalp, Uchar *bp, int count, 
                                                                         int track, int mode);
static      int   cw7501_write_dao(SCSI *usalp, Uchar *bp, int len, int disktype);
static      int   cw7501_reserve_track(SCSI *usalp, unsigned long);
static      int   cw7501_set_mode(SCSI *usalp, int phys_form, int control,
                                    int subc, int alt, int trackno, int tindex,
                                    int packet_size, int write_mode);
static      int   cw7501_finalize(SCSI *usalp, int pad, int fixed);


cdr_t cdr_cw7501 = {
      0, 0,
      /*
       * Prinzipiell geht auch: CDR_PACKET & CDR_SRAW96R
       */
      CDR_TAO|CDR_SAO|CDR_TRAYLOAD,
      CDR_CDRW_NONE,
      2, 2,
      "cw_7501",
      "driver for Matsushita/Panasonic CW-7501",
      0,
      (dstat_t *)0,
      drive_identify,
      cw7501_attach,
      cw7501_init,
      cw7501_getdisktype,
      scsi_load,
      scsi_unload,
      buf_dummy,                    /* RD buffer cap not supp. */
      cmd_dummy,                          /* recovery_needed */
      (int(*)(SCSI *, cdr_t *, int))cmd_dummy,  /* recover  */
      cw7501_speed_select,
      select_secsize,
      cw7501_next_wr_addr,
      cw7501_reserve_track,
      cw7501_write,
      cw7501_gen_cue,
      cw7501_send_cue,
      cw7501_write_leadin,
      cw7501_open_track,
      cw7501_close_track,
      cw7501_open_session,
      cmd_dummy,                    /* close seession */
      cmd_dummy,                          /* abort    */
      read_session_offset,
      cw7501_fixate,
      cmd_dummy,                          /* stats    */
      blank_dummy,
      format_dummy,
      (int(*)(SCSI *, caddr_t, int, int))NULL,  /* no OPC   */
      cmd_dummy,                          /* opt1           */
      cmd_dummy,                          /* opt2           */
};

static const char *sd_cw7501_error_str[] = {
      "\100\201diagnostic failure on ROM",                  /* 40 81 */
      "\100\202diagnostic failure on CPU internal RAM",     /* 40 82 */
      "\100\203diagnostic failure on BUFFER RAM",           /* 40 83 */
      "\100\204diagnostic failure on internal SCSI controller",   /* 40 84 */
      "\100\205diagnostic failure on system mechanism",     /* 40 85 */

      "\210\000Illegal Que Sheet (DAO parameter)",          /* 88 00 */
      "\211\000Inappropriate command",                /* 89 00 */

      "\250\000Audio Play operation Not in Progress",       /* A8 00 */
      "\251\000Buffer Overrun",                       /* A9 00 */

      "\300\000Unrecordable Disk",                    /* C0 00 */
      "\301\000Illegal Track Status",                       /* C1 00 */
      "\302\000Reserved track Status",                /* C2 00 */
      "\304\000Illegal Reserve Length for Reserve Track Command", /* C4 00 */
      "\304\001Illegal Data Form for Reserve Track Command",      /* C4 01 */
      "\304\002Unable to Reserve Track, Because Track Mode has been Changed", /* C4 02 */

      "\305\000Buffer error during recording",        /* C5 00 */
      "\307\000Disk Style mismatch",                        /* C7 00 */
      "\312\000Power Calibration error",              /* CA 00 */
      "\313\000Write error (Fatal Error/Time out)",         /* CB 00 */
      "\314\000Not enough space (Leadin/Leadout space)",    /* CC 00 */
      "\315\000No track present to finalize",               /* CD 00 */
      "\317\000Unable to recover damaged disk",       /* CF 00 */

      "\320\000PMA area full (1000 blocks)",                /* D0 00 */
      "\321\000PCA area full (100 counts)",                 /* D1 00 */
      "\322\000Recovery failed",                      /* D2 00 */
      "\323\000Recovery needed",                      /* D3 00 */
      NULL
};

static int 
cw7501_attach(SCSI *usalp, cdr_t *dp)
{
      usal_setnonstderrs(usalp, sd_cw7501_error_str);
      return (0);
}

static int 
cw7501_init(SCSI *usalp, cdr_t *dp)
{
      return (cw7501_speed_select(usalp, dp, NULL));
}

static int 
cw7501_getdisktype(SCSI *usalp, cdr_t *dp)
{
      Ulong maxb = 0;
      Uchar buf[256];
      int   ret;
      dstat_t     *dsp = dp->cdr_dstat;

      if (xdebug > 0) {
            usalp->silent++;
            fillbytes((caddr_t)buf, sizeof (buf), '\0');
            ret = cw7501_read_trackinfo(usalp, buf, 32, 0, 0);
            if (ret >= 0)
            usal_prbytes("TI EXIST-R   (0): ", buf, 32 -usal_getresid(usalp));

            fillbytes((caddr_t)buf, sizeof (buf), '\0');
            ret = cw7501_read_trackinfo(usalp, buf, 32, 0, 1);
            if (ret >= 0)
            usal_prbytes("TI NWA       (1): ", buf, 32 -usal_getresid(usalp));

            fillbytes((caddr_t)buf, sizeof (buf), '\0');
            ret = cw7501_read_trackinfo(usalp, buf, 32, 0, 2);
            if (ret >= 0)
            usal_prbytes("TI PMA       (2): ", buf, 32 -usal_getresid(usalp));

            fillbytes((caddr_t)buf, sizeof (buf), '\0');
            ret = cw7501_read_trackinfo(usalp, buf, 32, 0, 3);
            if (ret >= 0)
            usal_prbytes("TI EXIST-ROM (3): ", buf, 32 -usal_getresid(usalp));
            usalp->silent--;
      }

      fillbytes((caddr_t)buf, sizeof (buf), '\0');

      usalp->silent++;
      ret = cw7501_read_trackinfo(usalp, buf, 12, 0, TI_NWA);
      if (ret < 0 &&
                  (dsp->ds_cdrflags & (RF_WRITE|RF_BLANK)) == RF_WRITE) {

            /*
             * Try to clear the dummy bit to reset the virtual
             * drive status. Not all drives support it even though
             * it is mentioned in the MMC standard.
             */
            if (lverbose)
                  printf("Trying to clear drive status.\n");
            cw7501_rezero(usalp, 0, 1);
            wait_unit_ready(usalp, 60);
            ret = cw7501_read_trackinfo(usalp, buf, 12, 0, TI_NWA);
      }
      usalp->silent--;

      if (ret >= 0) {
            maxb = a_to_u_4_byte(&buf[8]);
            if (maxb != 0)
                  maxb -= 150;
      }
      dsp->ds_maxblocks = maxb;

      return (drive_getdisktype(usalp, dp));
}


static int 
cw7501_speed_select(SCSI *usalp, cdr_t *dp, int *speedp)
{
      struct      scsi_mode_page_header   *mp;
      char                    mode[256];
      int                     len = 20;
      int                     page = 0x20;
      struct cw7501_mode_page_20    *xp20;
      struct cw7501_mode_data       md;
      int                     count;
      int                     speed = 1;
      BOOL                    dummy = (dp->cdr_cmdflags & F_DUMMY) != 0;

      if (speedp) {
            speed = *speedp;
      } else {
            fillbytes((caddr_t)mode, sizeof (mode), '\0');

            if (!get_mode_params(usalp, page, "Speed information",
                  (Uchar *)mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) {
                  return (-1);
            }
            if (len == 0)
                  return (-1);

            mp = (struct scsi_mode_page_header *)
                  (mode + sizeof (struct scsi_mode_header) +
                  ((struct scsi_mode_header *)mode)->blockdesc_len);

            xp20  = (struct cw7501_mode_page_20 *)mp;
            speed = xp20->speed;
      }

      fillbytes((caddr_t)&md, sizeof (md), '\0');

      count  = sizeof (struct scsi_mode_header) +
            sizeof (struct cw7501_mode_page_20);

      md.pagex.page20.p_code = 0x20;
      md.pagex.page20.p_len =  0x02;
      md.pagex.page20.speed = speed;

      if (mode_select(usalp, (Uchar *)&md, count, 0, usalp->inq->data_format >= 2) < 0)
            return (-1);

      fillbytes((caddr_t)&md, sizeof (md), '\0');

      count  = sizeof (struct scsi_mode_header) +
            sizeof (struct cw7501_mode_page_23);

      md.pagex.page23.p_code = 0x23;
      md.pagex.page23.p_len =  0x02;
      md.pagex.page23.dummy = dummy?1:0;

      return (mode_select(usalp, (Uchar *)&md, count, 0, usalp->inq->data_format >= 2));
}

static int 
cw7501_next_wr_addr(SCSI *usalp, track_t *trackp, long *ap)
{
      struct cw7501_nwa *nwa;
      Uchar buf[256];
      long  next_addr;
      int   result = -1;


      /*
       * Reading info for current track may require doing the read_track_info
       * with either the track number (if the track is currently being written)
       * or with 0 (if the track hasn't been started yet and is invisible
       */
      nwa = (struct cw7501_nwa *)buf;

      if (trackp != 0 && trackp->track > 0 && is_packet(trackp)) {
            fillbytes((caddr_t)buf, sizeof (buf), '\0');

            usalp->silent++;
            result = cw7501_read_trackinfo(usalp, buf, sizeof (*nwa),
                                          trackp->trackno,
                                          TI_NWA);
            usalp->silent--;
      }

      if (result < 0) {
            if (cw7501_read_trackinfo(usalp, buf, sizeof (*nwa),
                                          0, TI_NWA) < 0)
                  return (-1);
      }
      if (usalp->verbose)
            usal_prbytes("track info:", buf,
                        12-usal_getresid(usalp));
      next_addr = a_to_4_byte(&nwa->nwa_nwa);
      /*
       * XXX Für TAO definitiv notwendig.
       * XXX ABhängig von Auto-Pregap?
       */
      /* XXX */ next_addr += 150;
      if (ap)
            *ap = next_addr;
      return (0);
}

static int 
cw7501_write(SCSI *usalp, 
             caddr_t bp     /* address of buffer */, 
             long sectaddr  /* disk address (sector) to put */, 
             long size      /* number of bytes to transfer */, 
             int blocks     /* sector count */, 
             BOOL islast    /* last write for track */)
{
      if (lverbose > 1 && islast)
            printf("\nWriting last record for this track.\n");

      return (write_xg0(usalp, bp, 0, size, blocks));
}

static int 
cw7501_write_leadin(SCSI *usalp, cdr_t *dp, track_t *trackp)
{
      Uint  i;
      long  startsec = 0L;

      if (wm_base(dp->cdr_dstat->ds_wrmode) == WM_SAO) {
            if (debug || lverbose) {
                  printf("Sending CUE sheet...\n");
                  flush();
            }
            if ((*dp->cdr_send_cue)(usalp, dp, trackp) < 0) {
                  errmsgno(EX_BAD, "Cannot send CUE sheet.\n");
                  return (-1);
            }

            /*
             * Next writable address function does not work in DAO
             * mode for this writer, so we just assume -150.
             */
            startsec = -150;
            if (debug)
                  printf("SAO startsec: %ld\n", startsec);

            if (trackp[0].flags & TI_TEXT) {
                  errmsgno(EX_BAD, "CD-Text unsupported in CW-7501 - ignoring.\n");
            } else for (i = 1; i <= trackp->tracks; i++) {
                  trackp[i].trackstart += startsec +150;
            }
      }
      return (0);
}

static Uchar      db2phys[] = {
      0x00,             /*  0 2352 bytes of raw data              */
      0xFF,             /*  1 2368 bytes (raw data + P/Q Subchannel)    */
      0xFF,             /*  2 2448 bytes (raw data + P-W Subchannel)    */
      0xFF,             /*  3 2448 bytes (raw data + P-W raw Subchannel)*/
      0xFF,             /*  4 -    Reserved                       */
      0xFF,             /*  5 -    Reserved                       */
      0xFF,             /*  6 -    Reserved                       */
      0xFF,             /*  7 -    Vendor specific                */
      0x02,             /*  8 2048 bytes Mode 1 (ISO/IEC 10149)         */
      0x03,             /*  9 2336 bytes Mode 2 (ISO/IEC 10149)         */
      0xFF,             /* 10 2048 bytes Mode 2 (CD-ROM XA form 1)      */
      0x04,             /* 11 2056 bytes Mode 2 (CD-ROM XA form 1)      */
      0xFF,             /* 12 2324 bytes Mode 2 (CD-ROM XA form 2)      */
      0x08,             /* 13 2332 bytes Mode 2 (CD-ROM XA 1/2+subhdr)  */
      0xFF,             /* 14 -    Reserved                       */
      0xFF,             /* 15 -    Vendor specific                */
};

static int 
cw7501_open_track(SCSI *usalp, cdr_t *dp, track_t *trackp)
{
      struct      scsi_mode_page_header   *mp;
      Uchar                   mode[256];
      int                     len = 0;
      int                     page = 0x23;
      struct cw7501_mode_page_23    *xp23;

      if (!is_tao(trackp) && !is_packet(trackp)) {
            if (trackp->pregapsize > 0 && (trackp->flags & TI_PREGAP) == 0) {
                  if (lverbose) {
                        printf("Writing pregap for track %d at %ld\n",
                              (int)trackp->trackno,
                              trackp->trackstart-trackp->pregapsize);
                  }
                  /*
                   * XXX Do we need to check isecsize too?
                   */
                  pad_track(usalp, dp, trackp,
                        trackp->trackstart-trackp->pregapsize,
                        (Llong)trackp->pregapsize*trackp->secsize,
                              FALSE, 0);
            }
            return (0);
      }

      if (select_secsize(usalp, trackp->secsize) < 0)
            return (-1);

      if (!get_mode_params(usalp, page, "Dummy/autopg information",
                  (Uchar *)mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) {
            return (-1);
      }
      if (len == 0)
            return (-1);

      mp = (struct scsi_mode_page_header *)
            (mode + sizeof (struct scsi_mode_header) +
            ((struct scsi_mode_header *)mode)->blockdesc_len);

      xp23  = (struct cw7501_mode_page_23 *)mp;
      xp23->autopg = 1;
      if (!set_mode_params(usalp, "Dummy/autopg page", mode, len, 0, trackp->secsize))
            return (-1);

      /*
       * Set write modes for next track.
       */
      if (cw7501_set_mode(usalp, db2phys[trackp->dbtype & 0x0F],
                  st2mode[trackp->sectype&ST_MASK] | (is_copy(trackp) ? TM_ALLOW_COPY : 0),
                  0, is_scms(trackp) ? 1 : 0,
                  trackp->trackno, 1, 0,
                  /* write mode TAO */ 0x01) < 0)
            return (-1);

      return (0);
}


static int 
cw7501_close_track(SCSI *usalp, cdr_t *dp, track_t *trackp)
{
      if (!is_tao(trackp) && !is_packet(trackp)) {
            return (0);
      }
      return (scsi_flush_cache(usalp, FALSE));
}

static int 
cw7501_open_session(SCSI *usalp, cdr_t *dp, track_t *trackp)
{
      struct cw7501_mode_data       md;
      int                     count;

      if (select_secsize(usalp, 2048) < 0)
            return (-1);

      /*
       * Disable Auto Pregap when writing in SAO mode.
       */
      if (!is_tao(trackp) && !is_packet(trackp)) {
            struct      scsi_mode_page_header   *mp;
            Uchar                   mode[256];
            int                     len = 0;
            int                     page = 0x23;
            struct cw7501_mode_page_23    *xp23;

            if (!get_mode_params(usalp, page, "Dummy/autopg information",
                        (Uchar *)mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) {
                  return (-1);
            }
            if (len == 0)
                  return (-1);

            mp = (struct scsi_mode_page_header *)
                  (mode + sizeof (struct scsi_mode_header) +
                  ((struct scsi_mode_header *)mode)->blockdesc_len);

            xp23  = (struct cw7501_mode_page_23 *)mp;
            xp23->autopg = 0;
            if (!set_mode_params(usalp, "Dummy/autopg page", mode, len, 0, trackp->secsize))
                  return (-1);

            return (0);
      }

      /*
       * Set Disk Type and Disk ID.
       */
      fillbytes((caddr_t)&md, sizeof (md), '\0');

      count  = sizeof (struct scsi_mode_header) +
            sizeof (struct cw7501_mode_page_24);

      md.pagex.page24.p_code = 0x24;
      md.pagex.page24.p_len =  0x0A;
      md.pagex.page24.disktype = toc2sess[track_base(trackp)->tracktype & TOC_MASK];
      i_to_4_byte(&md.pagex.page24.disk_id, 0x12345);

      return (mode_select(usalp, (Uchar *)&md, count, 0, usalp->inq->data_format >= 2));
}

static int 
cw7501_fixate(SCSI *usalp, cdr_t *dp, track_t *trackp)
{
      if (!is_tao(trackp) && !is_packet(trackp)) {
            return (scsi_flush_cache(usalp, FALSE));
      }
      /*
       * 0x00     Finalize Disk (not appendable)
       * 0x01     Finalize Session (allow next session)
       * 0x10     Finalize track (variable packet writing) - Must fluch cache before
       */
      return (cw7501_finalize(usalp, 0, (track_base(trackp)->tracktype & TOCF_MULTI) ? 0x01 : 0x00));
}

/*--------------------------------------------------------------------------*/

static int 
cw7501_gen_cue(track_t *trackp, void *vcuep, BOOL needgap)
{
      int   tracks = trackp->tracks;
      int   i;
      struct cw7501_cue **cuep = vcuep;
      struct cw7501_cue *cue;
      struct cw7501_cue *cp;
      int   ncue = 0;
      int   icue = 0;
      int   pgsize;
      msf_t m;
      int   ctl;
      int   df;
      int   scms;

      cue = malloc(1);

      for (i = 0; i <= tracks; i++) {
            ctl = (st2mode[trackp[i].sectype & ST_MASK]) << 4;
            if (is_copy(&trackp[i]))
                  ctl |= TM_ALLOW_COPY << 4;
            df = db2phys[trackp[i].dbtype & 0x0F];

            if (trackp[i].isrc) {   /* MCN or ISRC */
                  ncue += 2;
                  cue = realloc(cue, ncue * sizeof (*cue));
                  cp = &cue[icue++];
                  if (i == 0) {
                        cp->cs_ctladr = 0x02;
                        movebytes(&trackp[i].isrc[0], &cp->cs_tno, 7);
                        cp = &cue[icue++];
                        cp->cs_ctladr = 0x02;
                        movebytes(&trackp[i].isrc[7], &cp->cs_tno, 7);
                  } else {
                        cp->cs_ctladr = 0x03;
                        cp->cs_tno = i;
                        movebytes(&trackp[i].isrc[0], &cp->cs_index, 6);
                        cp = &cue[icue++];
                        cp->cs_ctladr = 0x03;
                        cp->cs_tno = i;
                        movebytes(&trackp[i].isrc[6], &cp->cs_index, 6);
                  }
            }
            if (i == 0) {     /* Lead in */
                  lba_to_msf(-150, &m);
                  cue = realloc(cue, ++ncue * sizeof (*cue));
                  cp = &cue[icue++];
                  fillcue(cp, ctl|0x01, i, 0, df, 0, &m);
            } else {
                  scms = 0;

                  if (is_scms(&trackp[i]))
                        scms = 0x80;
                  pgsize = trackp[i].pregapsize;
                  if (pgsize == 0 && needgap)
                        pgsize++;
                  lba_to_msf(trackp[i].trackstart-pgsize, &m);
                  cue = realloc(cue, ++ncue * sizeof (*cue));
                  cp = &cue[icue++];
                  fillcue(cp, ctl|0x01, i, 0, df, scms, &m);

                  if (trackp[i].nindex == 1) {
                        lba_to_msf(trackp[i].trackstart, &m);
                        cue = realloc(cue, ++ncue * sizeof (*cue));
                        cp = &cue[icue++];
                        fillcue(cp, ctl|0x01, i, 1, df, scms, &m);
                  } else {
                        int   idx;
                        long  *idxlist;

                        ncue += trackp[i].nindex;
                        idxlist = trackp[i].tindex;
                        cue = realloc(cue, ncue * sizeof (*cue));

                        for (idx = 1; idx <= trackp[i].nindex; idx++) {
                              lba_to_msf(trackp[i].trackstart + idxlist[idx], &m);
                              cp = &cue[icue++];
                              fillcue(cp, ctl|0x01, i, idx, df, scms, &m);
                        }
                  }
            }
      }
      /* Lead out */
      ctl = (st2mode[trackp[tracks+1].sectype & ST_MASK]) << 4;
      df = db2phys[trackp[tracks+1].dbtype & 0x0F];
      lba_to_msf(trackp[tracks+1].trackstart, &m);
      cue = realloc(cue, ++ncue * sizeof (*cue));
      cp = &cue[icue++];
      fillcue(cp, ctl|0x01, 0xAA, 1, df, 0, &m);

      if (lverbose > 1) {
            for (i = 0; i < ncue; i++) {
                  usal_prbytes("", (Uchar *)&cue[i], 8);
            }
      }
      if (cuep)
            *cuep = cue;
      else
            free(cue);
      return (ncue);
}

static void 
fillcue(struct cw7501_cue *cp /* The target cue entry */, 
        int ca                            /* Control/adr for this entry */, 
        int tno                           /* Track number for this entry */, 
        int idx                           /* Index for this entry */, 
        int dataform                /* Data format for this entry */, 
        int scms                          /* Serial copy management */, 
        msf_t *mp                   /* MSF value for this entry */)
{
      cp->cs_ctladr = ca;
      if (tno <= 99)
            cp->cs_tno = to_bcd(tno);
      else
            cp->cs_tno = tno;
      cp->cs_index = to_bcd(idx);
      if (scms != 0)
            dataform |= 0x10;
      cp->cs_dataform = dataform;
      cp->cs_extension = 0;
      cp->cs_min = to_bcd(mp->msf_min);
      cp->cs_sec = to_bcd(mp->msf_sec);
      cp->cs_frame = to_bcd(mp->msf_frame);
}

static int 
cw7501_send_cue(SCSI *usalp, cdr_t *dp, track_t *trackp)
{
      struct cw7501_cue *cp;
      int         ncue;
      int         ret;
      Uint        i;
      struct timeval starttime;
      struct timeval stoptime;
      int         disktype;

      disktype = toc2sess[track_base(trackp)->tracktype & TOC_MASK];

      for (i = 1; i <= trackp->tracks; i++) {
            if (trackp[i].tracksize < (tsize_t)0) {
                  errmsgno(EX_BAD, "Track %d has unknown length.\n", i);
                  return (-1);
            }
      }
      ncue = (*dp->cdr_gen_cue)(trackp, &cp, FALSE);

      starttime.tv_sec = 0;
      starttime.tv_usec = 0;
      stoptime = starttime;
      gettimeofday(&starttime, (struct timezone *)0);

      usalp->silent++;
      ret = cw7501_write_dao(usalp, (Uchar *)cp, ncue*8, disktype);
      usalp->silent--;
      free(cp);
      if (ret < 0) {
            errmsgno(EX_BAD, "CUE sheet not accepted. Retrying with minimum pregapsize = 1.\n");
            ncue = (*dp->cdr_gen_cue)(trackp, &cp, TRUE);
            ret  = cw7501_write_dao(usalp, (Uchar *)cp, ncue*8, disktype);
            free(cp);
      }
      if (ret >= 0 && lverbose) {
            gettimeofday(&stoptime, (struct timezone *)0);
            prtimediff("Write Lead-in time: ", &starttime, &stoptime);
      }
      return (ret);
}

/*--------------------------------------------------------------------------*/
static int 
cw7501_rezero(SCSI *usalp, int reset, int dwreset)
{
      register struct   usal_cmd    *scmd = usalp->scmd;

      fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
      scmd->addr = (caddr_t)0;
      scmd->size = 0;
      scmd->flags = SCG_DISRE_ENA;
      scmd->cdb_len = SC_G0_CDBLEN;
      scmd->sense_len = CCS_SENSE_LEN;
      scmd->cdb.g0_cdb.cmd = SC_REZERO_UNIT;
      scmd->cdb.g0_cdb.lun = usal_lun(usalp);
      scmd->cdb.cmd_cdb[5] |= reset ? 0x80 : 0;
      scmd->cdb.cmd_cdb[5] |= dwreset ? 0x40 : 0;

      usalp->cmdname = "cw7501 rezero";

      return (usal_cmd(usalp));
}


static int
cw7501_read_trackinfo(SCSI *usalp, Uchar *bp, int count, int track, int mode)
{
      register struct   usal_cmd    *scmd = usalp->scmd;

      fillbytes((caddr_t) scmd, sizeof (*scmd), '\0');
      scmd->addr = (caddr_t)bp;
      scmd->size = count;
      scmd->flags = SCG_RECV_DATA | SCG_DISRE_ENA;
      scmd->cdb_len = SC_G1_CDBLEN;
      scmd->sense_len = CCS_SENSE_LEN;
      scmd->cdb.g1_cdb.cmd = 0xE9;
      scmd->cdb.g1_cdb.lun = usal_lun(usalp);
      scmd->cdb.cmd_cdb[6] = track;
      g1_cdblen(&scmd->cdb.g1_cdb, count);
      scmd->cdb.cmd_cdb[9] = (mode & 3) << 6;

      usalp->cmdname = "cw7501 read_track_information";

      if (usal_cmd(usalp) < 0)
            return (-1);

      return (0);
}

static int 
cw7501_write_dao(SCSI *usalp, Uchar *bp, int len, int disktype)
{
      register struct   usal_cmd    *scmd = usalp->scmd;

      fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
      scmd->addr = (caddr_t)bp;
      scmd->size = len;
      scmd->flags = SCG_DISRE_ENA;
      scmd->cdb_len = SC_G1_CDBLEN;
      scmd->sense_len = CCS_SENSE_LEN;
      scmd->cdb.g1_cdb.cmd = 0xE6;
      scmd->cdb.g1_cdb.lun = usal_lun(usalp);
      scmd->cdb.cmd_cdb[2] = disktype;
      g1_cdblen(&scmd->cdb.g1_cdb, len);

      usalp->cmdname = "cw7501 write_dao";

      if (usal_cmd(usalp) < 0)
            return (-1);
      return (0);
}

/*
 * XXX CW-7501 also needs "control", so we need to make a different
 * XXX driver interface.
 */
static int 
cw7501_reserve_track(SCSI *usalp, unsigned long len)
{
      register struct   usal_cmd    *scmd = usalp->scmd;

      fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
      scmd->flags = SCG_DISRE_ENA;
      scmd->cdb_len = SC_G1_CDBLEN;
      scmd->sense_len = CCS_SENSE_LEN;
      scmd->cdb.g1_cdb.cmd = 0xE7;
      scmd->cdb.g1_cdb.lun = usal_lun(usalp);
/*    scmd->cdb.cmd_cdb[2] = control & 0x0F;*/
      i_to_4_byte(&scmd->cdb.cmd_cdb[5], len);

      usalp->cmdname = "cw7501 reserve_track";

      comerrno(EX_BAD, "Control (as in set mode) missing.\n");

      if (usal_cmd(usalp) < 0)
            return (-1);
      return (0);
}

static int 
cw7501_set_mode(SCSI *usalp, int phys_form, int control, int subc, 
                                    int alt, int trackno, int tindex, int packet_size, 
                                    int write_mode)
{
      register struct   usal_cmd    *scmd = usalp->scmd;

      fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
      scmd->flags = SCG_DISRE_ENA;
      scmd->cdb_len = SC_G1_CDBLEN;
      scmd->sense_len = CCS_SENSE_LEN;
      scmd->cdb.g1_cdb.cmd = 0xE2;
      scmd->cdb.g1_cdb.lun = usal_lun(usalp);
      scmd->cdb.cmd_cdb[2] = phys_form & 0x0F;
      scmd->cdb.cmd_cdb[3] = (control & 0x0F) << 4;
      scmd->cdb.cmd_cdb[3] |= subc ? 2 : 0;
      scmd->cdb.cmd_cdb[3] |= alt ? 1 : 0;
      scmd->cdb.cmd_cdb[4] = trackno;
      scmd->cdb.cmd_cdb[5] = tindex;
      i_to_3_byte(&scmd->cdb.cmd_cdb[6], packet_size);
      scmd->cdb.cmd_cdb[9] = (write_mode & 0x03) << 6;

      usalp->cmdname = "cw7501 set_mode";

      if (usal_cmd(usalp) < 0)
            return (-1);
      return (0);
}

static int 
cw7501_finalize(SCSI *usalp, int pad, int fixed)
{
      register struct   usal_cmd    *scmd = usalp->scmd;

      fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
      scmd->flags = SCG_DISRE_ENA;
      scmd->cdb_len = SC_G1_CDBLEN;
      scmd->sense_len = CCS_SENSE_LEN;
      scmd->timeout = 8 * 60;       /* Needs up to 4 minutes */
      scmd->cdb.g1_cdb.cmd = 0xE3;
      scmd->cdb.g1_cdb.lun = usal_lun(usalp);
      scmd->cdb.cmd_cdb[1] = pad ? 1 : 0;
      scmd->cdb.cmd_cdb[8] = fixed & 0x03;

      usalp->cmdname = "cw7501 finalize";

      if (usal_cmd(usalp) < 0)
            return (-1);
      return (0);
}

Generated by  Doxygen 1.6.0   Back to index