diff options
Diffstat (limited to 'wodim/drv_jvc.c')
-rw-r--r-- | wodim/drv_jvc.c | 1433 |
1 files changed, 1433 insertions, 0 deletions
diff --git a/wodim/drv_jvc.c b/wodim/drv_jvc.c new file mode 100644 index 0000000..ee2bcc2 --- /dev/null +++ b/wodim/drv_jvc.c @@ -0,0 +1,1433 @@ +/* + * 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_jvc.c 1.82 05/05/16 Copyright 1997-2005 J. Schilling */ +/* + * CDR device implementation for + * JVC/TEAC + * + * Copyright (c) 1997-2005 J. Schilling + */ +/* + * 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. + */ +/*#define XXDEBUG*/ +/*#define XXBUFFER*/ + +#include <mconfig.h> + +#include <stdio.h> +#include <standard.h> +#include <fctldefs.h> +#include <errno.h> +#include <strdefs.h> +#include <unixstd.h> +#ifdef XXDEBUG +#include <stdxlib.h> +#endif + +#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 "wodim.h" + +/* just a hack */ +long lba_addr; +BOOL last_done; + +/* + * macros for building MSF values from LBA + */ +#define LBA_MIN(x) ((x)/(60*75)) +#define LBA_SEC(x) (((x)%(60*75))/75) +#define LBA_FRM(x) ((x)%75) +#define MSF_CONV(a) ((((a)%(unsigned)100)/10)*16 + ((a)%(unsigned)10)) + +extern int lverbose; + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ +struct teac_mode_page_21 { /* teac dummy selection */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x01 = 1 Byte */ + Ucbit dummy : 2; + Ucbit res : 6; +}; +#else +struct teac_mode_page_21 { /* teac dummy selection */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x01 = 1 Byte */ + Ucbit res : 6; + Ucbit dummy : 2; +}; +#endif + +struct teac_mode_page_31 { /* teac speed selection */ + MP_P_CODE; /* parsave & pagecode */ + Uchar p_len; /* 0x02 = 2 Byte */ + Uchar speed; + Uchar res; +}; + +struct cdd_52x_mode_data { + struct scsi_mode_header header; + union cdd_pagex { + struct teac_mode_page_21 teac_page21; + struct teac_mode_page_31 teac_page31; + } pagex; +}; + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct pgm_subcode { /* subcode for progam area */ + Uchar subcode; + Ucbit addr : 4; + Ucbit control : 4; + Uchar track; + Uchar index; +}; + +#else + +struct pgm_subcode { /* subcode for progam area */ + Uchar subcode; + Ucbit control : 4; + Ucbit addr : 4; + Uchar track; + Uchar index; +}; + +#endif + +#define set_pgm_subcode(sp, t, c, a, tr, idx) (\ + (sp)->subcode = (t), \ + (sp)->control = (c), \ + (sp)->addr = (a), \ + (sp)->track = MSF_CONV(tr), \ + (sp)->index = (idx)) + +#define SC_P 1 /* Subcode defines pre-gap (Pause) */ +#define SC_TR 0 /* Subcode defines track data */ + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +typedef struct lin_subcode { /* subcode for lead in area */ + Ucbit addr : 4; + Ucbit control : 4; + Uchar track; + Uchar msf[3]; +} lsc_t; + +#else + +typedef struct lin_subcode { /* subcode for lead in area */ + Ucbit control : 4; + Ucbit addr : 4; + Uchar track; + Uchar msf[3]; +} lsc_t; + +#endif + +#define set_toc_subcode(sp, c, a, tr, bno) (\ + ((lsc_t *)sp)->control = (c), \ + ((lsc_t *)sp)->addr = (a), \ + ((lsc_t *)sp)->track = MSF_CONV(tr), \ + ((lsc_t *)sp)->msf[0] = MSF_CONV(LBA_MIN(bno)), \ + ((lsc_t *)sp)->msf[1] = MSF_CONV(LBA_SEC(bno)), \ + ((lsc_t *)sp)->msf[2] = MSF_CONV(LBA_FRM(bno)), \ + &((lsc_t *)sp)->msf[3]) + +#define set_lin_subcode(sp, c, a, pt, min, sec, frm) (\ + ((lsc_t *)sp)->control = (c), \ + ((lsc_t *)sp)->addr = (a), \ + ((lsc_t *)sp)->track = (pt), \ + ((lsc_t *)sp)->msf[0] = (min), \ + ((lsc_t *)sp)->msf[1] = (sec), \ + ((lsc_t *)sp)->msf[2] = (frm), \ + &((lsc_t *)sp)->msf[3]) + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct upc_subcode { /* subcode for upc/bar code */ + Uchar res; + Ucbit addr : 4; + Ucbit control : 4; + Uchar upc[13]; +}; + +#else + +struct upc_subcode { /* subcode for upc/bar code */ + Uchar res; + Ucbit control : 4; + Ucbit addr : 4; + Uchar upc[13]; +}; + +#endif + +#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */ + +struct isrc_subcode { /* subcode for ISRC code */ + Uchar res; + Ucbit addr : 4; + Ucbit control : 4; + Uchar isrc[12]; + Uchar res14; +}; + +#else + +struct isrc_subcode { /* subcode for ISRC code */ + Uchar res; + Ucbit control : 4; + Ucbit addr : 4; + Uchar isrc[12]; + Uchar res14; +}; + +#endif + + +static int teac_attach(SCSI *usalp, cdr_t *dp); +static int teac_init(SCSI *usalp, cdr_t *dp); +static int teac_getdisktype(SCSI *usalp, cdr_t *dp); +static int speed_select_teac(SCSI *usalp, cdr_t *dp, int *speedp); +static int select_secsize_teac(SCSI *usalp, track_t *trackp); +static int next_wr_addr_jvc(SCSI *usalp, track_t *, long *ap); +static int write_teac_xg1(SCSI *usalp, caddr_t, long, long, int, BOOL); +static int cdr_write_teac(SCSI *usalp, caddr_t bp, long sectaddr, long size, + int blocks, BOOL islast); +static int open_track_jvc(SCSI *usalp, cdr_t *dp, track_t *trackp); +static int teac_fixation(SCSI *usalp, cdr_t *dp, track_t *trackp); +static int close_track_teac(SCSI *usalp, cdr_t *dp, track_t *trackp); +static int teac_open_session(SCSI *usalp, cdr_t *dp, track_t *trackp); +static int initsub_teac(SCSI *usalp, int toctype, int multi); +static int teac_doopc(SCSI *usalp); +static int teac_opc(SCSI *usalp, caddr_t, int cnt, int doopc); +static int opt_power_judge(SCSI *usalp, int judge); +static int clear_subcode(SCSI *usalp); +static int set_limits(SCSI *usalp, long lba, long length); +static int set_subcode(SCSI *usalp, Uchar *subcode_data, int length); +static int read_disk_info_teac(SCSI *usalp, Uchar *data, int length, + int type); +static int teac_freeze(SCSI *usalp, int bp_flag); +static int teac_wr_pma(SCSI *usalp); +static int teac_rd_pma(SCSI *usalp); +static int next_wr_addr_teac(SCSI *usalp, long start_lba, long last_lba); +static int blank_jvc(SCSI *usalp, cdr_t *dp, long addr, int blanktype); +static int buf_cap_teac(SCSI *usalp, long *sp, long *fp); +static long read_peak_buffer_cap_teac(SCSI *usalp); +static int buffer_inquiry_teac(SCSI *usalp, int fmt); +#ifdef XXBUFFER +static void check_buffer_teac(SCSI *usalp); +#endif +#ifdef XXDEBUG +static void xxtest_teac(SCSI *usalp); +#endif + + +cdr_t cdr_teac_cdr50 = { + 0, 0, +/* CDR_TAO|CDR_SAO|CDR_SWABAUDIO|CDR_NO_LOLIMIT,*/ + CDR_TAO|CDR_SWABAUDIO|CDR_NO_LOLIMIT, + CDR_CDRW_ALL, + 2, 4, + "teac_cdr50", + "driver for Teac CD-R50S, Teac CD-R55S, JVC XR-W2010, Pinnacle RCD-5020", + 0, + (dstat_t *)0, + drive_identify, + teac_attach, + teac_init, + teac_getdisktype, + scsi_load, + scsi_unload, + buf_cap_teac, + cmd_dummy, /* recovery_needed */ + (int(*)(SCSI *, cdr_t *, int))cmd_dummy, /* recover */ + speed_select_teac, + select_secsize, + next_wr_addr_jvc, + (int(*)(SCSI *, Ulong))cmd_ill, /* reserve_track */ + cdr_write_teac, + (int(*)(track_t *, void *, BOOL))cmd_dummy, /* gen_cue */ + no_sendcue, + (int(*)(SCSI *, cdr_t *, track_t *))cmd_dummy, /* leadin */ + open_track_jvc, + close_track_teac, + teac_open_session, + cmd_dummy, + cmd_dummy, /* abort */ + read_session_offset_philips, + teac_fixation, + cmd_dummy, /* stats */ +/* blank_dummy,*/ + blank_jvc, + format_dummy, + teac_opc, + cmd_dummy, /* opt1 */ + cmd_dummy, /* opt2 */ +}; + +static int +teac_init(SCSI *usalp, cdr_t *dp) +{ + return (speed_select_teac(usalp, dp, NULL)); +} + +static int +teac_getdisktype(SCSI *usalp, cdr_t *dp) +{ + dstat_t *dsp = dp->cdr_dstat; + struct scsi_mode_data md; + int count = sizeof (struct scsi_mode_header) + + sizeof (struct scsi_mode_blockdesc); + int len; + int page = 0; + long l; + + fillbytes((caddr_t)&md, sizeof (md), '\0'); + + (void) test_unit_ready(usalp); + if (mode_sense(usalp, (Uchar *)&md, count, page, 0) < 0) { /* Page n current */ + return (-1); + } else { + len = ((struct scsi_mode_header *)&md)->sense_data_len + 1; + } + if (((struct scsi_mode_header *)&md)->blockdesc_len < 8) + return (-1); + + l = a_to_u_3_byte(md.blockdesc.nlblock); + dsp->ds_maxblocks = l; + return (drive_getdisktype(usalp, dp)); +} + +static int +speed_select_teac(SCSI *usalp, cdr_t *dp, int *speedp) +{ + struct cdd_52x_mode_data md; + int count; + int status; + int speed = 1; + BOOL dummy = (dp->cdr_cmdflags & F_DUMMY) != 0; + + if (speedp) + speed = *speedp; + + fillbytes((caddr_t)&md, sizeof (md), '\0'); + + count = sizeof (struct scsi_mode_header) + + sizeof (struct teac_mode_page_21); + + md.pagex.teac_page21.p_code = 0x21; + md.pagex.teac_page21.p_len = 0x01; + md.pagex.teac_page21.dummy = dummy?3:0; + + status = mode_select(usalp, (Uchar *)&md, count, 0, usalp->inq->data_format >= 2); + if (status < 0) + return (status); + + if (speedp == 0) + return (0); + + fillbytes((caddr_t)&md, sizeof (md), '\0'); + + count = sizeof (struct scsi_mode_header) + + sizeof (struct teac_mode_page_31); + + speed >>= 1; + md.pagex.teac_page31.p_code = 0x31; + md.pagex.teac_page31.p_len = 0x02; + md.pagex.teac_page31.speed = speed; + + return (mode_select(usalp, (Uchar *)&md, count, 0, usalp->inq->data_format >= 2)); +} + +static int +select_secsize_teac(SCSI *usalp, track_t *trackp) +{ + struct scsi_mode_data md; + int count = sizeof (struct scsi_mode_header) + + sizeof (struct scsi_mode_blockdesc); + int len; + int page = 0; + + fillbytes((caddr_t)&md, sizeof (md), '\0'); + + (void) test_unit_ready(usalp); + if (mode_sense(usalp, (Uchar *)&md, count, page, 0) < 0) { /* Page n current */ + return (-1); + } else { + len = ((struct scsi_mode_header *)&md)->sense_data_len + 1; + } + if (((struct scsi_mode_header *)&md)->blockdesc_len < 8) + return (-1); + + md.header.sense_data_len = 0; + md.header.blockdesc_len = 8; + + md.blockdesc.density = 1; + if (trackp->secsize == 2352) + md.blockdesc.density = 4; + i_to_3_byte(md.blockdesc.lblen, trackp->secsize); + + return (mode_select(usalp, (Uchar *)&md, count, 0, usalp->inq->data_format >= 2)); +} + +static int +next_wr_addr_jvc(SCSI *usalp, track_t *trackp, long *ap) +{ + if (trackp != 0 && trackp->track > 0) { + *ap = lba_addr; + } else { + long nwa; + + if (read_B0(usalp, TRUE, &nwa, NULL) < 0) + return (-1); + + *ap = nwa + 150; + } + return (0); +} + +static int +write_teac_xg1(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 extwr /* is an extended write */) +{ + register struct usal_cmd *scmd = usalp->scmd; + + fillbytes((caddr_t)scmd, sizeof (*scmd), '\0'); + scmd->addr = bp; + scmd->size = size; + scmd->flags = SCG_DISRE_ENA|SCG_CMD_RETRY; +/* scmd->flags = SCG_DISRE_ENA;*/ + scmd->cdb_len = SC_G1_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g1_cdb.cmd = SC_EWRITE; + scmd->cdb.g1_cdb.lun = usal_lun(usalp); + g1_cdbaddr(&scmd->cdb.g1_cdb, sectaddr); + g1_cdblen(&scmd->cdb.g1_cdb, blocks); + scmd->cdb.g1_cdb.vu_97 = extwr; + + usalp->cmdname = "write_teac_g1"; + + if (usal_cmd(usalp) < 0) + return (-1); + return (size - usal_getresid(usalp)); +} + +static int +cdr_write_teac(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 */) +{ + int ret; + + if (islast) + last_done = TRUE; + + ret = write_teac_xg1(usalp, bp, sectaddr, size, blocks, !islast); + if (ret < 0) + return (ret); + + lba_addr = sectaddr + blocks; +#ifdef XXBUFFER + check_buffer_teac(usalp); +#endif + return (ret); +} + +static int +open_track_jvc(SCSI *usalp, cdr_t *dp, track_t *trackp) +{ + int status; + long blocks; + long pregapsize; + struct pgm_subcode sc; + + last_done = FALSE; + + if (select_secsize_teac(usalp, trackp) < 0) + return (-1); + + status = clear_subcode(usalp); +/*next_wr_addr_teac(usalp);*/ + if (status < 0) + return (status); + +if (trackp->pregapsize != 0) { + if (lverbose > 1) { + printf("set_limits(%ld, %ld)-> %ld\n", + lba_addr, trackp->pregapsize, lba_addr + trackp->pregapsize); + } + + status = set_limits(usalp, lba_addr, trackp->pregapsize); + if (status < 0) + return (status); + + /* + * Set pre-gap (pause - index 0) + */ + set_pgm_subcode(&sc, SC_P, + st2mode[trackp->sectype&ST_MASK], ADR_POS, trackp->trackno, 0); + + if (lverbose > 1) + usal_prbytes("Subcode:", (Uchar *)&sc, sizeof (sc)); + + status = set_subcode(usalp, (Uchar *)&sc, sizeof (sc)); + if (status < 0) + return (status); + + pregapsize = trackp->pregapsize; + if (!is_audio(trackp)) { + lba_addr += 5; /* link & run in blocks */ + pregapsize -= 5; + } + if (lverbose > 1) { + printf("pad_track(%ld, %ld)-> %ld\n", + lba_addr, pregapsize, lba_addr + pregapsize); + } + /* + * XXX Do we need to check isecsize too? + */ + if (pad_track(usalp, dp, trackp, + lba_addr, (Llong)pregapsize*trackp->secsize, + FALSE, (Llong *)0) < 0) + return (-1); +} + + blocks = trackp->tracksize/trackp->secsize + + (trackp->tracksize%trackp->secsize?1:0); + blocks += trackp->padsecs; + if (blocks < 300) + blocks = 300; + if (!is_audio(trackp)) + blocks += 2; +if (!is_last(trackp) && trackp[1].pregapsize == 0) + blocks -= 150; + + /* + * set the limits for the new subcode - seems to apply to all + * of the data track. + * Unknown tracksize is handled in open_session. + * We definitely need to know the tracksize in this driver. + */ + if (lverbose > 1) { + printf("set_limits(%ld, %ld)-> %ld\n", + lba_addr, blocks, lba_addr + blocks); + } + status = set_limits(usalp, lba_addr, blocks); + if (status < 0) + return (status); + + /* + * Set track start (index 1) + */ + set_pgm_subcode(&sc, SC_TR, + st2mode[trackp->sectype&ST_MASK], ADR_POS, trackp->trackno, 1); + + if (lverbose > 1) + usal_prbytes("Subcode:", (Uchar *)&sc, sizeof (sc)); + + status = set_subcode(usalp, (Uchar *)&sc, sizeof (sc)); + if (status < 0) + return (status); + +if (!is_last(trackp) && trackp[1].pregapsize == 0) { + blocks += lba_addr; + pregapsize = 150; + + if (lverbose > 1) { + printf("set_limits(%ld, %ld)-> %ld\n", + blocks, pregapsize, blocks + pregapsize); + } + + status = set_limits(usalp, blocks, pregapsize); + if (status < 0) + return (status); + + /* + * Set pre-gap (pause - index 0) + */ + trackp++; + set_pgm_subcode(&sc, SC_P, + st2mode[trackp->sectype&ST_MASK], ADR_POS, trackp->trackno, 0); + + if (lverbose > 1) + usal_prbytes("Subcode:", (Uchar *)&sc, sizeof (sc)); + + status = set_subcode(usalp, (Uchar *)&sc, sizeof (sc)); + if (status < 0) + return (status); +} + return (status); +} + +static char sector[3000]; + +static int +close_track_teac(SCSI *usalp, cdr_t *dp, track_t *trackp) +{ + int ret = 0; + + if (!last_done) { + printf("WARNING: adding dummy block to close track.\n"); + /* + * need read sector size + * XXX do we really need this ? + * XXX if we need this can we set blocks to 0 ? + */ + ret = write_teac_xg1(usalp, sector, lba_addr, 2352, 1, FALSE); + lba_addr++; + } + if (!is_audio(trackp)) + lba_addr += 2; + teac_wr_pma(usalp); + return (ret); +} + + + +static const char *sd_teac50_error_str[] = { + "\100\200diagnostic failure on component parts", /* 40 80 */ + "\100\201diagnostic failure on memories", /* 40 81 */ + "\100\202diagnostic failure on cd-rom ecc circuit", /* 40 82 */ + "\100\203diagnostic failure on gate array", /* 40 83 */ + "\100\204diagnostic failure on internal SCSI controller", /* 40 84 */ + "\100\205diagnostic failure on servo processor", /* 40 85 */ + "\100\206diagnostic failure on program rom", /* 40 86 */ + "\100\220thermal sensor failure", /* 40 90 */ + "\200\000controller prom error", /* 80 00 */ /* JVC */ + "\201\000no disk present - couldn't get focus", /* 81 00 */ /* JVC */ + "\202\000no cartridge present", /* 82 00 */ /* JVC */ + "\203\000unable to spin up", /* 83 00 */ /* JVC */ + "\204\000addr exceeded the last valid block addr", /* 84 00 */ /* JVC */ + "\205\000sync error", /* 85 00 */ /* JVC */ + "\206\000address can't find or not data track", /* 86 00 */ /* JVC */ + "\207\000missing track", /* 87 00 */ /* JVC */ + "\213\000cartridge could not be ejected", /* 8B 00 */ /* JVC */ + "\215\000audio not playing", /* 8D 00 */ /* JVC */ + "\216\000read toc error", /* 8E 00 */ /* JVC */ + "\217\000a blank disk is detected by read toc", /* 8F 00 */ + "\220\000pma less disk - not a recordable disk", /* 90 00 */ + "\223\000mount error", /* 93 00 */ /* JVC */ + "\224\000toc less disk", /* 94 00 */ + "\225\000disc information less disk", /* 95 00 */ /* JVC */ + "\226\000disc information read error", /* 96 00 */ /* JVC */ + "\227\000linear velocity measurement error", /* 97 00 */ /* JVC */ + "\230\000drive sequence stop", /* 98 00 */ /* JVC */ + "\231\000actuator velocity control error", /* 99 00 */ /* JVC */ + "\232\000slider velocity control error", /* 9A 00 */ /* JVC */ + "\233\000opc initialize error", /* 9B 00 */ + "\233\001power calibration not executed", /* 9B 01 */ + "\234\000opc execution eror", /* 9C 00 */ + "\234\001alpc error - opc execution", /* 9C 01 */ + "\234\002opc execution timeout", /* 9C 02 */ + "\245\000disk application code does not match host application code", /* A5 00 */ + "\255\000completed preview write", /* AD 00 */ + "\256\000invalid B0 value", /* AE 00 */ /* JVC */ + "\257\000pca area full", /* AF 00 */ + "\260\000efm isn't detected", /* B0 00 */ /* JVC */ + "\263\000no logical sector", /* B3 00 */ /* JVC */ + "\264\000full pma area", /* B4 00 */ + "\265\000read address is atip area - blank", /* B5 00 */ + "\266\000write address is efm area - aleady written", /* B6 00 */ + "\271\000abnormal spinning - servo irq", /* B9 00 */ /* JVC */ + "\272\000no write data - buffer empty", /* BA 00 */ + "\273\000write emergency occurred", /* BB 00 */ + "\274\000read timeout", /* BC 00 */ /* JVC */ + "\277\000abnormal spin - nmi", /* BF 00 */ /* JVC */ + "\301\0004th run-in block detected", /* C1 00 */ + "\302\0003rd run-in block detected", /* C2 00 */ + "\303\0002nd run-in block detected", /* C3 00 */ + "\304\0001st run-in block detected", /* C4 00 */ + "\305\000link block detected", /* C5 00 */ + "\306\0001st run-out block detected", /* C6 00 */ + "\307\0002nd run-out block detected", /* C7 00 */ + "\314\000write request means mixed data mode", /* CC 00 */ + "\315\000unable to ensure reliable writing with the inserted disk - unsupported disk", /* CD 00 */ + "\316\000unable to ensure reliable writing as the inserted disk does not support speed", /* CE 00 */ + "\317\000unable to ensure reliable writing as the inserted disk has no char id code", /* CF 00 */ + NULL +}; + +static int +teac_attach(SCSI *usalp, cdr_t *dp) +{ + usal_setnonstderrs(usalp, sd_teac50_error_str); +#ifdef XXDEBUG + xxtest_teac(usalp); + exit(0); +#endif + return (0); +} + +static int +teac_fixation(SCSI *usalp, cdr_t *dp, track_t *trackp) +{ + long lba; + int status; + Uchar *sp; + Uint i; +extern char *buf; + + if (trackp->tracks < 1) { + /* + * We come here if wodim isonly called with the -fix option. + * As long as we cannot read and interpret the PMA, we must + * abort here. + */ + teac_rd_pma(usalp); +/* errmsgno(EX_BAD, "Cannot fixate zero track disk.\n");*/ + errmsgno(EX_BAD, "Cannot fixate without track list (not yet implemented).\n"); + return (-1); + } + sp = (Uchar *)buf; + + sleep(1); + + status = clear_subcode(usalp); + sleep(1); + if (status < 0) + return (status); + + sp[0] = 0; /* reserved */ + sp[1] = 0; /* reserved */ + sp[2] = 0; /* Q TNO */ + + sp = &sp[3]; /* point past header */ + + /* + * Set up TOC entries for all tracks + */ + for (i = 1; i <= trackp->tracks; i++) { + lba = trackp[i].trackstart+150; /* MSF=00:02:00 is LBA=0 */ + + sp = set_toc_subcode(sp, + /* ctrl/adr for this track */ + st2mode[trackp[i].sectype&ST_MASK], ADR_POS, + trackp[i].trackno, lba); + } + + /* + * Set first track on disk + * + * XXX We set the track type for the lead-in to the track type + * XXX of the first track. The TEAC manual states that we should use + * XXX audio if the disk contains both, audio and data tracks. + */ + sp = set_lin_subcode(sp, + /* ctrl/adr for first track */ + st2mode[trackp[1].sectype&ST_MASK], ADR_POS, + 0xA0, /* Point A0 */ + trackp[1].trackno, /* first track # */ + toc2sess[track_base(trackp)->tracktype & TOC_MASK], /* disk type */ + 0); /* reserved */ + + /* + * Set last track on disk + */ + sp = set_lin_subcode(sp, + /* ctrl/adr for first track */ + st2mode[trackp[1].sectype&ST_MASK], ADR_POS, + 0xA1, /* Point A1 */ + MSF_CONV(trackp[trackp->tracks].trackno), /* last track # */ + 0, /* reserved */ + 0); /* reserved */ + + /* + * Set start of lead out area in MSF + * MSF=00:02:00 is LBA=0 + */ + lba = lba_addr + 150; + if (lverbose > 1) + printf("lba: %ld lba_addr: %ld\n", lba, lba_addr); + + if (lverbose > 1) + printf("Lead out start: (%02d:%02d/%02d)\n", + minutes(lba*2352), + seconds(lba*2352), + frames(lba*2352)); + + sp = set_lin_subcode(sp, + /* ctrl/adr for first track */ + st2mode[trackp[1].sectype&ST_MASK], ADR_POS, + 0xA2, /* Point A2 */ + MSF_CONV(LBA_MIN(lba)), + MSF_CONV(LBA_SEC(lba)), + MSF_CONV(LBA_FRM(lba))); + + status = sp - ((Uchar *)buf); + if (lverbose > 1) { + printf("Subcode len: %d\n", status); + usal_prbytes("Subcode:", (Uchar *)buf, status); + } + status = set_subcode(usalp, (Uchar *)buf, status); + sleep(1); + if (status < 0) + return (status); + + /* + * now write the toc + */ + status = teac_freeze(usalp, (track_base(trackp)->tracktype & TOCF_MULTI) == 0); + return (status); + +} + +static int +teac_open_session(SCSI *usalp, cdr_t *dp, track_t *trackp) +{ + Uint i; + + for (i = 1; i <= trackp->tracks; i++) { + if (trackp[i].tracksize < (tsize_t)0) { + /* + * XXX How about setting the subcode range to infinity. + * XXX and correct it in clode track before writing + * XXX the PMA? + */ + errmsgno(EX_BAD, "Track %d has unknown length.\n", i); + return (-1); + } + } + return (initsub_teac(usalp, track_base(trackp)->tracktype & TOC_MASK, + track_base(trackp)->tracktype & TOCF_MULTI)); +} + +static int +initsub_teac(SCSI *usalp, int toctype, int multi) +{ + int status; + + usalp->silent++; + if (read_B0(usalp, TRUE, &lba_addr, NULL) < 0) + lba_addr = -150; + usalp->silent--; + + status = clear_subcode(usalp); + if (status < 0) + return (status); + + return (0); +} + +static int +teac_doopc(SCSI *usalp) +{ + int status; + + if (lverbose) { + fprintf(stdout, "Judging disk..."); + flush(); + } + status = opt_power_judge(usalp, 1); + if (status < 0) { + printf("\n"); + return (status); + } + if (lverbose) { + fprintf(stdout, "done.\nCalibrating laser..."); + flush(); + } + + status = opt_power_judge(usalp, 0); + if (lverbose) { + fprintf(stdout, "done.\n"); + } + /* + * Check for error codes 0xCD ... 0xCF + */ + usalp->silent++; + if (next_wr_addr_teac(usalp, -1, -1) < 0) { + if (usalp->verbose == 0 && usal_sense_key(usalp) != SC_ILLEGAL_REQUEST) + usal_printerr(usalp); + } + usalp->silent--; + return (status); +} + +static int +teac_opc(SCSI *usalp, caddr_t bp, int cnt, int doopc) +{ + int status; + int count = 0; + + do { + status = teac_doopc(usalp); + } while (++count <= 1 && status < 0); + + return (status); +} + +/*--------------------------------------------------------------------------*/ +#define SC_SET_LIMITS 0xb3 /* teac 12 byte command */ +#define SC_SET_SUBCODE 0xc2 /* teac 10 byte command */ +#define SC_READ_PMA 0xc4 /* teac 10 byte command */ +#define SC_READ_DISK_INFO 0xc7 /* teac 10 byte command */ +#define SC_BUFFER_INQUIRY 0xe0 /* teac 12 byte command */ + +#define SC_WRITE_PMA 0xe1 /* teac 12 byte command */ +#define SC_FREEZE 0xe3 /* teac 12 byte command */ +#define SC_OPC_EXECUTE 0xec /* teac 12 byte command */ +#define SC_CLEAR_SUBCODE 0xe4 /* teac 12 byte command */ +#define SC_NEXT_WR_ADDRESS 0xe6 /* teac 12 byte command */ + +#define SC_READ_PEAK_BUF_CAP 0xef /* teac 12 byte command */ + +/* + * Optimum power calibration for Teac Drives. + */ +static int +opt_power_judge(SCSI *usalp, int judge) +{ + 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_RECV_DATA|SCG_DISRE_ENA; + scmd->cdb_len = SC_G5_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->timeout = 60; + + scmd->cdb.g5_cdb.cmd = SC_OPC_EXECUTE; + scmd->cdb.g5_cdb.lun = usal_lun(usalp); + scmd->cdb.g5_cdb.reladr = judge; /* Judge the Disc */ + + usalp->cmdname = "opt_power_judge"; + + return (usal_cmd(usalp)); +} + +/* + * Clear subcodes for Teac Drives. + */ +static int +clear_subcode(SCSI *usalp) +{ + 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_G5_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + + scmd->cdb.g5_cdb.cmd = SC_CLEAR_SUBCODE; + scmd->cdb.g5_cdb.lun = usal_lun(usalp); + scmd->cdb.g5_cdb.addr[3] = 0x80; + + usalp->cmdname = "clear subcode"; + + return (usal_cmd(usalp)); +} + +/* + * Set limits for command linking for Teac Drives. + */ +static int +set_limits(SCSI *usalp, long lba, long length) +{ + 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_G5_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + + scmd->cdb.g5_cdb.cmd = SC_SET_LIMITS; + scmd->cdb.g5_cdb.lun = usal_lun(usalp); + i_to_4_byte(&scmd->cdb.g5_cdb.addr[0], lba); + i_to_4_byte(&scmd->cdb.g5_cdb.count[0], length); + + usalp->cmdname = "set limits"; + + return (usal_cmd(usalp)); +} + +/* + * Set subcode for Teac Drives. + */ +static int +set_subcode(SCSI *usalp, Uchar *subcode_data, int length) +{ + register struct usal_cmd *scmd = usalp->scmd; + + fillbytes((caddr_t)scmd, sizeof (*scmd), '\0'); + scmd->addr = (caddr_t)subcode_data; + scmd->size = length; + scmd->flags = SCG_DISRE_ENA; + scmd->cdb_len = SC_G1_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + + scmd->cdb.g1_cdb.cmd = SC_SET_SUBCODE; + scmd->cdb.g1_cdb.lun = usal_lun(usalp); + g1_cdblen(&scmd->cdb.g1_cdb, length); + + usalp->cmdname = "set subcode"; + + return (usal_cmd(usalp)); +} + +static int +read_disk_info_teac(SCSI *usalp, Uchar *data, int length, int type) +{ + register struct usal_cmd *scmd = usalp->scmd; + + fillbytes((caddr_t)scmd, sizeof (*scmd), '\0'); + scmd->addr = (caddr_t)data; + scmd->size = length; + 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 = SC_READ_DISK_INFO; + scmd->cdb.g1_cdb.lun = usal_lun(usalp); + + scmd->cdb.g1_cdb.reladr = type & 1; + scmd->cdb.g1_cdb.res = (type & 2) >> 1; + + usalp->cmdname = "read disk info teac"; + + return (usal_cmd(usalp)); +} + +/* + * Perform the freeze command for Teac Drives. + */ +static int +teac_freeze(SCSI *usalp, int bp_flag) +{ + 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_G5_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->timeout = 8 * 60; /* Needs up to 4 minutes */ + + scmd->cdb.g5_cdb.cmd = SC_FREEZE; + scmd->cdb.g5_cdb.lun = usal_lun(usalp); + scmd->cdb.g5_cdb.addr[3] = bp_flag ? 0x80 : 0; + + usalp->cmdname = "teac_freeze"; + + return (usal_cmd(usalp)); +} + +static int +teac_wr_pma(SCSI *usalp) +{ + 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_G5_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + + scmd->cdb.g5_cdb.cmd = SC_WRITE_PMA; + scmd->cdb.g5_cdb.lun = usal_lun(usalp); + + usalp->cmdname = "teac_write_pma"; + + return (usal_cmd(usalp)); +} + +/* + * Read PMA for Teac Drives. + */ +static int +teac_rd_pma(SCSI *usalp) +{ + unsigned char xx[256]; + register struct usal_cmd *scmd = usalp->scmd; + + fillbytes((caddr_t)xx, sizeof (xx), '\0'); + fillbytes((caddr_t)scmd, sizeof (*scmd), '\0'); + scmd->addr = (caddr_t)xx; + scmd->size = sizeof (xx); + 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 = SC_READ_PMA; + scmd->cdb.g1_cdb.lun = usal_lun(usalp); + + g1_cdblen(&scmd->cdb.g1_cdb, sizeof (xx)); + + usalp->cmdname = "teac_read_pma"; + +/* return (usal_cmd(usalp));*/ + if (usal_cmd(usalp) < 0) + return (-1); + + if (usalp->verbose) { + usal_prbytes("PMA Data", xx, sizeof (xx) - usal_getresid(usalp)); + } + if (lverbose) { + unsigned i; + Uchar *p; + + usal_prbytes("PMA Header: ", xx, 4); + i = xx[2]; + p = &xx[4]; + for (; i <= xx[3]; i++) { + usal_prbytes("PMA: ", p, 10); + p += 10; + } + } + return (0); +} + +/* + * Next writable address for Teac Drives. + */ +static int +next_wr_addr_teac(SCSI *usalp, long start_lba, long last_lba) +{ + unsigned char xx[256]; + register struct usal_cmd *scmd = usalp->scmd; + + fillbytes((caddr_t)xx, sizeof (xx), '\0'); + fillbytes((caddr_t)scmd, sizeof (*scmd), '\0'); + scmd->addr = (caddr_t)xx; + scmd->size = sizeof (xx); + scmd->flags = SCG_RECV_DATA |SCG_DISRE_ENA; + scmd->cdb_len = SC_G5_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + + scmd->cdb.g5_cdb.cmd = SC_NEXT_WR_ADDRESS; + scmd->cdb.g5_cdb.lun = usal_lun(usalp); + + i_to_4_byte(&scmd->cdb.g5_cdb.addr[0], start_lba); + i_to_4_byte(&scmd->cdb.g5_cdb.count[0], last_lba); + + if (usalp->verbose) + printf("start lba: %ld last lba: %ld\n", + start_lba, last_lba); + + usalp->cmdname = "next writable address"; + +/* return (usal_cmd(usalp));*/ + if (usal_cmd(usalp) < 0) + return (-1); + + if (usalp->verbose) { + usal_prbytes("WRa Data", xx, sizeof (xx) - usal_getresid(usalp)); + printf("NWA: %ld\n", a_to_4_byte(xx)); + } + return (0); +} + +static int +blank_jvc(SCSI *usalp, cdr_t *dp, long addr, int blanktype) +{ + extern char *blank_types[]; + + if (lverbose) { + printf("Blanking %s\n", blank_types[blanktype & 0x07]); + flush(); + } + + return (scsi_blank(usalp, addr, blanktype, FALSE)); +} + +static int +buf_cap_teac(SCSI *usalp, long *sp, long *fp) +{ + Ulong freespace; + Ulong bufsize; + long ret; + int per; + + ret = read_peak_buffer_cap_teac(usalp); + if (ret < 0) + return (-1); + bufsize = ret; + freespace = 0; + if (sp) + *sp = bufsize; + if (fp) + *fp = freespace; + + if (usalp->verbose || (sp == 0 && fp == 0)) + printf("BFree: %ld K BSize: %ld K\n", freespace >> 10, bufsize >> 10); + + if (bufsize == 0) + return (0); + per = (100 * (bufsize - freespace)) / bufsize; + if (per < 0) + return (0); + if (per > 100) + return (100); + return (per); +} + +static long +read_peak_buffer_cap_teac(SCSI *usalp) +{ + Uchar xx[4]; + register struct usal_cmd *scmd = usalp->scmd; + + fillbytes((caddr_t)xx, sizeof (xx), '\0'); + fillbytes((caddr_t)scmd, sizeof (*scmd), '\0'); + scmd->addr = (caddr_t)xx; + scmd->size = sizeof (xx); + scmd->flags = SCG_RECV_DATA |SCG_DISRE_ENA; + scmd->cdb_len = SC_G5_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + + scmd->cdb.g5_cdb.cmd = SC_READ_PEAK_BUF_CAP; + scmd->cdb.g5_cdb.lun = usal_lun(usalp); + + usalp->cmdname = "read peak buffer capacity"; + +#define BDEBUG +#ifndef BDEBUG + return (usal_cmd(usalp)); +#else + if (usal_cmd(usalp) < 0) + return (-1); + + if (usalp->verbose) { + usal_prbytes("WRa Data", xx, sizeof (xx) - usal_getresid(usalp)); + printf("Buffer cap: %ld\n", a_to_u_3_byte(&xx[1])); + } + return (a_to_u_3_byte(&xx[1])); +/* return (0);*/ +#endif +} + +#define BI_ONE_BYTE 0xC0 +#define BI_448_BYTE 0x40 +#define BI_APP_CODE 0x10 + +static int +buffer_inquiry_teac(SCSI *usalp, int fmt) +{ + Uchar xx[448]; + register struct usal_cmd *scmd = usalp->scmd; + + fillbytes((caddr_t)xx, sizeof (xx), '\0'); + fillbytes((caddr_t)scmd, sizeof (*scmd), '\0'); + scmd->addr = (caddr_t)xx; + scmd->size = sizeof (xx); + scmd->size = 448; + scmd->flags = SCG_RECV_DATA |SCG_DISRE_ENA; + scmd->cdb_len = SC_G5_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + + scmd->cdb.g5_cdb.cmd = SC_BUFFER_INQUIRY; + scmd->cdb.g5_cdb.lun = usal_lun(usalp); + + if (fmt > 0) { + scmd->cdb.g5_cdb.addr[3] = fmt; + if (fmt == BI_ONE_BYTE) + scmd->size = 1; + } else { + scmd->cdb.g5_cdb.addr[3] = BI_448_BYTE; +/* scmd->cdb.g5_cdb.addr[3] = BI_APP_CODE;*/ + } + + usalp->cmdname = "buffer inquiry"; + +#define BDEBUG +#ifndef BDEBUG + return (usal_cmd(usalp)); +#else + if (usal_cmd(usalp) < 0) + return (-1); + + if (usalp->verbose) { +/* usal_prbytes("WRa Data", xx, sizeof (xx) - usal_getresid(usalp));*/ +/* usal_prbytes("WRa Data", xx, 1);*/ + + if (fmt > 0) printf("fmt: %X ", fmt); + usal_prbytes("WRa Data", xx, 9); + printf("%d\n", xx[8] - xx[1]); +/* printf("Buffer cap: %ld\n", a_to_u_3_byte(&xx[1]));*/ + } + return (0); +#endif +} + +#ifdef XXBUFFER +static void +check_buffer_teac(SCSI *usalp) +{ + printf("-------\n"); + buffer_inquiry_teac(usalp, 0); +#ifdef SL + usleep(40000); + buffer_inquiry_teac(usalp, 0); +#endif + read_peak_buffer_cap_teac(usalp); +} +#endif +/*--------------------------------------------------------------------------*/ +#ifdef XXDEBUG +#include "scsimmc.h" + +static int g7_teac(SCSI *usalp); +static int g6_teac(SCSI *usalp); + +static int +g7_teac(SCSI *usalp) +{ + Uchar xx[2048]; + register struct usal_cmd *scmd = usalp->scmd; + + fillbytes((caddr_t)xx, sizeof (xx), '\0'); + fillbytes((caddr_t)scmd, sizeof (*scmd), '\0'); + scmd->addr = (caddr_t)xx; + scmd->size = sizeof (xx); + scmd->flags = SCG_RECV_DATA |SCG_DISRE_ENA; + scmd->cdb_len = SC_G5_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + + scmd->cdb.g5_cdb.cmd = 0xDf; +/* scmd->cdb.g5_cdb.cmd = 0xE5;*/ + scmd->cdb.g5_cdb.lun = usal_lun(usalp); + +/* scmd->cdb.g5_cdb.addr[3] = BI_ONE_BYTE;*/ +/* scmd->size = 1;*/ + +/* scmd->cdb.g5_cdb.addr[3] = BI_448_BYTE;*/ +/* scmd->cdb.g5_cdb.addr[3] = BI_APP_CODE;*/ + + usalp->cmdname = "g7 teac"; + +/* return (usal_cmd(usalp));*/ + if (usal_cmd(usalp) < 0) + return (-1); + +/* if (usalp->verbose) {*/ + usal_prbytes("WRa Data", xx, sizeof (xx) - usal_getresid(usalp)); +/* usal_prbytes("WRa Data", xx, 1);*/ +/* usal_prbytes("WRa Data", xx, 9);*/ +/*printf("%d\n", xx[8] - xx[1]);*/ +/* printf("Buffer cap: %ld\n", a_to_u_3_byte(&xx[1]));*/ +/* }*/ + return (0); +} + +static int +g6_teac(SCSI *usalp) +{ + Uchar xx[2048]; + register struct usal_cmd *scmd = usalp->scmd; + + fillbytes((caddr_t)xx, sizeof (xx), '\0'); + fillbytes((caddr_t)scmd, sizeof (*scmd), '\0'); + scmd->addr = (caddr_t)xx; + scmd->size = sizeof (xx); + 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 = 0xC1; + scmd->cdb.g1_cdb.cmd = 0xC3; + scmd->cdb.g1_cdb.cmd = 0xC6; + scmd->cdb.g1_cdb.cmd = 0xC7; /* Read TOC */ + scmd->cdb.g1_cdb.cmd = 0xCe; + scmd->cdb.g1_cdb.cmd = 0xCF; + scmd->cdb.g1_cdb.cmd = 0xC7; /* Read TOC */ + scmd->cdb.g1_cdb.lun = usal_lun(usalp); + + usalp->cmdname = "g6 teac"; + +/* return (usal_cmd(usalp));*/ + if (usal_cmd(usalp) < 0) + return (-1); + +/* if (usalp->verbose) {*/ + usal_prbytes("WRa Data", xx, sizeof (xx) - usal_getresid(usalp)); +/* usal_prbytes("WRa Data", xx, 1);*/ +/* usal_prbytes("WRa Data", xx, 9);*/ +/*printf("%d\n", xx[8] - xx[1]);*/ +/* printf("Buffer cap: %ld\n", a_to_u_3_byte(&xx[1]));*/ +/* }*/ + return (0); +} + +static void +xxtest_teac(SCSI *usalp) +{ + read_peak_buffer_cap_teac(usalp); + +/*#define XDI*/ +#ifdef XDI + { + Uchar cbuf[512]; + +/* read_disk_info_teac(usalp, data, length, type)*/ +/* read_disk_info_teac(usalp, cbuf, 512, 2);*/ +/* read_disk_info_teac(usalp, cbuf, 512, 2);*/ + read_disk_info_teac(usalp, cbuf, 512, 3); + usal_prbytes("DI Data", cbuf, sizeof (cbuf) - usal_getresid(usalp)); + } +#endif /* XDI */ + + buffer_inquiry_teac(usalp, -1); + +/*#define XBU*/ +#ifdef XBU + { + int i; + + for (i = 0; i < 63; i++) { + usalp->silent++; + buffer_inquiry_teac(usalp, i<<2); + usalp->silent--; + } + } +#endif /* XBU */ + +/* printf("LLLL\n");*/ +/* g7_teac(usalp);*/ +/* g6_teac(usalp);*/ +} +#endif /* XXDEBUG */ |