/* * 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_mmc.c 1.163 06/01/12 Copyright 1997-2006 J. Schilling */ /* * CDR device implementation for * SCSI-3/mmc conforming drives * e.g. Yamaha CDR-400, Ricoh MP6200 * * Copyright (c) 1997-2006 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 DEBUG*/ #define PRINT_ATIP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "scsimmc.h" #include "mmcvendor.h" #include "wodim.h" #include "scsi_scan.h" extern char *driveropts; extern int debug; extern int lverbose; extern int xdebug; static int curspeed = 1; static char clv_to_speed[16] = { /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ 0, 2, 4, 6, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static char hs_clv_to_speed[16] = { /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ 0, 2, 4, 6, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static char us_clv_to_speed[16] = { /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ 0, 2, 4, 8, 0, 0, 16, 0, 24, 32, 40, 48, 0, 0, 0, 0 }; #ifdef __needed__ static int mmc_load(SCSI *usalp, cdr_t *dp); static int mmc_unload(SCSI *usalp, cdr_t *dp); #endif void mmc_opthelp(cdr_t *dp, int excode); char *hasdrvopt(char *optstr, char *optname); static cdr_t *identify_mmc(SCSI *usalp, cdr_t *, struct scsi_inquiry *); static int attach_mmc(SCSI *usalp, cdr_t *); static int attach_mdvd(SCSI *usalp, cdr_t *); int check_writemodes_mmc(SCSI *usalp, cdr_t *dp); int check_writemodes_mdvd(SCSI *usalp, cdr_t *dp); static int deflt_writemodes_mmc(SCSI *usalp, BOOL reset_dummy); static int deflt_writemodes_mdvd(SCSI *usalp, BOOL reset_dummy); static int get_diskinfo(SCSI *usalp, struct disk_info *dip); static void di_to_dstat(struct disk_info *dip, dstat_t *dsp); static int get_atip(SCSI *usalp, struct atipinfo *atp); #ifdef PRINT_ATIP static int get_pma(SCSI *usalp); #endif static int init_mmc(SCSI *usalp, cdr_t *dp); static int getdisktype_mmc(SCSI *usalp, cdr_t *dp); static int getdisktype_mdvd(SCSI *usalp, cdr_t *dp); static int speed_select_mmc(SCSI *usalp, cdr_t *dp, int *speedp); static int speed_select_mdvd(SCSI *usalp, cdr_t *dp, int *speedp); static int mmc_set_speed(SCSI *usalp, int readspeed, int writespeed, int rotctl); static int next_wr_addr_mmc(SCSI *usalp, track_t *trackp, long *ap); static int next_wr_addr_mdvd(SCSI *usalp, track_t *trackp, long *ap); static int write_leadin_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp); static int open_track_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp); static int open_track_mdvd(SCSI *usalp, cdr_t *dp, track_t *trackp); static int close_track_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp); static int close_track_mdvd(SCSI *usalp, cdr_t *dp, track_t *trackp); static int open_session_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp); static int open_session_mdvd(SCSI *usalp, cdr_t *dp, track_t *trackp); static int waitfix_mmc(SCSI *usalp, int secs); static int fixate_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp); static int fixate_mdvd(SCSI *usalp, cdr_t *dp, track_t *trackp); static int blank_mmc(SCSI *usalp, cdr_t *dp, long addr, int blanktype); static int format_mdvd(SCSI *usalp, cdr_t *dp, int formattype); static int send_opc_mmc(SCSI *usalp, caddr_t, int cnt, int doopc); static int opt1_mmc(SCSI *usalp, cdr_t *dp); static int opt1_mdvd(SCSI *usalp, cdr_t *dp); static int opt2_mmc(SCSI *usalp, cdr_t *dp); static int scsi_sony_write(SCSI *usalp, caddr_t bp, long sectaddr, long size, int blocks, BOOL islast); static int gen_cue_mmc(track_t *trackp, void *vcuep, BOOL needgap); static void fillcue(struct mmc_cue *cp, int ca, int tno, int idx, int dataform, int scms, msf_t *mp); static int send_cue_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp); static int stats_mmc(SCSI *usalp, cdr_t *dp); static BOOL mmc_isplextor(SCSI *usalp); static BOOL mmc_isyamaha(SCSI *usalp); static void do_varirec_plextor(SCSI *usalp); static int do_gigarec_plextor(SCSI *usalp); static int drivemode_plextor(SCSI *usalp, caddr_t bp, int cnt, int modecode, void *modeval); static int drivemode2_plextor(SCSI *usalp, caddr_t bp, int cnt, int modecode, void *modeval); static int check_varirec_plextor(SCSI *usalp); static int check_gigarec_plextor(SCSI *usalp); static int varirec_plextor(SCSI *usalp, BOOL on, int val); static int gigarec_plextor(SCSI *usalp, int val); static Int32_t gigarec_mult(int code, Int32_t val); static int check_ss_hide_plextor(SCSI *usalp); static int check_speed_rd_plextor(SCSI *usalp); static int check_powerrec_plextor(SCSI *usalp); static int ss_hide_plextor(SCSI *usalp, BOOL do_ss, BOOL do_hide); static int speed_rd_plextor(SCSI *usalp, BOOL do_speedrd); static int powerrec_plextor(SCSI *usalp, BOOL do_powerrec); static int get_speeds_plextor(SCSI *usalp, int *selp, int *maxp, int *lastp); static int bpc_plextor(SCSI *usalp, int mode, int *bpp); static int set_audiomaster_yamaha(SCSI *usalp, cdr_t *dp, BOOL keep_mode); struct ricoh_mode_page_30 * get_justlink_ricoh(SCSI *usalp, Uchar *mode); static int force_speed_yamaha(SCSI *usalp, int readspeed, int writespeed); static BOOL get_tattoo_yamaha(SCSI *usalp, BOOL print, Int32_t *irp, Int32_t *orp); static int do_tattoo_yamaha(SCSI *usalp, FILE *f); static int yamaha_write_buffer(SCSI *usalp, int mode, int bufferid, long offset, long parlen, void *buffer, long buflen); static int dvd_dual_layer_split(SCSI *usalp, cdr_t *dp, long tsize); extern int reserve_track(SCSI *usalp, Ulong size); /* FIXME */ extern int scsi_format(SCSI *usalp, caddr_t addr, int size, BOOL background); /* FIXME */ #ifdef __needed__ static int mmc_load(SCSI *usalp, cdr_t *dp) { return (scsi_load_unload(usalp, 1)); } static int mmc_unload(SCSI *usalp, cdr_t *dp) { return (scsi_load_unload(usalp, 0)); } #endif /* * MMC CD-writer */ cdr_t cdr_mmc = { 0, 0, CDR_SWABAUDIO, CDR_CDRW_ALL, 372, 372, "mmc_cdr", "generic SCSI-3/mmc CD-R/CD-RW driver", 0, (dstat_t *)0, identify_mmc, attach_mmc, init_mmc, getdisktype_mmc, scsi_load, scsi_unload, read_buff_cap, cmd_dummy, /* check_recovery */ (int(*)(SCSI *, cdr_t *, int))cmd_dummy, /* recover */ speed_select_mmc, select_secsize, next_wr_addr_mmc, (int(*)(SCSI *, Ulong))cmd_ill, /* reserve_track */ scsi_cdr_write, gen_cue_mmc, send_cue_mmc, write_leadin_mmc, open_track_mmc, close_track_mmc, open_session_mmc, cmd_dummy, cmd_dummy, /* abort */ read_session_offset, fixate_mmc, stats_mmc, blank_mmc, format_dummy, send_opc_mmc, opt1_mmc, opt2_mmc, }; cdr_t cdr_mdvd = { 0, 0, CDR_SWABAUDIO, CDR_CDRW_ALL, 370,370, "mmc_mdvd", "generic SCSI-3/mmc DVD-R(W) driver", 0, (dstat_t *)0, identify_mmc, attach_mdvd, init_mmc, getdisktype_mdvd, scsi_load, scsi_unload, read_buff_cap, cmd_dummy, /* check_recovery */ (int(*)__PR((SCSI *, cdr_t *, int)))cmd_dummy, /* recover */ speed_select_mdvd, select_secsize, next_wr_addr_mdvd, (int(*)(SCSI *, Ulong))cmd_ill, /* reserve_track */ scsi_cdr_write, (int(*)__PR((track_t *, void *, BOOL)))cmd_dummy, /* gen_cue */ (int(*)__PR((SCSI *usalp, cdr_t *, track_t *)))cmd_dummy, /* send_cue */ write_leadin_mmc, open_track_mdvd, close_track_mdvd, open_session_mdvd, cmd_dummy, cmd_dummy, /* abort */ read_session_offset, fixate_mdvd, stats_mmc, blank_mmc, format_mdvd, send_opc_mmc, opt1_mdvd, opt2_mmc, dvd_dual_layer_split, }; /* * Sony MMC CD-writer */ cdr_t cdr_mmc_sony = { 0, 0, CDR_SWABAUDIO, CDR_CDRW_ALL, 372, 372, "mmc_cdr_sony", "generic SCSI-3/mmc CD-R/CD-RW driver (Sony 928 variant)", 0, (dstat_t *)0, identify_mmc, attach_mmc, init_mmc, getdisktype_mmc, scsi_load, scsi_unload, read_buff_cap, cmd_dummy, /* check_recovery */ (int(*)(SCSI *, cdr_t *, int))cmd_dummy, /* recover */ speed_select_mmc, select_secsize, next_wr_addr_mmc, (int(*)(SCSI *, Ulong))cmd_ill, /* reserve_track */ scsi_sony_write, gen_cue_mmc, send_cue_mmc, write_leadin_mmc, open_track_mmc, close_track_mmc, open_session_mmc, cmd_dummy, cmd_dummy, /* abort */ read_session_offset, fixate_mmc, cmd_dummy, /* stats */ blank_mmc, format_dummy, send_opc_mmc, opt1_mmc, opt2_mmc, }; /* * SCSI-3/mmc conformant CD-ROM drive */ cdr_t cdr_cd = { 0, 0, CDR_ISREADER|CDR_SWABAUDIO, CDR_CDRW_NONE, 372, 372, "mmc_cd", "generic SCSI-3/mmc CD-ROM driver", 0, (dstat_t *)0, identify_mmc, attach_mmc, cmd_dummy, drive_getdisktype, scsi_load, scsi_unload, read_buff_cap, cmd_dummy, /* check_recovery */ (int(*)(SCSI *, cdr_t *, int))cmd_dummy, /* recover */ speed_select_mmc, select_secsize, (int(*)(SCSI *usalp, track_t *, long *))cmd_ill, /* next_wr_addr */ (int(*)(SCSI *, Ulong))cmd_ill, /* reserve_track */ scsi_cdr_write, (int(*)(track_t *, void *, BOOL))cmd_dummy, /* gen_cue */ no_sendcue, (int(*)(SCSI *, cdr_t *, track_t *))cmd_dummy, /* leadin */ open_track_mmc, close_track_mmc, (int(*)(SCSI *usalp, cdr_t *, track_t *))cmd_dummy, cmd_dummy, cmd_dummy, /* abort */ read_session_offset, (int(*)(SCSI *usalp, cdr_t *, track_t *))cmd_dummy, /* fixation */ cmd_dummy, /* stats */ blank_dummy, format_dummy, (int(*)(SCSI *, caddr_t, int, int))NULL, /* no OPC */ cmd_dummy, /* opt1 */ cmd_dummy, /* opt2 */ }; /* * Old pre SCSI-3/mmc CD drive */ cdr_t cdr_oldcd = { 0, 0, CDR_ISREADER, CDR_CDRW_NONE, 372, 372, "scsi2_cd", "generic SCSI-2 CD-ROM driver", 0, (dstat_t *)0, identify_mmc, drive_attach, cmd_dummy, drive_getdisktype, scsi_load, scsi_unload, buf_dummy, cmd_dummy, /* check_recovery */ (int(*)(SCSI *, cdr_t *, int))cmd_dummy, /* recover */ speed_select_mmc, select_secsize, (int(*)(SCSI *usal, track_t *, long *))cmd_ill, /* next_wr_addr */ (int(*)(SCSI *, Ulong))cmd_ill, /* reserve_track */ scsi_cdr_write, (int(*)(track_t *, void *, BOOL))cmd_dummy, /* gen_cue */ no_sendcue, (int(*)(SCSI *, cdr_t *, track_t *))cmd_dummy, /* leadin */ open_track_mmc, close_track_mmc, (int(*)(SCSI *usalp, cdr_t *, track_t *))cmd_dummy, cmd_dummy, cmd_dummy, /* abort */ read_session_offset_philips, (int(*)(SCSI *usalp, cdr_t *, track_t *))cmd_dummy, /* fixation */ cmd_dummy, /* stats */ blank_dummy, format_dummy, (int(*)(SCSI *, caddr_t, int, int))NULL, /* no OPC */ cmd_dummy, /* opt1 */ cmd_dummy, /* opt2 */ }; /* * SCSI-3/mmc conformant CD or DVD writer * Checks the current medium and then returns either cdr_mmc or cdr_dvd */ cdr_t cdr_cd_dvd = { 0, 0, CDR_SWABAUDIO, CDR_CDRW_ALL, 372, 372, "mmc_cd_dvd", "generic SCSI-3/mmc CD/DVD driver (checks media)", 0, (dstat_t *)0, identify_mmc, attach_mmc, cmd_dummy, drive_getdisktype, scsi_load, scsi_unload, read_buff_cap, cmd_dummy, /* check_recovery */ (int(*)(SCSI *, cdr_t *, int))cmd_dummy, /* recover */ speed_select_mmc, select_secsize, (int(*)(SCSI *usalp, track_t *, long *))cmd_ill, /* next_wr_addr */ (int(*)(SCSI *, Ulong))cmd_ill, /* reserve_track */ scsi_cdr_write, (int(*)(track_t *, void *, BOOL))cmd_dummy, /* gen_cue */ no_sendcue, (int(*)(SCSI *, cdr_t *, track_t *))cmd_dummy, /* leadin */ open_track_mmc, close_track_mmc, (int(*)(SCSI *usalp, cdr_t *, track_t *))cmd_dummy, cmd_dummy, cmd_dummy, /* abort */ read_session_offset, (int(*)(SCSI *usalp, cdr_t *, track_t *))cmd_dummy, /* fixation */ cmd_dummy, /* stats */ blank_dummy, format_dummy, (int(*)(SCSI *, caddr_t, int, int))NULL, /* no OPC */ cmd_dummy, /* opt1 */ cmd_dummy, /* opt2 */ }; void mmc_opthelp(cdr_t *dp, int excode) { BOOL haveopts = FALSE; fprintf(stderr, "Driver options:\n"); if (dp->cdr_flags & CDR_BURNFREE) { fprintf(stderr, "burnfree Prepare writer to use BURN-Free technology\n"); fprintf(stderr, "noburnfree Disable using BURN-Free technology\n"); haveopts = TRUE; } if (dp->cdr_flags & CDR_VARIREC) { fprintf(stderr, "varirec=val Set VariRec Laserpower to -2, -1, 0, 1, 2\n"); fprintf(stderr, " Only works for audio and if speed is set to 4\n"); haveopts = TRUE; } if (dp->cdr_flags & CDR_GIGAREC) { fprintf(stderr, "gigarec=val Set GigaRec capacity ratio to 0.6, 0.7, 0.8, 1.0, 1.2, 1.3, 1.4\n"); haveopts = TRUE; } if (dp->cdr_flags & CDR_AUDIOMASTER) { fprintf(stderr, "audiomaster Turn Audio Master feature on (SAO CD-R Audio/Data only)\n"); haveopts = TRUE; } if (dp->cdr_flags & CDR_FORCESPEED) { fprintf(stderr, "forcespeed Tell the drive to force speed even for low quality media\n"); haveopts = TRUE; } if (dp->cdr_flags & CDR_SPEEDREAD) { fprintf(stderr, "speedread Tell the drive to read as fast as possible\n"); fprintf(stderr, "nospeedread Disable to read as fast as possible\n"); haveopts = TRUE; } if (dp->cdr_flags & CDR_DISKTATTOO) { fprintf(stderr, "tattooinfo Print image size info for DiskT@2 feature\n"); fprintf(stderr, "tattoofile=name Use 'name' as DiskT@2 image file\n"); haveopts = TRUE; } if (dp->cdr_flags & CDR_SINGLESESS) { fprintf(stderr, "singlesession Tell the drive to behave as single session only drive\n"); fprintf(stderr, "nosinglesession Disable single session only mode\n"); haveopts = TRUE; } if (dp->cdr_flags & CDR_HIDE_CDR) { fprintf(stderr, "hidecdr Tell the drive to hide CD-R media\n"); fprintf(stderr, "nohidecdr Disable hiding CD-R media\n"); haveopts = TRUE; } if (!haveopts) { fprintf(stderr, "None supported for this drive.\n"); } exit(excode); } char * hasdrvopt(char *optstr, char *optname) { char *ep; char *np; char *ret = NULL; int optnamelen; int optlen; BOOL not = FALSE; if (optstr == NULL) return (ret); optnamelen = strlen(optname); while (*optstr) { not = FALSE; /* Reset before every token */ if ((ep = strchr(optstr, ',')) != NULL) { optlen = ep - optstr; np = &ep[1]; } else { optlen = strlen(optstr); np = &optstr[optlen]; } if ((ep = strchr(optstr, '=')) != NULL) { if (ep < np) optlen = ep - optstr; } if (optstr[0] == '!') { optstr++; optlen--; not = TRUE; } if (strncmp(optstr, "no", 2) == 0) { optstr += 2; optlen -= 2; not = TRUE; } if (strncmp(optstr, optname, optlen) == 0) { ret = &optstr[optlen]; break; } optstr = np; } if (ret != NULL) { if (*ret == ',' || *ret == '\0') { if (not) return ("0"); return ("1"); } if (*ret == '=') { if (not) return (NULL); return (++ret); } } return (ret); } static cdr_t * identify_mmc(SCSI *usalp, cdr_t *dp, struct scsi_inquiry *ip) { BOOL cdrr = FALSE; /* Read CD-R */ BOOL cdwr = FALSE; /* Write CD-R */ BOOL cdrrw = FALSE; /* Read CD-RW */ BOOL cdwrw = FALSE; /* Write CD-RW */ BOOL dvdwr = FALSE; /* DVD writer */ BOOL is_dvd = FALSE; /* use DVD driver*/ Uchar mode[0x100]; struct cd_mode_page_2A *mp; int profile; if (ip->type != INQ_WORM && ip->type != INQ_ROMD) return ((cdr_t *)0); allow_atapi(usalp, TRUE); /* Try to switch to 10 byte mode cmds */ usalp->silent++; mp = mmc_cap(usalp, mode); /* Get MMC capabilities */ usalp->silent--; if (mp == NULL) return (&cdr_oldcd); /* Pre SCSI-3/mmc drive */ /* * At this point we know that we have a SCSI-3/mmc compliant drive. * Unfortunately ATAPI drives violate the SCSI spec in returning * a response data format of '1' which from the SCSI spec would * tell us not to use the "PF" bit in mode select. As ATAPI drives * require the "PF" bit to be set, we 'correct' the inquiry data. * * XXX xxx_identify() should not have any side_effects ?? */ if (ip->data_format < 2) ip->data_format = 2; /* * First handle exceptions.... */ if (strncmp(ip->vendor_info, "SONY", 4) == 0 && strncmp(ip->prod_ident, "CD-R CDU928E", 14) == 0) { return (&cdr_mmc_sony); } /* * Now try to do it the MMC-3 way.... */ profile = get_curprofile(usalp); if (xdebug) printf("Current profile: 0x%04X\n", profile); if (profile == 0) { if (xdebug) print_profiles(usalp); /* * If the current profile is 0x0000, then the * drive does not know about the media. First * close the tray and then try to issue the * get_curprofile() command again. */ usalp->silent++; load_media(usalp, dp, FALSE); usalp->silent--; profile = get_curprofile(usalp); scsi_prevent_removal(usalp, 0); if (xdebug) printf("Current profile: 0x%04X\n", profile); } if (profile >= 0) { if (lverbose) print_profiles(usalp); if (profile == 0 || (profile >= 0x10 && profile <= 0x15) || profile > 0x19) { /* * 10h DVD-ROM * 11h DVD-R * 12h DVD-RAM * 13h DVD-RW (Restricted overwrite) * 14h DVD-RW (Sequential recording) * 1Ah DVD+RW * 1Bh DVD+R * 2Bh DVD+R DL * */ if (profile == 0x11 || profile == 0x13 || profile == 0x14 || profile == 0x1A || profile == 0x1B || profile == 0x2B) { is_dvd = TRUE; dp = &cdr_mdvd; } else { is_dvd = FALSE; dp = &cdr_cd; if (profile == 0) { /* No Medium */ BOOL is_cdr = FALSE; /* * Check for CD-writer */ get_wproflist(usalp, &is_cdr, NULL, NULL, NULL); if (is_cdr) return (&cdr_mmc); /* * Other MMC-3 drive without media */ return (dp); } if (profile == 0x12) { /* DVD-RAM */ errmsgno(EX_BAD, "Found unsupported DVD-RAM media.\n"); return (dp); } } } } else { if (xdebug) printf("Drive is pre MMC-3\n"); } mmc_getval(mp, &cdrr, &cdwr, &cdrrw, &cdwrw, NULL, &dvdwr); if (!cdwr && !cdwrw) { /* SCSI-3/mmc CD drive */ /* * If the drive does not support to write CD's, we select the * CD-ROM driver here. If we have DVD-R/DVD-RW support compiled * in, we may later decide to switch to the DVD driver. */ dp = &cdr_cd; } else { /* * We need to set the driver to cdr_mmc because we may come * here with driver set to cdr_cd_dvd which is not a driver * that may be used for actual CD/DVD writing. */ dp = &cdr_mmc; } /*#define DVD_DEBUG*/ #ifdef DVD_DEBUG if (1) { /* Always check for DVD media in debug mode */ #else if ((cdwr || cdwrw) && dvdwr) { #endif char xb[32]; #ifndef DVD_DEBUG usalp->silent++; #else fprintf(stderr, "identify_dvd: checking for DVD media\n"); #endif if (read_dvd_structure(usalp, (caddr_t)xb, 32, 0, 0, 0) >= 0) { /* * If read DVD structure is supported and works, then * we must have a DVD media in the drive. Signal to * use the DVD driver. */ is_dvd = TRUE; } else { if (usal_sense_key(usalp) == SC_NOT_READY) { /* * If the SCSI sense key is NOT READY, then the * drive does not know about the media. First * close the tray and then try to issue the * read_dvd_structure() command again. */ load_media(usalp, dp, FALSE); if (read_dvd_structure(usalp, (caddr_t)xb, 32, 0, 0, 0) >= 0) { is_dvd = TRUE; } scsi_prevent_removal(usalp, 0); } } #ifndef DVD_DEBUG usalp->silent--; #else fprintf(stderr, "identify_dvd: is_dvd: %d\n", is_dvd); #endif } if (is_dvd) { if(lverbose>2) fprintf(stderr, "Found DVD media: using cdr_mdvd.\n"); dp = &cdr_mdvd; } dp->profile = profile; dp->is_dvd = is_dvd; return (dp); } static int attach_mmc(SCSI *usalp, cdr_t *dp) { int ret; Uchar mode[0x100]; struct cd_mode_page_2A *mp; struct ricoh_mode_page_30 *rp = NULL; allow_atapi(usalp, TRUE); /* Try to switch to 10 byte mode cmds */ usalp->silent++; mp = mmc_cap(usalp, NULL); /* Get MMC capabilities in allocated mp */ usalp->silent--; if (mp == NULL) return (-1); /* Pre SCSI-3/mmc drive */ dp->cdr_cdcap = mp; /* Store MMC cap pointer */ dp->cdr_dstat->ds_dr_max_rspeed = a_to_u_2_byte(mp->max_read_speed)/176; if (dp->cdr_dstat->ds_dr_max_rspeed == 0) dp->cdr_dstat->ds_dr_max_rspeed = 372; dp->cdr_dstat->ds_dr_cur_rspeed = a_to_u_2_byte(mp->cur_read_speed)/176; if (dp->cdr_dstat->ds_dr_cur_rspeed == 0) dp->cdr_dstat->ds_dr_cur_rspeed = 372; dp->cdr_dstat->ds_dr_max_wspeed = a_to_u_2_byte(mp->max_write_speed)/176; if (mp->p_len >= 28) dp->cdr_dstat->ds_dr_cur_wspeed = a_to_u_2_byte(mp->v3_cur_write_speed)/176; else dp->cdr_dstat->ds_dr_cur_wspeed = a_to_u_2_byte(mp->cur_write_speed)/176; if (dp->cdr_speedmax > dp->cdr_dstat->ds_dr_max_wspeed) dp->cdr_speedmax = dp->cdr_dstat->ds_dr_max_wspeed; if (dp->cdr_speeddef > dp->cdr_speedmax) dp->cdr_speeddef = dp->cdr_speedmax; rp = get_justlink_ricoh(usalp, mode); if (mp->p_len >= 28) dp->cdr_flags |= CDR_MMC3; if (mp->p_len >= 24) dp->cdr_flags |= CDR_MMC2; dp->cdr_flags |= CDR_MMC; if (mp->loading_type == LT_TRAY) dp->cdr_flags |= CDR_TRAYLOAD; else if (mp->loading_type == LT_CADDY) dp->cdr_flags |= CDR_CADDYLOAD; if (mp->BUF != 0) { dp->cdr_flags |= CDR_BURNFREE; } else if (rp) { if ((dp->cdr_cmdflags & F_DUMMY) && rp->TWBFS && rp->BUEFS) dp->cdr_flags |= CDR_BURNFREE; if (rp->BUEFS) dp->cdr_flags |= CDR_BURNFREE; } if (mmc_isplextor(usalp)) { if (check_varirec_plextor(usalp) >= 0) dp->cdr_flags |= CDR_VARIREC; if (check_gigarec_plextor(usalp) >= 0) dp->cdr_flags |= CDR_GIGAREC; if (check_ss_hide_plextor(usalp) >= 0) dp->cdr_flags |= CDR_SINGLESESS|CDR_HIDE_CDR; if (check_powerrec_plextor(usalp) >= 0) dp->cdr_flags |= CDR_FORCESPEED; if (check_speed_rd_plextor(usalp) >= 0) dp->cdr_flags |= CDR_SPEEDREAD; } if (mmc_isyamaha(usalp)) { if (set_audiomaster_yamaha(usalp, dp, FALSE) >= 0) dp->cdr_flags |= CDR_AUDIOMASTER; /* * Starting with CRW 2200 / CRW 3200 */ if ((mp->p_len+2) >= (unsigned)28) dp->cdr_flags |= CDR_FORCESPEED; if (get_tattoo_yamaha(usalp, FALSE, 0, 0)) dp->cdr_flags |= CDR_DISKTATTOO; } if (rp && rp->AWSCS) dp->cdr_flags |= CDR_FORCESPEED; #ifdef FUTURE_ROTCTL if (mp->p_len >= 28) { int val; val = dp->cdr_dstat->ds_dr_cur_wspeed; if (val == 0) val = 372; usalp->verbose++; if (scsi_set_speed(usalp, -1, val, ROTCTL_CAV) < 0) { fprintf(stderr, "XXX\n"); } usalp->verbose--; } #endif check_writemodes_mmc(usalp, dp); /* Enable Burnfree by default, it can be disabled later */ if ((dp->cdr_flags & CDR_BURNFREE) != 0) dp->cdr_dstat->ds_cdrflags |= RF_BURNFREE; if (driveropts != NULL) { char *p; if (strcmp(driveropts, "help") == 0) { mmc_opthelp(dp, 0); } p = hasdrvopt(driveropts, "varirec"); if (p != NULL && (dp->cdr_flags & CDR_VARIREC) != 0) { dp->cdr_dstat->ds_cdrflags |= RF_VARIREC; } p = hasdrvopt(driveropts, "gigarec"); if (p != NULL && (dp->cdr_flags & CDR_GIGAREC) != 0) { dp->cdr_dstat->ds_cdrflags |= RF_GIGAREC; } p = hasdrvopt(driveropts, "audiomaster"); if (p != NULL && *p == '1' && (dp->cdr_flags & CDR_AUDIOMASTER) != 0) { dp->cdr_dstat->ds_cdrflags |= RF_AUDIOMASTER; dp->cdr_dstat->ds_cdrflags &= ~RF_BURNFREE; } p = hasdrvopt(driveropts, "forcespeed"); if (p != NULL && *p == '1' && (dp->cdr_flags & CDR_FORCESPEED) != 0) { dp->cdr_dstat->ds_cdrflags |= RF_FORCESPEED; } p = hasdrvopt(driveropts, "tattooinfo"); if (p != NULL && *p == '1' && (dp->cdr_flags & CDR_DISKTATTOO) != 0) { get_tattoo_yamaha(usalp, TRUE, 0, 0); } p = hasdrvopt(driveropts, "tattoofile"); if (p != NULL && (dp->cdr_flags & CDR_DISKTATTOO) != 0) { FILE *f; if ((f = fileopen(p, "rb")) == NULL) comerr("Cannot open '%s'.\n", p); if (do_tattoo_yamaha(usalp, f) < 0) errmsgno(EX_BAD, "Cannot do DiskT@2.\n"); fclose(f); } p = hasdrvopt(driveropts, "singlesession"); if (p != NULL && (dp->cdr_flags & CDR_SINGLESESS) != 0) { if (*p == '1') { dp->cdr_dstat->ds_cdrflags |= RF_SINGLESESS; } else if (*p == '0') { dp->cdr_dstat->ds_cdrflags &= ~RF_SINGLESESS; } } p = hasdrvopt(driveropts, "hidecdr"); if (p != NULL && (dp->cdr_flags & CDR_HIDE_CDR) != 0) { if (*p == '1') { dp->cdr_dstat->ds_cdrflags |= RF_HIDE_CDR; } else if (*p == '0') { dp->cdr_dstat->ds_cdrflags &= ~RF_HIDE_CDR; } } p = hasdrvopt(driveropts, "speedread"); if (p != NULL && (dp->cdr_flags & CDR_SPEEDREAD) != 0) { if (*p == '1') { dp->cdr_dstat->ds_cdrflags |= RF_SPEEDREAD; } else if (*p == '0') { dp->cdr_dstat->ds_cdrflags &= ~RF_SPEEDREAD; } } } if ((ret = get_supported_cdrw_media_types(usalp)) < 0) { dp->cdr_cdrw_support = CDR_CDRW_ALL; return (0); } dp->cdr_cdrw_support = ret; if (lverbose > 1) printf("Supported CD-RW media types: %02X\n", dp->cdr_cdrw_support); return (0); } static int attach_mdvd(SCSI *usalp, cdr_t *dp) { struct cd_mode_page_2A *mp; allow_atapi(usalp, TRUE);/* Try to switch to 10 byte mode cmds */ usalp->silent++; mp = mmc_cap(usalp, NULL);/* Get MMC capabilities in allocated mp */ usalp->silent--; if (mp == NULL) return (-1); /* Pre SCSI-3/mmc drive */ dp->cdr_cdcap = mp; /* Store MMC cap pointer */ dp->cdr_dstat->ds_dr_max_rspeed = a_to_u_2_byte(mp->max_read_speed)/1385; if (dp->cdr_dstat->ds_dr_max_rspeed == 0) dp->cdr_dstat->ds_dr_max_rspeed = 1385; dp->cdr_dstat->ds_dr_cur_rspeed = a_to_u_2_byte(mp->cur_read_speed)/1385; if (dp->cdr_dstat->ds_dr_cur_rspeed == 0) dp->cdr_dstat->ds_dr_cur_rspeed = 1385; dp->cdr_dstat->ds_dr_max_wspeed = a_to_u_2_byte(mp->max_write_speed)/1385; if (mp->p_len >= 28) dp->cdr_dstat->ds_dr_cur_wspeed = a_to_u_2_byte(mp->v3_cur_write_speed)/1385; else dp->cdr_dstat->ds_dr_cur_wspeed = a_to_u_2_byte(mp->cur_write_speed)/1385; if (dp->cdr_speedmax > dp->cdr_dstat->ds_dr_max_wspeed) dp->cdr_speedmax = dp->cdr_dstat->ds_dr_max_wspeed; if (dp->cdr_speeddef > dp->cdr_speedmax) dp->cdr_speeddef = dp->cdr_speedmax; if (mp->loading_type == LT_TRAY) dp->cdr_flags |= CDR_TRAYLOAD; else if (mp->loading_type == LT_CADDY) dp->cdr_flags |= CDR_CADDYLOAD; if (mp->BUF != 0) dp->cdr_flags |= CDR_BURNFREE; check_writemodes_mdvd(usalp, dp); if (driveropts != NULL) { if (strcmp(driveropts, "help") == 0) { mmc_opthelp(dp, 0); } } return (0); } int check_writemodes_mmc(SCSI *usalp, cdr_t *dp) { Uchar mode[0x100]; int len; struct cd_mode_page_05 *mp; if (xdebug) printf("Checking possible write modes: "); /* * Reset mp->test_write (-dummy) here. */ deflt_writemodes_mmc(usalp, TRUE); fillbytes((caddr_t)mode, sizeof (mode), '\0'); usalp->silent++; if (!get_mode_params(usalp, 0x05, "CD write parameter", mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) { usalp->silent--; return (-1); } if (len == 0) { usalp->silent--; return (-1); } mp = (struct cd_mode_page_05 *) (mode + sizeof (struct scsi_mode_header) + ((struct scsi_mode_header *)mode)->blockdesc_len); #ifdef DEBUG usal_prbytes("CD write parameter:", (Uchar *)mode, len); #endif /* * mp->test_write has already been reset in deflt_writemodes_mmc() * Do not reset mp->test_write (-dummy) here. It should be set * only at one place and only one time. */ mp->write_type = WT_TAO; mp->track_mode = TM_DATA; mp->dbtype = DB_ROM_MODE1; if (set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) { dp->cdr_flags |= CDR_TAO; if (xdebug) printf("TAO "); } else dp->cdr_flags &= ~CDR_TAO; mp->write_type = WT_PACKET; mp->track_mode |= TM_INCREMENTAL; /* mp->fp = (trackp->pktsize > 0) ? 1 : 0;*/ /* i_to_4_byte(mp->packet_size, trackp->pktsize);*/ mp->fp = 0; i_to_4_byte(mp->packet_size, 0); if (set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) { dp->cdr_flags |= CDR_PACKET; if (xdebug) printf("PACKET "); } else dp->cdr_flags &= ~CDR_PACKET; mp->fp = 0; i_to_4_byte(mp->packet_size, 0); mp->track_mode = TM_DATA; mp->write_type = WT_SAO; if (set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) { dp->cdr_flags |= CDR_SAO; if (xdebug) printf("SAO "); } else dp->cdr_flags &= ~CDR_SAO; if (dp->cdr_flags & CDR_SAO) { mp->dbtype = DB_RAW_PQ; #ifdef __needed__ if (set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) { dp->cdr_flags |= CDR_SRAW16; if (xdebug) printf("SAO/R16 "); } #endif mp->dbtype = DB_RAW_PW; if (set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) { dp->cdr_flags |= CDR_SRAW96P; if (xdebug) printf("SAO/R96P "); } mp->dbtype = DB_RAW_PW_R; if (set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) { dp->cdr_flags |= CDR_SRAW96R; if (xdebug) printf("SAO/R96R "); } } mp->write_type = WT_RAW; mp->dbtype = DB_RAW_PQ; if (set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) { dp->cdr_flags |= CDR_RAW; dp->cdr_flags |= CDR_RAW16; if (xdebug) printf("RAW/R16 "); } mp->dbtype = DB_RAW_PW; if (set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) { dp->cdr_flags |= CDR_RAW; dp->cdr_flags |= CDR_RAW96P; if (xdebug) printf("RAW/R96P "); } mp->dbtype = DB_RAW_PW_R; if (set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) { dp->cdr_flags |= CDR_RAW; dp->cdr_flags |= CDR_RAW96R; if (xdebug) printf("RAW/R96R "); } if (xdebug) printf("\n"); /* * Reset mp->test_write (-dummy) here. */ deflt_writemodes_mmc(usalp, TRUE); usalp->silent--; return (0); } int check_writemodes_mdvd(SCSI *usalp, cdr_t *dp) { Uchar mode[0x100]; int len; struct cd_mode_page_05 *mp; if (xdebug) printf("Checking possible write modes: "); deflt_writemodes_mdvd(usalp, FALSE); fillbytes((caddr_t)mode, sizeof(mode), '\0'); usalp->silent++; if (!get_mode_params(usalp, 0x05, "DVD write parameter", mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) { usalp->silent--; return (-1); } if (len == 0) { usalp->silent--; return (-1); } mp = (struct cd_mode_page_05 *) (mode + sizeof(struct scsi_mode_header) + ((struct scsi_mode_header *)mode)->blockdesc_len); mp->test_write = 0; /*We only check for PACKET and SAO since these are the only supported modes for DVD */ /*XXX these checks are irrelevant because they are not medium sensitive. ie the device returns error only when it does not support a given mode for ALL mediums. It should check using GET CONFIGURATION command.*/ mp->write_type = WT_PACKET; mp->fp = 0; i_to_4_byte(mp->packet_size, 0); if (set_mode_params(usalp, "DVD write parameter", mode, len, 0, -1)) { dp->cdr_flags |= CDR_PACKET; if (xdebug) printf("PACKET "); } else dp->cdr_flags &= ~CDR_PACKET; mp->fp = 0; i_to_4_byte(mp->packet_size, 0); mp->track_mode = TM_DATA; mp->write_type = WT_SAO; if (set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) { dp->cdr_flags |= CDR_SAO; if (xdebug) printf("SAO "); } else dp->cdr_flags &= ~CDR_SAO; if (xdebug) printf("\n"); deflt_writemodes_mdvd(usalp, TRUE); usalp->silent--; return (0); } static int deflt_writemodes_mmc(SCSI *usalp, BOOL reset_dummy) { Uchar mode[0x100]; int len; struct cd_mode_page_05 *mp; fillbytes((caddr_t)mode, sizeof (mode), '\0'); usalp->silent++; if (!get_mode_params(usalp, 0x05, "CD write parameter", mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) { usalp->silent--; return (-1); } if (len == 0) { usalp->silent--; return (-1); } mp = (struct cd_mode_page_05 *) (mode + sizeof (struct scsi_mode_header) + ((struct scsi_mode_header *)mode)->blockdesc_len); #ifdef DEBUG usal_prbytes("CD write parameter:", (Uchar *)mode, len); fprintf(stderr, "Audio pause len: %d\n", a_to_2_byte(mp->audio_pause_len)); #endif /* * This is the only place where we reset mp->test_write (-dummy) */ if (reset_dummy) mp->test_write = 0; /* * Set default values: * Write type = 01 (track at once) * Track mode = 04 (CD-ROM) * Data block type = 08 (CD-ROM) * Session format = 00 (CD-ROM) * * XXX Note: the same code appears in check_writemodes_mmc() and * XXX in speed_select_mmc(). */ mp->write_type = WT_TAO; mp->track_mode = TM_DATA; mp->dbtype = DB_ROM_MODE1; mp->session_format = SES_DA_ROM; /* Matsushita has illegal def. value */ i_to_2_byte(mp->audio_pause_len, 150); /* LG has illegal def. value */ #ifdef DEBUG usal_prbytes("CD write parameter:", (Uchar *)mode, len); #endif if (!set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) { mp->write_type = WT_SAO; mp->LS_V = 0; mp->copy = 0; mp->fp = 0; mp->multi_session = MS_NONE; mp->host_appl_code = 0; if (!set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) { usalp->silent--; return (-1); } } usalp->silent--; return (0); } static int deflt_writemodes_mdvd(SCSI *usalp, BOOL reset_dummy) { Uchar mode[0x100]; int len; struct cd_mode_page_05 *mp; fillbytes((caddr_t)mode, sizeof(mode), '\0'); usalp->silent++; if (!get_mode_params(usalp, 0x05, "DVD write parameter", mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) { usalp->silent--; return (-1); } if (len == 0) { usalp->silent--; return (-1); } mp = (struct cd_mode_page_05 *) (mode + sizeof(struct scsi_mode_header) + ((struct scsi_mode_header *)mode)->blockdesc_len); mp->test_write = 0; /* * This is the only place where we reset mp->test_write (-dummy) for DVD */ if (reset_dummy) mp->test_write = 0; /* * Set default values: * Write type = 02 (session at once) * * XXX Note: the same code appears in check_writemodes_mmc() and * XXX in speed_select_mmc(). */ mp->write_type = WT_SAO; mp->track_mode = TM_DATA; mp->dbtype = DB_ROM_MODE1; mp->session_format = SES_DA_ROM; if (set_mode_params(usalp, "DVD write parameter", mode, len, 0, -1) < 0) { usalp->silent--; return (-1); } usalp->silent--; return (0); } #ifdef PRINT_ATIP static void print_di(struct disk_info *dip); static void atip_printspeed(char *fmt, int speedindex, char speedtab[]); static void print_atip(SCSI *usalp, struct atipinfo *atp); #endif /* PRINT_ATIP */ static int get_diskinfo(SCSI *usalp, struct disk_info *dip) { int len; int ret; fillbytes((caddr_t)dip, sizeof (*dip), '\0'); /* * Used to be 2 instead of 4 (now). But some Y2k ATAPI drives as used * by IOMEGA create a DMA overrun if we try to transfer only 2 bytes. */ /* if (read_disk_info(usalp, (caddr_t)dip, 2) < 0)*/ if (read_disk_info(usalp, (caddr_t)dip, 4) < 0) return (-1); len = a_to_u_2_byte(dip->data_len); len += 2; ret = read_disk_info(usalp, (caddr_t)dip, len); #ifdef DEBUG usal_prbytes("Disk info:", (Uchar *)dip, len-usal_getresid(usalp)); #endif return (ret); } static void di_to_dstat(struct disk_info *dip, dstat_t *dsp) { dsp->ds_diskid = a_to_u_4_byte(dip->disk_id); if (dip->did_v) dsp->ds_flags |= DSF_DID_V; dsp->ds_disktype = dip->disk_type; dsp->ds_diskstat = dip->disk_status; dsp->ds_sessstat = dip->sess_status; if (dip->erasable) dsp->ds_flags |= DSF_ERA; dsp->ds_trfirst = dip->first_track; dsp->ds_trlast = dip->last_track_ls; dsp->ds_trfirst_ls = dip->first_track_ls; dsp->ds_maxblocks = msf_to_lba(dip->last_lead_out[1], dip->last_lead_out[2], dip->last_lead_out[3], TRUE); /* * Check for 0xFF:0xFF/0xFF which is an indicator for a complete disk */ if (dsp->ds_maxblocks == 1166730) dsp->ds_maxblocks = -1L; dsp->ds_first_leadin = msf_to_lba(dip->last_lead_in[1], dip->last_lead_in[2], dip->last_lead_in[3], FALSE); if (dsp->ds_first_leadin > 0) dsp->ds_first_leadin = 0; if (dsp->ds_last_leadout == 0 && dsp->ds_maxblocks >= 0) dsp->ds_last_leadout = dsp->ds_maxblocks; dsp->ds_trfirst=dip->first_track; dsp->ds_trlast=dip->last_track_ls; dsp->ds_trfirst_ls=dip->first_track_ls; } static int get_atip(SCSI *usalp, struct atipinfo *atp) { int len; int ret; fillbytes((caddr_t)atp, sizeof (*atp), '\0'); /* * Used to be 2 instead of sizeof (struct tocheader), but all * other places in the code use sizeof (struct tocheader) too and * some Y2k ATAPI drives as used by IOMEGA create a DMA overrun if we * try to transfer only 2 bytes. */ if (read_toc(usalp, (caddr_t)atp, 0, sizeof (struct tocheader), 0, FMT_ATIP) < 0) return (-1); len = a_to_u_2_byte(atp->hd.len); len += 2; ret = read_toc(usalp, (caddr_t)atp, 0, len, 0, FMT_ATIP); #ifdef DEBUG usal_prbytes("ATIP info:", (Uchar *)atp, len-usal_getresid(usalp)); #endif /* * Yamaha sometimes returns zeroed ATIP info for disks without ATIP */ if (atp->desc.lead_in[1] == 0 && atp->desc.lead_in[2] == 0 && atp->desc.lead_in[3] == 0 && atp->desc.lead_out[1] == 0 && atp->desc.lead_out[2] == 0 && atp->desc.lead_out[3] == 0) return (-1); if (atp->desc.lead_in[1] >= 0x90 && debug) { /* * Only makes sense with buggy Ricoh firmware. */ errmsgno(EX_BAD, "Converting ATIP from BCD\n"); atp->desc.lead_in[1] = from_bcd(atp->desc.lead_in[1]); atp->desc.lead_in[2] = from_bcd(atp->desc.lead_in[2]); atp->desc.lead_in[3] = from_bcd(atp->desc.lead_in[3]); atp->desc.lead_out[1] = from_bcd(atp->desc.lead_out[1]); atp->desc.lead_out[2] = from_bcd(atp->desc.lead_out[2]); atp->desc.lead_out[3] = from_bcd(atp->desc.lead_out[3]); } return (ret); } #ifdef PRINT_ATIP static int get_pma(SCSI *usalp) { int len; int ret; char atp[1024]; fillbytes((caddr_t)atp, sizeof (*atp), '\0'); /* * Used to be 2 instead of sizeof (struct tocheader), but all * other places in the code use sizeof (struct tocheader) too and * some Y2k ATAPI drives as used by IOMEGA create a DMA overrun if we * try to transfer only 2 bytes. */ /* if (read_toc(usalp, (caddr_t)atp, 0, 2, 1, FMT_PMA) < 0)*/ /* if (read_toc(usalp, (caddr_t)atp, 0, 2, 0, FMT_PMA) < 0)*/ if (read_toc(usalp, (caddr_t)atp, 0, sizeof (struct tocheader), 0, FMT_PMA) < 0) return (-1); /* len = a_to_u_2_byte(atp->hd.len);*/ len = a_to_u_2_byte(atp); len += 2; /* ret = read_toc(usalp, (caddr_t)atp, 0, len, 1, FMT_PMA);*/ ret = read_toc(usalp, (caddr_t)atp, 0, len, 0, FMT_PMA); #ifdef DEBUG usal_prbytes("PMA:", (Uchar *)atp, len-usal_getresid(usalp)); #endif ret = read_toc(usalp, (caddr_t)atp, 0, len, 1, FMT_PMA); #ifdef DEBUG usal_prbytes("PMA:", (Uchar *)atp, len-usal_getresid(usalp)); #endif return (ret); } #endif /* PRINT_ATIP */ static int init_mmc(SCSI *usalp, cdr_t *dp) { return (speed_select_mmc(usalp, dp, NULL)); } static int getdisktype_mdvd(SCSI *usalp, cdr_t *dp) { int ret = 0; dstat_t *dsp = dp->cdr_dstat; struct track_info track_info; if(lverbose) printf("HINT: use dvd+rw-mediainfo from dvd+rw-tools for information extraction.\n"); /* if(getdisktype_mmc(usalp, dp)<0) return -1; */ /* read rzone info to get the space left on disk */ /*ds_trlast is the last rzone on disk, can be invisible */ if(read_rzone_info(usalp, (caddr_t)&track_info, sizeof(track_info))>=0) dsp->ds_maxblocks=a_to_u_4_byte(track_info.free_blocks)+a_to_4_byte(track_info.next_writable_addr); dsp->ds_disktype&= ~DT_CD; dsp->ds_disktype|= DT_DVD; return (ret); } static int getdisktype_mmc(SCSI *usalp, cdr_t *dp) { extern char *buf; dstat_t *dsp = dp->cdr_dstat; struct disk_info *dip; Uchar mode[0x100]; msf_t msf; BOOL did_atip = FALSE; BOOL did_dummy = FALSE; int rplus; msf.msf_min = msf.msf_sec = msf.msf_frame = 0; /* * It seems that there are drives that do not support to * read ATIP (e.g. HP 7100) * Also if a NON CD-R media is inserted, this will never work. * For this reason, make a failure non-fatal. */ usalp->silent++; if (get_atip(usalp, (struct atipinfo *)mode) >= 0) { struct atipinfo *atp = (struct atipinfo *)mode; msf.msf_min = mode[8]; msf.msf_sec = mode[9]; msf.msf_frame = mode[10]; if (atp->desc.erasable) { dsp->ds_flags |= DSF_ERA; if (atp->desc.sub_type == 1) dsp->ds_flags |= DSF_HIGHSP_ERA; else if (atp->desc.sub_type == 2) dsp->ds_flags |= DSF_ULTRASP_ERA; else if (atp->desc.sub_type == 3) dsp->ds_flags |= DSF_ULTRASP_ERA | DSF_ULTRASPP_ERA; } if (atp->desc.a1_v) { if (atp->desc.clv_low != 0) dsp->ds_at_min_speed = clv_to_speed[atp->desc.clv_low]; if (atp->desc.clv_high != 0) dsp->ds_at_max_speed = clv_to_speed[atp->desc.clv_high]; if (atp->desc.erasable && atp->desc.sub_type == 1) { if (atp->desc.clv_high != 0) dsp->ds_at_max_speed = hs_clv_to_speed[atp->desc.clv_high]; } } if (atp->desc.a2_v && atp->desc.erasable && (atp->desc.sub_type == 2 || atp->desc.sub_type == 3)) { Uint vlow; Uint vhigh; vlow = (atp->desc.a2[0] >> 4) & 0x07; vhigh = atp->desc.a2[0] & 0x0F; if (vlow != 0) dsp->ds_at_min_speed = us_clv_to_speed[vlow]; if (vhigh != 0) dsp->ds_at_max_speed = us_clv_to_speed[vhigh]; } did_atip = TRUE; } usalp->silent--; #ifdef PRINT_ATIP if ((dp->cdr_dstat->ds_cdrflags & RF_PRATIP) != 0 && did_atip) { print_atip(usalp, (struct atipinfo *)mode); pr_manufacturer(&msf, ((struct atipinfo *)mode)->desc.erasable, ((struct atipinfo *)mode)->desc.uru); } #endif again: dip = (struct disk_info *)buf; if (get_diskinfo(usalp, dip) < 0) return (-1); /* * Check for non writable disk first. */ /* DVD+RW does not need to be blanked */ rplus = dsp->ds_cdrflags; if (dp->profile == 0x1A) rplus = RF_BLANK; if (dip->disk_status == DS_COMPLETE && (rplus & dsp->ds_cdrflags & (RF_WRITE|RF_BLANK)) == RF_WRITE) { if (!did_dummy) { int xspeed = 0xFFFF; int oflags = dp->cdr_cmdflags; /* * 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"); dp->cdr_cmdflags &= ~F_DUMMY; speed_select_mmc(usalp, dp, &xspeed); dp->cdr_cmdflags = oflags; did_dummy = TRUE; goto again; } /* * Trying to clear drive status did not work... */ reload_media(usalp, dp); } if (get_diskinfo(usalp, dip) < 0) return (-1); di_to_dstat(dip, dsp); if (!did_atip && dsp->ds_first_leadin < 0) lba_to_msf(dsp->ds_first_leadin, &msf); if ((dp->cdr_dstat->ds_cdrflags & RF_PRATIP) != 0 && !did_atip) { print_min_atip(dsp->ds_first_leadin, dsp->ds_last_leadout); if (dsp->ds_first_leadin < 0) pr_manufacturer(&msf, dip->erasable, dip->uru); } dsp->ds_maxrblocks = disk_rcap(&msf, dsp->ds_maxblocks, dip->erasable, dip->uru); #ifdef PRINT_ATIP #ifdef DEBUG if (get_atip(usalp, (struct atipinfo *)mode) < 0) return (-1); /* * Get pma gibt Ärger mit CW-7502 * Wenn Die Disk leer ist, dann stuerzt alles ab. * Firmware 4.02 kann nicht get_pma */ if (dip->disk_status != DS_EMPTY) { /* get_pma();*/ } printf("ATIP lead in: %ld (%02d:%02d/%02d)\n", msf_to_lba(mode[8], mode[9], mode[10], FALSE), mode[8], mode[9], mode[10]); printf("ATIP lead out: %ld (%02d:%02d/%02d)\n", msf_to_lba(mode[12], mode[13], mode[14], TRUE), mode[12], mode[13], mode[14]); print_di(dip); print_atip(usalp, (struct atipinfo *)mode); #endif #endif /* PRINT_ATIP */ return (drive_getdisktype(usalp, dp)); } #ifdef PRINT_ATIP #define DOES(what, flag) printf(" Does %s%s\n", flag?"":"not ", what); #define IS(what, flag) printf(" Is %s%s\n", flag?"":"not ", what); #define VAL(what, val) printf(" %s: %d\n", what, val[0]*256 + val[1]); #define SVAL(what, val) printf(" %s: %s\n", what, val); static void print_di(struct disk_info *dip) { static char *ds_name[] = { "empty", "incomplete/appendable", "complete", "illegal" }; static char *ss_name[] = { "empty", "incomplete/appendable", "illegal", "complete", }; IS("erasable", dip->erasable); printf("disk status: %s\n", ds_name[dip->disk_status]); printf("session status: %s\n", ss_name[dip->sess_status]); printf("first track: %d number of sessions: %d first track in last sess: %d last track in last sess: %d\n", dip->first_track, dip->numsess, dip->first_track_ls, dip->last_track_ls); IS("unrestricted", dip->uru); printf("Disk type: "); switch (dip->disk_type) { case SES_DA_ROM: printf("CD-DA or CD-ROM"); break; case SES_CDI: printf("CDI"); break; case SES_XA: printf("CD-ROM XA"); break; case SES_UNDEF: printf("undefined"); break; default: printf("reserved"); break; } printf("\n"); if (dip->did_v) printf("Disk id: 0x%lX\n", a_to_u_4_byte(dip->disk_id)); printf("last start of lead in: %ld\n", msf_to_lba(dip->last_lead_in[1], dip->last_lead_in[2], dip->last_lead_in[3], FALSE)); printf("last start of lead out: %ld\n", msf_to_lba(dip->last_lead_out[1], dip->last_lead_out[2], dip->last_lead_out[3], TRUE)); if (dip->dbc_v) printf("Disk bar code: 0x%lX%lX\n", a_to_u_4_byte(dip->disk_barcode), a_to_u_4_byte(&dip->disk_barcode[4])); if (dip->num_opc_entries > 0) { printf("OPC table:\n"); } } char *cdr_subtypes[] = { "Normal Rewritable (CLV) media", "High speed Rewritable (CAV) media", "Medium Type A, low Beta category (A-)", "Medium Type A, high Beta category (A+)", "Medium Type B, low Beta category (B-)", "Medium Type B, high Beta category (B+)", "Medium Type C, low Beta category (C-)", "Medium Type C, high Beta category (C+)", }; char *cdrw_subtypes[] = { "Normal Rewritable (CLV) media", "High speed Rewritable (CAV) media", "Ultra High speed Rewritable media", "Ultra High speed+ Rewritable media", "Medium Type B, low Beta category (B-)", "Medium Type B, high Beta category (B+)", "Medium Type C, low Beta category (C-)", "Medium Type C, high Beta category (C+)", }; static void atip_printspeed(char *fmt, int speedindex, char speedtab[]) { printf("%s:", fmt); if (speedtab[speedindex] == 0) { printf(" %2d (reserved val %2d)", speedtab[speedindex], speedindex); } else { printf(" %2d", speedtab[speedindex]); } } static void print_atip(SCSI *usalp, struct atipinfo *atp) { char *sub_type; char *speedvtab = clv_to_speed; if (usalp->verbose) usal_prbytes("ATIP info: ", (Uchar *)atp, sizeof (*atp)); printf("ATIP info from disk:\n"); printf(" Indicated writing power: %d\n", atp->desc.ind_wr_power); if (atp->desc.erasable || atp->desc.ref_speed) printf(" Reference speed: %d\n", clv_to_speed[atp->desc.ref_speed]); IS("unrestricted", atp->desc.uru); /* printf(" Disk application code: %d\n", atp->desc.res5_05);*/ IS("erasable", atp->desc.erasable); if (atp->desc.erasable) sub_type = cdrw_subtypes[atp->desc.sub_type]; else sub_type = cdr_subtypes[atp->desc.sub_type]; if (atp->desc.sub_type) printf(" Disk sub type: %s (%d)\n", sub_type, atp->desc.sub_type); printf(" ATIP start of lead in: %ld (%02d:%02d/%02d)\n", msf_to_lba(atp->desc.lead_in[1], atp->desc.lead_in[2], atp->desc.lead_in[3], FALSE), atp->desc.lead_in[1], atp->desc.lead_in[2], atp->desc.lead_in[3]); printf(" ATIP start of lead out: %ld (%02d:%02d/%02d)\n", msf_to_lba(atp->desc.lead_out[1], atp->desc.lead_out[2], atp->desc.lead_out[3], TRUE), atp->desc.lead_out[1], atp->desc.lead_out[2], atp->desc.lead_out[3]); if (atp->desc.a1_v) { if (atp->desc.erasable && atp->desc.sub_type == 1) { speedvtab = hs_clv_to_speed; } if (atp->desc.a2_v && (atp->desc.sub_type == 2 || atp->desc.sub_type == 3)) { speedvtab = us_clv_to_speed; } if (atp->desc.clv_low != 0 || atp->desc.clv_high != 0) { atip_printspeed(" 1T speed low", atp->desc.clv_low, speedvtab); atip_printspeed(" 1T speed high", atp->desc.clv_high, speedvtab); printf("\n"); } } if (atp->desc.a2_v) { Uint vlow; Uint vhigh; vlow = (atp->desc.a2[0] >> 4) & 0x07; vhigh = atp->desc.a2[0] & 0x0F; if (vlow != 0 || vhigh != 0) { atip_printspeed(" 2T speed low", vlow, speedvtab); atip_printspeed(" 2T speed high", vhigh, speedvtab); printf("\n"); } } if (atp->desc.a1_v) { printf(" power mult factor: %d %d\n", atp->desc.power_mult, atp->desc.tgt_y_pow); if (atp->desc.erasable) printf(" recommended erase/write power: %d\n", atp->desc.rerase_pwr_ratio); } if (atp->desc.a1_v) { printf(" A1 values: %02X %02X %02X\n", (&atp->desc.res15)[1], (&atp->desc.res15)[2], (&atp->desc.res15)[3]); } if (atp->desc.a2_v) { printf(" A2 values: %02X %02X %02X\n", atp->desc.a2[0], atp->desc.a2[1], atp->desc.a2[2]); } if (atp->desc.a3_v) { printf(" A3 values: %02X %02X %02X\n", atp->desc.a3[0], atp->desc.a3[1], atp->desc.a3[2]); } } #endif /* PRINT_ATIP */ static int speed_select_mmc(SCSI *usalp, cdr_t *dp, int *speedp) { Uchar mode[0x100]; Uchar moder[0x100]; int len; struct cd_mode_page_05 *mp; struct ricoh_mode_page_30 *rp = NULL; int val; BOOL forcespeed = FALSE; BOOL dummy = (dp->cdr_cmdflags & F_DUMMY) != 0; if (speedp) curspeed = *speedp; /* * Do not reset mp->test_write (-dummy) here. */ deflt_writemodes_mmc(usalp, FALSE); fillbytes((caddr_t)mode, sizeof (mode), '\0'); if (!get_mode_params(usalp, 0x05, "CD write parameter", mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) return (-1); if (len == 0) return (-1); mp = (struct cd_mode_page_05 *) (mode + sizeof (struct scsi_mode_header) + ((struct scsi_mode_header *)mode)->blockdesc_len); #ifdef DEBUG usal_prbytes("CD write parameter:", (Uchar *)mode, len); #endif if(dummy) { mp->test_write = 1; /* but it does not work on DVD+RW and -RAM, also bail out on other * types that have not been tested yet */ int profile=get_curprofile(usalp); switch(profile) { case(0x12): case(0x1a): case(0x2a): case(0x43): case(0x52): { fprintf(stderr, "Dummy mode not possible with %s.\n", mmc_obtain_profile_name(profile) ); exit(EXIT_FAILURE); } } } else mp->test_write = 0; #ifdef DEBUG usal_prbytes("CD write parameter:", (Uchar *)mode, len); #endif if (!set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) return (-1); /* * Neither set nor get speed. */ if (speedp == 0) return (0); rp = get_justlink_ricoh(usalp, moder); if (mmc_isyamaha(usalp)) { forcespeed = FALSE; } else if (mmc_isplextor(usalp) && (dp->cdr_flags & CDR_FORCESPEED) != 0) { int pwr; pwr = check_powerrec_plextor(usalp); if (pwr >= 0) forcespeed = (pwr == 0); } else if ((dp->cdr_flags & CDR_FORCESPEED) != 0) { forcespeed = rp && rp->AWSCD != 0; } if (lverbose && (dp->cdr_flags & CDR_FORCESPEED) != 0) printf("Forcespeed is %s.\n", forcespeed?"ON":"OFF"); if (!forcespeed && (dp->cdr_dstat->ds_cdrflags & RF_FORCESPEED) != 0) { printf("Turning forcespeed on\n"); forcespeed = TRUE; } if (forcespeed && (dp->cdr_dstat->ds_cdrflags & RF_FORCESPEED) == 0) { printf("Turning forcespeed off\n"); forcespeed = FALSE; } if (mmc_isplextor(usalp) && (dp->cdr_flags & CDR_FORCESPEED) != 0) { powerrec_plextor(usalp, !forcespeed); } if (!mmc_isyamaha(usalp) && (dp->cdr_flags & CDR_FORCESPEED) != 0) { if (rp) { rp->AWSCD = forcespeed?1:0; set_mode_params(usalp, "Ricoh Vendor Page", moder, moder[0]+1, 0, -1); rp = get_justlink_ricoh(usalp, moder); } } /* * 44100 * 2 * 2 = 176400 bytes/s * * The right formula would be: * tmp = (((long)curspeed) * 1764) / 10; * * But the standard is rounding the wrong way. * Furtunately rounding down is guaranteed. */ val = curspeed*177; if (val > 0xFFFF) val = 0xFFFF; if (mmc_isyamaha(usalp) && forcespeed) { if (force_speed_yamaha(usalp, -1, val) < 0) return (-1); } else if (mmc_set_speed(usalp, -1, val, ROTCTL_CLV) < 0) { return (-1); } if (scsi_get_speed(usalp, 0, &val) >= 0) { if (val > 0) { fprintf(stderr, "Speed set to %d KB/s\n", val); curspeed = val / 176; *speedp = curspeed; } } return (0); } /* * Some drives do not round up when writespeed is e.g. 1 and * the minimum write speed of the drive is higher. Try to increment * the write speed unti it gets accepted by the drive. */ static int mmc_set_speed(SCSI *usalp, int readspeed, int writespeed, int rotctl) { int rs; int ws; int ret = -1; int c; int k; if (scsi_get_speed(usalp, &rs, &ws) >= 0) { if (readspeed < 0) readspeed = rs; if (writespeed < 0) writespeed = ws; } if (writespeed < 0 || writespeed > 0xFFFF) return (ret); usalp->silent++; while (writespeed <= 0xFFFF) { ret = scsi_set_speed(usalp, readspeed, writespeed, rotctl); if (ret >= 0) break; c = usal_sense_code(usalp); k = usal_sense_key(usalp); /* * Abort quickly if it does not make sense to repeat. * 0x24 == Invalid field in cdb * 0x24 means illegal speed. */ if ((k != SC_ILLEGAL_REQUEST) || (c != 0x24)) { if (usalp->silent <= 1) usal_printerr(usalp); usalp->silent--; return (-1); } writespeed += 177; } if (ret < 0 && usalp->silent <= 1) usal_printerr(usalp); usalp->silent--; return (ret); } static int speed_select_mdvd(SCSI *usalp, cdr_t *dp, int *speedp) { int retcode; char perf_desc[28]; int write_speed = *speedp * 1385; /* For the moment we just divide the CD speed by 7*/ if(speedp!=NULL) (*speedp)=(*speedp)*8; memset(perf_desc, 0, sizeof(perf_desc)); /* Write Rotation Control = ROTCTL_CLV * | Restore Logical Unit Defaults = 0 * | Exact = 0 * | Random Access = 0) */ perf_desc[0]= ROTCTL_CLV << 3 | 0 << 2 | 0 << 1 | 0; /* Start LBA to 0 */ perf_desc[4] = 0; perf_desc[5] = 0; perf_desc[6] = 0; perf_desc[7] = 0; /* End LBA set to 0 (setting to 0xffffffff failed on my LG burner */ perf_desc[8] = 0; perf_desc[9] = 0; perf_desc[10] = 0; perf_desc[11] = 0; /* Read Speed = 0xFFFF */ perf_desc[12] = 0; perf_desc[13] = 0; perf_desc[14] = 0xFF; perf_desc[15] = 0xFF; /* Read Time = 1s */ perf_desc[18] = 1000 >> 8; perf_desc[19] = 1000 & 0xFF; /* Write Speed */ perf_desc[20] = write_speed >> 24; perf_desc[21] = write_speed >> 16 & 0xFF; perf_desc[22] = write_speed >> 8 & 0xFF; perf_desc[23] = write_speed & 0xFF; /* Write Time = 1s */ perf_desc[26] = 1000 >> 8; perf_desc[27] = 1000 & 0xFF; /* retcode = scsi_set_streaming(usalp, NULL, 0); */ retcode = scsi_set_streaming(usalp, perf_desc, sizeof(perf_desc)); if (retcode == -1) return retcode; retcode = speed_select_mmc(usalp, dp, speedp); if(speedp!=NULL) (*speedp)=(*speedp)/7; return retcode; } static int next_wr_addr_mmc(SCSI *usalp, track_t *trackp, long *ap) { struct track_info track_info; 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 0xFF (if the track hasn't been started yet and is invisible */ if (trackp != 0 && trackp->track > 0 && is_packet(trackp)) { usalp->silent++; result = read_track_info(usalp, (caddr_t)&track_info, TI_TYPE_TRACK, trackp->trackno, sizeof (track_info)); usalp->silent--; } if (result < 0) { if (read_track_info(usalp, (caddr_t)&track_info, TI_TYPE_TRACK, 0xFF, sizeof (track_info)) < 0) { errmsgno(EX_BAD, "Cannot get next writable address for 'invisible' track.\n"); errmsgno(EX_BAD, "This means that we are checking recorded media.\n"); errmsgno(EX_BAD, "This media cannot be written in streaming mode anymore.\n"); errmsgno(EX_BAD, "If you like to write to 'preformatted' RW media, try to blank the media first.\n"); return (-1); } } if (usalp->verbose) usal_prbytes("track info:", (Uchar *)&track_info, sizeof (track_info)-usal_getresid(usalp)); next_addr = a_to_4_byte(track_info.next_writable_addr); if (ap) *ap = next_addr; return (0); } static int write_leadin_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp) { Uint i; long startsec = 0L; /* if (flags & F_SAO) {*/ 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); } (*dp->cdr_next_wr_address)(usalp, &trackp[0], &startsec); if (trackp[0].flags & TI_TEXT) { startsec = dp->cdr_dstat->ds_first_leadin; printf("SAO startsec: %ld\n", startsec); } else if (startsec <= 0 && startsec != -150) { if(lverbose>2) fprintf(stderr, "WARNING: Drive returns wrong startsec (%ld) using -150\n", startsec); startsec = -150; } if (debug) printf("SAO startsec: %ld\n", startsec); if (trackp[0].flags & TI_TEXT) { if (startsec > 0) { errmsgno(EX_BAD, "CD-Text must be in first session.\n"); return (-1); } if (debug || lverbose) printf("Writing lead-in...\n"); if (write_cdtext(usalp, dp, startsec) < 0) return (-1); dp->cdr_dstat->ds_cdrflags |= RF_LEADIN; } else for (i = 1; i <= trackp->tracks; i++) { trackp[i].trackstart += startsec +150; } #ifdef XXX if (debug || lverbose) printf("Writing lead-in...\n"); pad_track(usalp, dp, &trackp[1], -150, (Llong)0, FALSE, 0); #endif } /* if (flags & F_RAW) {*/ if (wm_base(dp->cdr_dstat->ds_wrmode) == WM_RAW) { /* * In RAW write mode, we now write the lead in (TOC). */ (*dp->cdr_next_wr_address)(usalp, &trackp[0], &startsec); if (startsec > -4500) { /* * There must be at least 1 minute lead-in. */ errmsgno(EX_BAD, "WARNING: Drive returns wrong startsec (%ld) using %ld from ATIP\n", startsec, (long)dp->cdr_dstat->ds_first_leadin); startsec = dp->cdr_dstat->ds_first_leadin; } if (startsec > -4500) { errmsgno(EX_BAD, "Illegal startsec (%ld)\n", startsec); return (-1); } if (debug || lverbose) printf("Writing lead-in at sector %ld\n", startsec); if (write_leadin(usalp, dp, trackp, startsec) < 0) return (-1); dp->cdr_dstat->ds_cdrflags |= RF_LEADIN; } return (0); } int st2mode[] = { 0, /* 0 */ TM_DATA, /* 1 ST_ROM_MODE1 */ TM_DATA, /* 2 ST_ROM_MODE2 */ 0, /* 3 */ 0, /* 4 ST_AUDIO_NOPRE */ TM_PREEM, /* 5 ST_AUDIO_PRE */ 0, /* 6 */ 0, /* 7 */ }; static int next_wr_addr_mdvd(SCSI *usalp, track_t *trackp, long *ap) { int track=0; struct track_info track_info; long next_addr; int result = -1; struct disk_info disk_info; if (trackp){ track = trackp->trackno; } if (trackp != 0 && track > 0 && is_packet(trackp)) { usalp->silent++; result = read_track_info(usalp, (caddr_t)&track_info, TI_TYPE_SESS, track, sizeof(track_info)); usalp->silent--; if (scsi_in_progress(usalp)){ return -1; } } if (result < 0) { /* Get the last rzone*/ if(read_disk_info(usalp,(caddr_t)&disk_info,8)<0) return (-1); /* if (read_track_info(usalp, (caddr_t)&track_info, TI_TYPE_SESS, 0xFF, sizeof(track_info)) < 0) */ if (read_rzone_info(usalp, (caddr_t)&track_info, sizeof(track_info)) < 0) return (-1); } if (usalp->verbose) usal_prbytes("track info:", (Uchar *)&track_info, sizeof(track_info)-usal_getresid(usalp)); next_addr = a_to_4_byte(track_info.next_writable_addr); if (ap) *ap = next_addr; return (0); } static int open_track_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp) { Uchar mode[0x100]; int len; struct cd_mode_page_05 *mp; 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); } fillbytes((caddr_t)mode, sizeof (mode), '\0'); if (!get_mode_params(usalp, 0x05, "CD write parameter", mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) return (-1); if (len == 0) return (-1); mp = (struct cd_mode_page_05 *) (mode + sizeof (struct scsi_mode_header) + ((struct scsi_mode_header *)mode)->blockdesc_len); /* mp->track_mode = ???;*/ mp->track_mode = st2mode[trackp->sectype & ST_MASK]; /* mp->copy = ???;*/ mp->dbtype = trackp->dbtype; /*i_to_short(mp->audio_pause_len, 300);*/ /*i_to_short(mp->audio_pause_len, 150);*/ /*i_to_short(mp->audio_pause_len, 0);*/ if (is_packet(trackp)) { mp->write_type = WT_PACKET; mp->track_mode |= TM_INCREMENTAL; mp->fp = (trackp->pktsize > 0) ? 1 : 0; i_to_4_byte(mp->packet_size, trackp->pktsize); } else if (is_tao(trackp)) { mp->write_type = WT_TAO; mp->fp = 0; i_to_4_byte(mp->packet_size, 0); } else { errmsgno(EX_BAD, "Unknown write mode.\n"); return (-1); } if (trackp->isrc) { mp->ISRC[0] = 0x80; /* Set ISRC valid */ strncpy((char *)&mp->ISRC[1], trackp->isrc, 12); } else { fillbytes(&mp->ISRC[0], sizeof (mp->ISRC), '\0'); } #ifdef DEBUG usal_prbytes("CD write parameter:", (Uchar *)mode, len); #endif if (!set_mode_params(usalp, "CD write parameter", mode, len, 0, trackp->secsize)) return (-1); return (0); } static int open_track_mdvd(SCSI *usalp, cdr_t *dp, track_t *trackp) { Uchar mode[0x100]; int len; struct cd_mode_page_05 *mp; if (is_packet(trackp)) { fillbytes((caddr_t)mode, sizeof(mode), '\0'); if (!get_mode_params(usalp, 0x05, "DVD write parameter", mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) return (-1); if (len == 0) return (-1); mp = (struct cd_mode_page_05 *) (mode + sizeof(struct scsi_mode_header) + ((struct scsi_mode_header *)mode)->blockdesc_len); mp->write_type = WT_PACKET; mp->LS_V = 1; /*For now we set the link size to 0x10(32k) because Pioneer-A03 only support this */ mp->link_size=0x10; mp->fp = 1; i_to_4_byte(mp->packet_size, trackp->pktsize); } else { return 0; } if (!set_mode_params(usalp, "CD write parameter", mode, len, 0, trackp->secsize)) return (-1); return (0); } static int close_track_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp) { int ret; if (!is_tao(trackp) && !is_packet(trackp)) return (0); if (scsi_flush_cache(usalp, (dp->cdr_cmdflags&F_IMMED) != 0) < 0) { printf("Trouble flushing the cache\n"); return (-1); } wait_unit_ready(usalp, 300); /* XXX Wait for ATAPI */ if (is_packet(trackp) && !is_noclose(trackp)) { /* close the incomplete track */ ret = scsi_close_tr_session(usalp, CL_TYPE_TRACK, 0xFF, (dp->cdr_cmdflags&F_IMMED) != 0); wait_unit_ready(usalp, 300); /* XXX Wait for ATAPI */ return (ret); } return (0); } static int close_track_mdvd(SCSI *usalp, cdr_t *dp, track_t *trackp) { int ret; if (!is_packet(trackp)) return (0); if (scsi_flush_cache(usalp, (dp->cdr_cmdflags&F_IMMED) != 0) < 0) { printf("Trouble flushing the cache\n"); return -1; } wait_unit_ready(usalp, 300); /* XXX Wait for ATAPI */ if (is_packet(trackp) && !is_noclose(trackp)) { /* close the incomplete track */ ret = scsi_close_tr_session(usalp, 1, 0xFF, (dp->cdr_cmdflags&F_IMMED) != 0); wait_unit_ready(usalp, 300); /* XXX Wait for ATAPI */ return (ret); } return (0); } int toc2sess[] = { SES_DA_ROM, /* CD-DA */ SES_DA_ROM, /* CD-ROM */ SES_XA, /* CD-ROM XA mode 1 */ SES_XA, /* CD-ROM XA MODE 2 */ SES_CDI, /* CDI */ SES_DA_ROM, /* Invalid - use default */ SES_DA_ROM, /* Invalid - use default */ }; static int open_session_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp) { Uchar mode[0x100]; int len; struct cd_mode_page_05 *mp; fillbytes((caddr_t)mode, sizeof (mode), '\0'); if (!get_mode_params(usalp, 0x05, "CD write parameter", mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) return (-1); if (len == 0) return (-1); mp = (struct cd_mode_page_05 *) (mode + sizeof (struct scsi_mode_header) + ((struct scsi_mode_header *)mode)->blockdesc_len); mp->write_type = WT_TAO; /* fix to allow DAO later */ /* * We need to set the right dbtype here because Sony drives * don't like multi session in to be set with DB_ROM_MODE1 * which is set by us at the beginning as default as some drives * have illegal default values. */ mp->track_mode = st2mode[trackp[0].sectype & ST_MASK]; mp->dbtype = trackp[0].dbtype; if (!is_tao(trackp) && !is_packet(trackp)) { mp->write_type = WT_SAO; if (dp->cdr_dstat->ds_cdrflags & RF_AUDIOMASTER) mp->write_type = 8; mp->track_mode = 0; mp->dbtype = DB_RAW; } if (is_raw(trackp)) { mp->write_type = WT_RAW; mp->track_mode = 0; if (is_raw16(trackp)) { mp->dbtype = DB_RAW_PQ; } else if (is_raw96r(trackp)) { mp->dbtype = DB_RAW_PW_R; } else { mp->dbtype = DB_RAW_PW; } } mp->multi_session = (track_base(trackp)->tracktype & TOCF_MULTI) ? MS_MULTI : MS_NONE; mp->session_format = toc2sess[track_base(trackp)->tracktype & TOC_MASK]; if (trackp->isrc) { mp->media_cat_number[0] = 0x80; /* Set MCN valid */ strncpy((char *)&mp->media_cat_number[1], trackp->isrc, 13); } else { fillbytes(&mp->media_cat_number[0], sizeof (mp->media_cat_number), '\0'); } #ifdef DEBUG usal_prbytes("CD write parameter:", (Uchar *)mode, len); #endif if (!set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) return (-1); return (0); } static int open_session_mdvd(SCSI *usalp, cdr_t *dp, track_t *trackp) { Uchar mode[0x100]; int tracks = trackp->tracks; int len; struct cd_mode_page_05 *mp; Ulong totalsize; int i; int profile; fillbytes((caddr_t)mode, sizeof(mode), '\0'); if (!get_mode_params(usalp, 0x05, "DVD write parameter", mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) return (-1); if (len == 0) return (-1); mp = (struct cd_mode_page_05 *) (mode + sizeof(struct scsi_mode_header) + ((struct scsi_mode_header *)mode)->blockdesc_len); if(is_packet(trackp)){ mp->write_type=WT_PACKET; mp->fp=0; mp->BUFE=1; mp->track_mode=1; }else{ mp->write_type = WT_SAO; } mp->multi_session = (track_base(trackp)->tracktype & TOCF_MULTI) ? MS_MULTI : MS_NONE; mp->session_format = toc2sess[track_base(trackp)->tracktype & TOC_MASK]; /* Enable Burnfree by default, allow to disable. XXX Sucks, duplicated functionality. */ if (dp->cdr_cdcap->BUF != 0) { if (lverbose > 2) fprintf(stderr, "BURN-Free is %s.\n" "Turning BURN-Free on\n", mp->BUFE?"ON":"OFF"); mp->BUFE = 1; } if (driveropts != NULL) { if ((strcmp(driveropts, "noburnproof") == 0 || strcmp(driveropts, "noburnfree") == 0)) { if(lverbose>1) fprintf(stderr, "Turning BURN-Free off\n"); mp->BUFE = 0; } else if ((strcmp(driveropts, "burnproof") == 0 || strcmp(driveropts, "burnfree") == 0)) { /* a NOP, we enable burnfree by default */ if(lverbose>2) fprintf(stderr, "Found burnproof/burnfree in driveropts, those options are enabled by default now."); } else if (strcmp(driveropts, "help") == 0) { mmc_opthelp(dp, 0); } else { errmsgno(EX_BAD, "Bad driver opts '%s'.\n", driveropts); mmc_opthelp(dp, EX_BAD); } } if (!set_mode_params(usalp, "DVD write parameter", mode, len, 0, -1)) return (-1); totalsize=0; for(i=1;i<=tracks;i++) { totalsize+=trackp[i].tracksecs; } profile = get_curprofile(usalp); if(!is_packet(trackp) && profile != 0x1A){ /* in DAO mode we need to reserve space for the track*/ if(reserve_track(usalp, totalsize)<0) return (-1); } return (0); } static int waitfix_mmc(SCSI *usalp, int secs) { char dibuf[16]; int i; int key; #define W_SLEEP 2 usalp->silent++; for (i = 0; i < secs/W_SLEEP; i++) { if (read_disk_info(usalp, dibuf, sizeof (dibuf)) >= 0) { usalp->silent--; return (0); } key = usal_sense_key(usalp); if (key != SC_UNIT_ATTENTION && key != SC_NOT_READY) break; sleep(W_SLEEP); } usalp->silent--; return (-1); #undef W_SLEEP } static int fixate_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp) { int ret = 0; int key = 0; int code = 0; struct timeval starttime; struct timeval stoptime; int dummy = (track_base(trackp)->tracktype & TOCF_DUMMY) != 0; if(debug) printf("fixate_mmc\n"); starttime.tv_sec = 0; starttime.tv_usec = 0; stoptime = starttime; gettimeofday(&starttime, (struct timezone *)0); if (dummy && lverbose) printf("WARNING: Some drives don't like fixation in dummy mode.\n"); usalp->silent++; if(debug) printf("is_tao: %d,is_packet: %d\n", is_tao(trackp), is_packet(trackp)); if (is_tao(trackp) || is_packet(trackp)) { ret = scsi_close_tr_session(usalp, CL_TYPE_SESSION, 0, (dp->cdr_cmdflags&F_IMMED) != 0); } else { if (scsi_flush_cache(usalp, (dp->cdr_cmdflags&F_IMMED) != 0) < 0) { if (!scsi_in_progress(usalp)) printf("Trouble flushing the cache\n"); } } usalp->silent--; key = usal_sense_key(usalp); code = usal_sense_code(usalp); usalp->silent++; if (debug && !unit_ready(usalp)) { fprintf(stderr, "Early return from fixating. Ret: %d Key: %d, Code: %d\n", ret, key, code); } usalp->silent--; if (ret >= 0) { wait_unit_ready(usalp, 420/curspeed); /* XXX Wait for ATAPI */ waitfix_mmc(usalp, 420/curspeed); /* XXX Wait for ATAPI */ return (ret); } if ((dummy != 0 && (key != SC_ILLEGAL_REQUEST)) || /* * Try to suppress messages from drives that don't like fixation * in -dummy mode. */ ((dummy == 0) && (((key != SC_UNIT_ATTENTION) && (key != SC_NOT_READY)) || ((code != 0x2E) && (code != 0x04))))) { /* * UNIT ATTENTION/2E seems to be a magic for old Mitsumi ATAPI drives * NOT READY/ code 4 qual 7 (logical unit not ready, operation in progress) * seems to be a magic for newer Mitsumi ATAPI drives * NOT READY/ code 4 qual 8 (logical unit not ready, long write in progress) * seems to be a magic for SONY drives * when returning early from fixating. * Try to supress the error message in this case to make * simple minded users less confused. */ usal_printerr(usalp); usal_printresult(usalp); /* XXX restore key/code in future */ } if (debug && !unit_ready(usalp)) { fprintf(stderr, "Early return from fixating. Ret: %d Key: %d, Code: %d\n", ret, key, code); } wait_unit_ready(usalp, 420); /* XXX Wait for ATAPI */ waitfix_mmc(usalp, 420/curspeed); /* XXX Wait for ATAPI */ if (!dummy && (ret >= 0 || (key == SC_UNIT_ATTENTION && code == 0x2E))) { /* * Some ATAPI drives (e.g. Mitsumi) imply the * IMMED bit in the SCSI cdb. As there seems to be no * way to properly check for the real end of the * fixating process we wait for the expected time. */ gettimeofday(&stoptime, (struct timezone *)0); timevaldiff(&starttime, &stoptime); if (stoptime.tv_sec < (220 / curspeed)) { unsigned secs; if (lverbose) { printf("Actual fixating time: %ld seconds\n", (long)stoptime.tv_sec); } secs = (280 / curspeed) - stoptime.tv_sec; if (lverbose) { printf("ATAPI early return: sleeping %d seconds.\n", secs); } sleep(secs); } } return (ret); } static int fixate_mdvd(SCSI *usalp, cdr_t *dp, track_t *trackp) { int ret; if (scsi_flush_cache(usalp, (dp->cdr_cmdflags&F_IMMED) != 0) < 0) { printf("Trouble flushing the cache\n"); return -1; } wait_unit_ready(usalp, 300); /* XXX Wait for ATAPI */ /*set a really BIG timeout and call fixate_mmc The BIG timeout is needed in case there was a very short rzone to write at the beginning of the disk, because lead-out needs to be at some distance. */ if(debug) printf("fixate_mdvd\n"); usal_settimeout(usalp, 1000); if(is_packet(trackp) || dp->profile == 0x1B){ scsi_close_tr_session(usalp, CL_TYPE_SESSION, 0, FALSE); } ret = fixate_mmc(usalp, dp, trackp); if (dp->profile == 0x2B) { scsi_close_tr_session(usalp, CL_TYPE_OPEN_SESSION, 0, FALSE); scsi_close_tr_session(usalp, CL_TYPE_FINALISE_MINRAD, 0, FALSE); } usal_settimeout(usalp, 200); return ret; } char *blank_types[] = { "entire disk", "PMA, TOC, pregap", "incomplete track", "reserved track", "tail of track", "closing of last session", "last session", "reserved blanking type", }; char *format_types[] = { "full format", "background format", "forced format", }; static int blank_mmc(SCSI *usalp, cdr_t *dp, long addr, int blanktype) { BOOL cdrr = FALSE; /* Read CD-R */ BOOL cdwr = FALSE; /* Write CD-R */ BOOL cdrrw = FALSE; /* Read CD-RW */ BOOL cdwrw = FALSE; /* Write CD-RW */ int ret; mmc_check(usalp, &cdrr, &cdwr, &cdrrw, &cdwrw, NULL, NULL); if (!cdwrw) return (blank_dummy(usalp, dp, addr, blanktype)); if (dp->profile == 0x1A) { printf("Error: this media does not support blanking, ignoring.\n"); return (blank_dummy(usalp, dp, addr, blanktype)); } if (lverbose) { printf("Blanking %s\n", blank_types[blanktype & 0x07]); flush(); } ret = scsi_blank(usalp, addr, blanktype, (dp->cdr_cmdflags&F_IMMED) != 0); if (ret < 0) return (ret); wait_unit_ready(usalp, 90*60/curspeed); /* XXX Wait for ATAPI */ waitfix_mmc(usalp, 90*60/curspeed); /* XXX Wait for ATAPI */ return (ret); } static int format_mdvd(SCSI *usalp, cdr_t *dp, int formattype) { extern char *buf; BOOL dvdwr = FALSE; /* Write DVD */ int ret; int profile; char addr[12]; struct disk_info *dip; if (debug || lverbose > 2) printf("format_mdvd\n"); mmc_check(usalp, NULL, NULL, NULL, NULL, NULL, &dvdwr); if (!dvdwr) return (format_dummy(usalp, dp, formattype)); if (debug || lverbose > 2) printf("format_mdvd: drive is a dvd burner.\n"); profile = get_curprofile(usalp); if (profile != 0x1A) { printf("Error: only support DVD+RW formating, ignoring.\n"); return (format_dummy(usalp, dp, formattype)); } dip = (struct disk_info *)buf; if (get_diskinfo(usalp, dip) < 0) return -1; if (dip->disk_status & 3 && formattype != FORCE_FORMAT) { printf("Error: disk already formated, ignoring.\n"); return -1; } addr[0] = 0; /* "Reserved" */ addr[1] = 2; /* "IMMED" flag */ addr[2] = 0; /* "Descriptor Length" (MSB) */ addr[3] = 8; /* "Descriptor Length" (LSB) */ addr[4+0] = 0xff; addr[4+1] = 0xff; addr[4+2] = 0xff; addr[4+3] = 0xff; addr[4+4] = 0x26<<2; addr[4+5] = 0; addr[4+6] = 0; addr[4+7] = 0; if (formattype == FORCE_FORMAT) { printf("format_mdvd: forcing reformat.\n"); formattype = FULL_FORMAT; addr[4+0] = 0; addr[4+1] = 0; addr[4+2] = 0; addr[4+3] = 0; addr[4+7] = 1; } else { printf("format_mdvd: media is unformated.\n"); } if (lverbose) { printf("Formating %s\n", format_types[formattype & 0x07]); flush(); } if (formattype == FULL_FORMAT) { ret = scsi_format(usalp, (caddr_t)&addr, sizeof(addr), FALSE); } else { ret = scsi_format(usalp, (caddr_t)&addr, sizeof(addr), TRUE); } if (ret < 0) return (ret); wait_unit_ready(usalp, 90*60/curspeed); /* XXX Wait for ATAPI */ waitfix_mmc(usalp, 90*60/curspeed); /* XXX Wait for ATAPI */ return (ret); } static int send_opc_mmc(SCSI *usalp, caddr_t bp, int cnt, int doopc) { int ret; usalp->silent++; ret = send_opc(usalp, bp, cnt, doopc); usalp->silent--; if (ret >= 0) return (ret); /* BEGIN CSTYLED */ /* * Hack for a mysterioys drive .... * Device type : Removable CD-ROM * Version : 0 * Response Format: 1 * Vendor_info : 'RWD ' * Identifikation : 'RW2224 ' * Revision : '2.53' * Device seems to be: Generic mmc CD-RW. * * Performing OPC... * CDB: 54 01 00 00 00 00 00 00 00 00 * Sense Bytes: 70 00 06 00 00 00 00 0A 00 00 00 00 5A 03 00 00 * Sense Key: 0x6 Unit Attention, Segment 0 * Sense Code: 0x5A Qual 0x03 (operator selected write permit) Fru 0x0 * Sense flags: Blk 0 (not valid) */ /* END CSTYLED */ if (usal_sense_key(usalp) == SC_UNIT_ATTENTION && usal_sense_code(usalp) == 0x5A && usal_sense_qual(usalp) == 0x03) return (0); /* * Do not make the condition: * "Power calibration area almost full" a fatal error. * It just flags that we have a single and last chance to write now. */ if ((usal_sense_key(usalp) == SC_RECOVERABLE_ERROR || usal_sense_key(usalp) == SC_MEDIUM_ERROR) && usal_sense_code(usalp) == 0x73 && usal_sense_qual(usalp) == 0x01) return (0); /* * Send OPC is optional. */ if (usal_sense_key(usalp) != SC_ILLEGAL_REQUEST) { if (usalp->silent <= 0) usal_printerr(usalp); return (ret); } return (0); } static int opt1_mmc(SCSI *usalp, cdr_t *dp) { int oflags = dp->cdr_dstat->ds_cdrflags; if ((dp->cdr_dstat->ds_cdrflags & RF_AUDIOMASTER) != 0) { printf("Turning Audio Master Q. R. on\n"); if (set_audiomaster_yamaha(usalp, dp, TRUE) < 0) return (-1); if (!debug && lverbose <= 1) dp->cdr_dstat->ds_cdrflags &= ~RF_PRATIP; if (getdisktype_mmc(usalp, dp) < 0) { dp->cdr_dstat->ds_cdrflags = oflags; return (-1); } dp->cdr_dstat->ds_cdrflags = oflags; if (oflags & RF_PRATIP) { msf_t msf; lba_to_msf(dp->cdr_dstat->ds_first_leadin, &msf); printf("New start of lead in: %ld (%02d:%02d/%02d)\n", (long)dp->cdr_dstat->ds_first_leadin, msf.msf_min, msf.msf_sec, msf.msf_frame); lba_to_msf(dp->cdr_dstat->ds_maxblocks, &msf); printf("New start of lead out: %ld (%02d:%02d/%02d)\n", (long)dp->cdr_dstat->ds_maxblocks, msf.msf_min, msf.msf_sec, msf.msf_frame); } } if (mmc_isplextor(usalp)) { int gcode; if ((dp->cdr_flags & (CDR_SINGLESESS|CDR_HIDE_CDR)) != 0) { if (ss_hide_plextor(usalp, (dp->cdr_dstat->ds_cdrflags & RF_SINGLESESS) != 0, (dp->cdr_dstat->ds_cdrflags & RF_HIDE_CDR) != 0) < 0) return (-1); } if ((dp->cdr_flags & CDR_SPEEDREAD) != 0) { if (speed_rd_plextor(usalp, (dp->cdr_dstat->ds_cdrflags & RF_SPEEDREAD) != 0) < 0) return (-1); } if ((dp->cdr_cmdflags & F_SETDROPTS) || (wm_base(dp->cdr_dstat->ds_wrmode) == WM_SAO) || (wm_base(dp->cdr_dstat->ds_wrmode) == WM_RAW)) gcode = do_gigarec_plextor(usalp); else gcode = gigarec_plextor(usalp, 0); if (gcode != 0) { msf_t msf; dp->cdr_dstat->ds_first_leadin = gigarec_mult(gcode, dp->cdr_dstat->ds_first_leadin); dp->cdr_dstat->ds_maxblocks = gigarec_mult(gcode, dp->cdr_dstat->ds_maxblocks); if (oflags & RF_PRATIP) { lba_to_msf(dp->cdr_dstat->ds_first_leadin, &msf); printf("New start of lead in: %ld (%02d:%02d/%02d)\n", (long)dp->cdr_dstat->ds_first_leadin, msf.msf_min, msf.msf_sec, msf.msf_frame); lba_to_msf(dp->cdr_dstat->ds_maxblocks, &msf); printf("New start of lead out: %ld (%02d:%02d/%02d)\n", (long)dp->cdr_dstat->ds_maxblocks, msf.msf_min, msf.msf_sec, msf.msf_frame); } } } return (0); } static int opt2_mmc(SCSI *usalp, cdr_t *dp) { Uchar mode[0x100]; Uchar moder[0x100]; int len; struct cd_mode_page_05 *mp; struct ricoh_mode_page_30 *rp = NULL; BOOL burnfree = FALSE; fillbytes((caddr_t)mode, sizeof (mode), '\0'); if (!get_mode_params(usalp, 0x05, "CD write parameter", mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) return (-1); if (len == 0) return (-1); mp = (struct cd_mode_page_05 *) (mode + sizeof (struct scsi_mode_header) + ((struct scsi_mode_header *)mode)->blockdesc_len); rp = get_justlink_ricoh(usalp, moder); if (dp->cdr_cdcap->BUF != 0) { burnfree = (mp->BUFE != 0); } else if ((dp->cdr_flags & CDR_BURNFREE) != 0) { burnfree = (rp && (rp->BUEFE != 0)); } if (lverbose>2 && (dp->cdr_flags & CDR_BURNFREE) != 0) printf("BURN-Free is %s.\n", burnfree?"ON":"OFF"); if (!burnfree && (dp->cdr_dstat->ds_cdrflags & RF_BURNFREE) != 0) { if(lverbose>2) printf("Turning BURN-Free on\n"); burnfree = TRUE; } if (burnfree && (dp->cdr_dstat->ds_cdrflags & RF_BURNFREE) == 0) { if(lverbose>2) printf("Turning BURN-Free off\n"); burnfree = FALSE; } if (dp->cdr_cdcap->BUF != 0) { mp->BUFE = burnfree?1:0; } else if ((dp->cdr_flags & CDR_BURNFREE) != 0) { if (rp) rp->BUEFE = burnfree?1:0; } if (rp) { /* * Clear Just-Link counter */ i_to_2_byte(rp->link_counter, 0); if (xdebug) usal_prbytes("Mode Select Data ", moder, moder[0]+1); if (!set_mode_params(usalp, "Ricoh Vendor Page", moder, moder[0]+1, 0, -1)) return (-1); rp = get_justlink_ricoh(usalp, moder); } #ifdef DEBUG usal_prbytes("CD write parameter:", (Uchar *)mode, len); #endif if (!set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) return (-1); if (mmc_isplextor(usalp)) { /* * Clear Burn-Proof counter */ usalp->silent++; bpc_plextor(usalp, 1, NULL); usalp->silent--; do_varirec_plextor(usalp); } return (0); } static int opt1_mdvd(SCSI *usalp, cdr_t *dp) { int oflags = dp->cdr_dstat->ds_cdrflags; if ((dp->cdr_dstat->ds_cdrflags & RF_AUDIOMASTER) != 0) { printf("Turning Audio Master Q. R. on\n"); if (set_audiomaster_yamaha(usalp, dp, TRUE) < 0) return (-1); if (!debug && lverbose <= 1) dp->cdr_dstat->ds_cdrflags &= ~RF_PRATIP; if (getdisktype_mdvd(usalp, dp) < 0) { dp->cdr_dstat->ds_cdrflags = oflags; return (-1); } dp->cdr_dstat->ds_cdrflags = oflags; if (oflags & RF_PRATIP) { msf_t msf; lba_to_msf(dp->cdr_dstat->ds_first_leadin, &msf); printf("New start of lead in: %ld (%02d:%02d/%02d)\n", (long)dp->cdr_dstat->ds_first_leadin, msf.msf_min, msf.msf_sec, msf.msf_frame); lba_to_msf(dp->cdr_dstat->ds_maxblocks, &msf); printf("New start of lead out: %ld (%02d:%02d/%02d)\n", (long)dp->cdr_dstat->ds_maxblocks, msf.msf_min, msf.msf_sec, msf.msf_frame); } } return (0); } static int scsi_sony_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 */) { return (write_xg5(usalp, bp, sectaddr, size, blocks)); } Uchar db2df[] = { 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 */ 0x10, /* 8 2048 bytes Mode 1 (ISO/IEC 10149) */ 0x30, /* 9 2336 bytes Mode 2 (ISO/IEC 10149) */ 0xFF, /* 10 2048 bytes Mode 2! (CD-ROM XA form 1) */ 0xFF, /* 11 2056 bytes Mode 2 (CD-ROM XA form 1) */ 0xFF, /* 12 2324 bytes Mode 2 (CD-ROM XA form 2) */ 0xFF, /* 13 2332 bytes Mode 2 (CD-ROM XA 1/2+subhdr) */ 0xFF, /* 14 - Reserved */ 0xFF, /* 15 - Vendor specific */ }; static int gen_cue_mmc(track_t *trackp, void *vcuep, BOOL needgap) { int tracks = trackp->tracks; int i; struct mmc_cue **cuep = vcuep; struct mmc_cue *cue; struct mmc_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; if (is_quadro(&trackp[i])) ctl |= TM_QUADRO << 4; df = db2df[trackp[i].dbtype & 0x0F]; if (trackp[i].tracktype == TOC_XA2 && trackp[i].sectype == (SECT_MODE_2_MIX|ST_MODE_RAW)) { /* * Hack for CUE with MODE2/CDI and * trackp[i].dbtype == DB_RAW */ df = 0x21; } 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 */ df &= ~7; /* Mask off data size & nonRAW subch */ if (df < 0x10) df |= 1; else df |= 4; if (trackp[0].flags & TI_TEXT) /* CD-Text in Lead-in*/ df |= 0x40; 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; if (is_copy(&trackp[i])) ctl |= TM_ALLOW_COPY << 4; if (is_quadro(&trackp[i])) ctl |= TM_QUADRO << 4; df = db2df[trackp[tracks+1].dbtype & 0x0F]; if (trackp[i].tracktype == TOC_XA2 && trackp[i].sectype == (SECT_MODE_2_MIX|ST_MODE_RAW)) { /* * Hack for CUE with MODE2/CDI and * trackp[i].dbtype == DB_RAW */ df = 0x21; } df &= ~7; /* Mask off data size & nonRAW subch */ if (df < 0x10) df |= 1; else df |= 4; 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 mmc_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; /* XXX wie lead in */ cp->cs_tno = tno; cp->cs_index = idx; cp->cs_dataform = dataform; /* XXX wie lead in */ cp->cs_scms = scms; cp->cs_min = mp->msf_min; cp->cs_sec = mp->msf_sec; cp->cs_frame = mp->msf_frame; } static int send_cue_mmc(SCSI *usalp, cdr_t *dp, track_t *trackp) { struct mmc_cue *cp; int ncue; int ret; Uint i; 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); usalp->silent++; ret = send_cue_sheet(usalp, (caddr_t)cp, ncue*8); 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 = send_cue_sheet(usalp, (caddr_t)cp, ncue*8); if (ret < 0) { errmsgno(EX_BAD, "CUE sheet still not accepted. Please try to write in RAW (-raw96r) mode.\n"); } free(cp); } return (ret); } static int stats_mmc(SCSI *usalp, cdr_t *dp) { Uchar mode[256]; struct ricoh_mode_page_30 *rp; UInt32_t count; if (mmc_isplextor(usalp) && lverbose) { int sels; int maxs; int lasts; /* * Run it in silent mode as old drives do not support it. * As this function looks to be a part of the PowerRec * features, we may want to check * dp->cdr_flags & CDR_FORCESPEED */ usalp->silent++; if (get_speeds_plextor(usalp, &sels, &maxs, &lasts) >= 0) { printf("Last selected write speed: %dx\n", sels / 176); printf("Max media write speed: %dx\n", maxs / 176); printf("Last actual write speed: %dx\n", lasts / 176); } usalp->silent--; } if ((dp->cdr_dstat->ds_cdrflags & RF_BURNFREE) == 0) return (0); if (mmc_isplextor(usalp)) { int i = 0; int ret; /* * Read Burn-Proof counter */ usalp->silent++; ret = bpc_plextor(usalp, 2, &i); usalp->silent--; if (ret < 0) return (-1); count = i; /* * Clear Burn-Proof counter */ bpc_plextor(usalp, 1, NULL); } else { rp = get_justlink_ricoh(usalp, mode); if (rp) count = a_to_u_2_byte(rp->link_counter); else return (-1); } if (lverbose) { if (count == 0) printf("BURN-Free was never needed.\n"); else printf("BURN-Free was %d times used.\n", (int)count); } return (0); } /*--------------------------------------------------------------------------*/ static BOOL mmc_isplextor(SCSI *usalp) { if (usalp->inq != NULL && strncmp(usalp->inq->vendor_info, "PLEXTOR", 7) == 0) { return (TRUE); } return (FALSE); } static BOOL mmc_isyamaha(SCSI *usalp) { if (usalp->inq != NULL && strncmp(usalp->inq->vendor_info, "YAMAHA", 6) == 0) { return (TRUE); } return (FALSE); } static void do_varirec_plextor(SCSI *usalp) { char *p; int voff; p = hasdrvopt(driveropts, "varirec="); if (p == NULL || curspeed != 4) { if (check_varirec_plextor(usalp) >= 0) varirec_plextor(usalp, FALSE, 0); } else { if (*astoi(p, &voff) != '\0') comerrno(EX_BAD, "Bad varirec value '%s'.\n", p); if (check_varirec_plextor(usalp) < 0) comerrno(EX_BAD, "Drive does not support VariRec.\n"); varirec_plextor(usalp, TRUE, voff); } } /* * GigaRec value table */ struct gr { Uchar val; char vadd; char *name; } gr[] = { { 0x00, 0, "off", }, { 0x00, 0, "1.0", }, { 0x01, 2, "1.2", }, { 0x02, 3, "1.3", }, { 0x03, 4, "1.4", }, { 0x81, -2, "0.8", }, { 0x82, -3, "0.7", }, { 0x83, -4, "0.6", }, { 0x00, 0, NULL, }, }; static int do_gigarec_plextor(SCSI *usalp) { char *p; int val = 0; /* Make silly GCC happy */ p = hasdrvopt(driveropts, "gigarec="); if (p == NULL) { if (check_gigarec_plextor(usalp) >= 0) gigarec_plextor(usalp, 0); } else { struct gr *gp = gr; for (; gp->name != NULL; gp++) { if (streql(p, gp->name)) { val = gp->val; break; } } if (gp->name == NULL) comerrno(EX_BAD, "Bad gigarec value '%s'.\n", p); if (check_gigarec_plextor(usalp) < 0) comerrno(EX_BAD, "Drive does not support GigaRec.\n"); return (gigarec_plextor(usalp, val)); } return (0); } static int drivemode_plextor(SCSI *usalp, caddr_t bp, int cnt, int modecode, void *modeval) { register struct usal_cmd *scmd = usalp->scmd; fillbytes((caddr_t)scmd, sizeof (*scmd), '\0'); scmd->flags = SCG_DISRE_ENA; if (modeval == NULL) { scmd->flags |= SCG_RECV_DATA; scmd->addr = bp; scmd->size = cnt; } else { scmd->cdb.g5_cdb.res = 0x08; } scmd->cdb_len = SC_G5_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g5_cdb.cmd = 0xE9; scmd->cdb.g5_cdb.lun = usal_lun(usalp); scmd->cdb.g1_cdb.addr[0] = modecode; if (modeval) movebytes(modeval, &scmd->cdb.g1_cdb.addr[1], 6); else i_to_2_byte(&scmd->cdb.g1_cdb.count[2], cnt); usalp->cmdname = "plextor drive mode"; if (usal_cmd(usalp) < 0) return (-1); return (0); } /* * #defines for drivemode_plextor()... */ #define MODE_CODE_SH 0x01 /* Mode code for Single Session & Hide-CDR */ #define MB1_SS 0x01 /* Single Session Mode */ #define MB1_HIDE_CDR 0x02 /* Hide CDR Media */ #define MODE_CODE_VREC 0x02 /* Mode code for Vari Rec */ #define MODE_CODE_GREC 0x04 /* Mode code for Giga Rec */ #define MODE_CODE_SPEED 0xbb /* Mode code for Speed Read */ #define MBbb_SPEAD_READ 0x01 /* Spead Read */ /* Danach Speed auf 0xFFFF 0xFFFF setzen */ static int drivemode2_plextor(SCSI *usalp, caddr_t bp, int cnt, int modecode, void *modeval) { register struct usal_cmd *scmd = usalp->scmd; fillbytes((caddr_t)scmd, sizeof (*scmd), '\0'); scmd->flags = SCG_DISRE_ENA; if (modeval == NULL) { scmd->flags |= SCG_RECV_DATA; scmd->addr = bp; scmd->size = cnt; } else { scmd->cdb.g5_cdb.res = 0x08; } scmd->cdb_len = SC_G5_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g5_cdb.cmd = 0xED; scmd->cdb.g5_cdb.lun = usal_lun(usalp); scmd->cdb.g1_cdb.addr[0] = modecode; if (modeval) scmd->cdb.g5_cdb.reladr = *(char *)modeval != 0 ? 1 : 0; else i_to_2_byte(&scmd->cdb.g1_cdb.count[1], cnt); usalp->cmdname = "plextor drive mode2"; if (usal_cmd(usalp) < 0) return (-1); return (0); } static int check_varirec_plextor(SCSI *usalp) { int modecode = 2; Uchar getmode[8]; fillbytes(getmode, sizeof (getmode), '\0'); usalp->silent++; if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) { usalp->silent--; return (-1); } usalp->silent--; return (0); } static int check_gigarec_plextor(SCSI *usalp) { int modecode = 4; Uchar getmode[8]; fillbytes(getmode, sizeof (getmode), '\0'); usalp->silent++; if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) { usalp->silent--; return (-1); } usalp->silent--; return (0); } static int varirec_plextor(SCSI *usalp, BOOL on, int val) { int modecode = 2; Uchar setmode[8]; Uchar getmode[8]; fillbytes(getmode, sizeof (getmode), '\0'); usalp->silent++; if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) { usalp->silent--; return (-1); } usalp->silent--; if (lverbose > 1) usal_prbytes("Modes", getmode, sizeof (getmode)); fillbytes(setmode, sizeof (setmode), '\0'); setmode[0] = on?1:0; if (on) { if (val < -2 || val > 2) comerrno(EX_BAD, "Bad VariRec offset %d\n", val); printf("Turning Varirec on.\n"); printf("Varirec offset is %d.\n", val); if (val > 0) { setmode[1] = val & 0x7F; } else { setmode[1] = (-val) & 0x7F; setmode[1] |= 0x80; } } if (drivemode_plextor(usalp, NULL, 0, modecode, setmode) < 0) return (-1); fillbytes(getmode, sizeof (getmode), '\0'); if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) return (-1); if (lverbose > 1) usal_prbytes("Modes", getmode, sizeof (getmode)); return (0); } static int gigarec_plextor(SCSI *usalp, int val) { int modecode = 4; Uchar setmode[8]; Uchar getmode[8]; fillbytes(getmode, sizeof (getmode), '\0'); usalp->silent++; if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) { usalp->silent--; return (-1); } usalp->silent--; if (lverbose > 1) usal_prbytes("Modes", getmode, sizeof (getmode)); fillbytes(setmode, sizeof (setmode), '\0'); setmode[1] = val; if (drivemode_plextor(usalp, NULL, 0, modecode, setmode) < 0) return (-1); fillbytes(getmode, sizeof (getmode), '\0'); if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) return (-1); if (lverbose > 1) usal_prbytes("Modes", getmode, sizeof (getmode)); { struct gr *gp = gr; for (; gp->name != NULL; gp++) { if (getmode[3] == gp->val) break; } if (gp->name == NULL) printf("Unknown GigaRec value 0x%X.\n", getmode[3]); else printf("GigaRec %sis %s.\n", gp->val?"value ":"", gp->name); } return (getmode[3]); } static Int32_t gigarec_mult(int code, Int32_t val) { Int32_t add; struct gr *gp = gr; for (; gp->name != NULL; gp++) { if (code == gp->val) break; } if (gp->vadd == 0) return (val); add = val * gp->vadd / 10; return (val + add); } static int check_ss_hide_plextor(SCSI *usalp) { int modecode = 1; Uchar getmode[8]; fillbytes(getmode, sizeof (getmode), '\0'); usalp->silent++; if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) { usalp->silent--; return (-1); } usalp->silent--; return (getmode[2] & 0x03); } static int check_speed_rd_plextor(SCSI *usalp) { int modecode = 0xBB; Uchar getmode[8]; fillbytes(getmode, sizeof (getmode), '\0'); usalp->silent++; if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) { usalp->silent--; return (-1); } usalp->silent--; return (getmode[2] & 0x01); } static int check_powerrec_plextor(SCSI *usalp) { int modecode = 0; Uchar getmode[8]; fillbytes(getmode, sizeof (getmode), '\0'); usalp->silent++; if (drivemode2_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) { usalp->silent--; return (-1); } usalp->silent--; if (getmode[2] & 1) return (1); return (0); } static int ss_hide_plextor(SCSI *usalp, BOOL do_ss, BOOL do_hide) { int modecode = 1; Uchar setmode[8]; Uchar getmode[8]; BOOL is_ss; BOOL is_hide; fillbytes(getmode, sizeof (getmode), '\0'); usalp->silent++; if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) { usalp->silent--; return (-1); } usalp->silent--; if (lverbose > 1) usal_prbytes("Modes", getmode, sizeof (getmode)); is_ss = (getmode[2] & MB1_SS) != 0; is_hide = (getmode[2] & MB1_HIDE_CDR) != 0; if (lverbose > 0) { printf("Single session is %s.\n", is_ss ? "ON":"OFF"); printf("Hide CDR is %s.\n", is_hide ? "ON":"OFF"); } fillbytes(setmode, sizeof (setmode), '\0'); setmode[0] = getmode[2]; /* Copy over old values */ if (do_ss >= 0) { if (do_ss) setmode[0] |= MB1_SS; else setmode[0] &= ~MB1_SS; } if (do_hide >= 0) { if (do_hide) setmode[0] |= MB1_HIDE_CDR; else setmode[0] &= ~MB1_HIDE_CDR; } if (do_ss >= 0 && do_ss != is_ss) printf("Turning single session %s.\n", do_ss?"on":"off"); if (do_hide >= 0 && do_hide != is_hide) printf("Turning hide CDR %s.\n", do_hide?"on":"off"); if (drivemode_plextor(usalp, NULL, 0, modecode, setmode) < 0) return (-1); fillbytes(getmode, sizeof (getmode), '\0'); if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) return (-1); if (lverbose > 1) usal_prbytes("Modes", getmode, sizeof (getmode)); return (0); } static int speed_rd_plextor(SCSI *usalp, BOOL do_speedrd) { int modecode = 0xBB; Uchar setmode[8]; Uchar getmode[8]; BOOL is_speedrd; fillbytes(getmode, sizeof (getmode), '\0'); usalp->silent++; if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) { usalp->silent--; return (-1); } usalp->silent--; if (lverbose > 1) usal_prbytes("Modes", getmode, sizeof (getmode)); is_speedrd = (getmode[2] & MBbb_SPEAD_READ) != 0; if (lverbose > 0) printf("Speed-Read is %s.\n", is_speedrd ? "ON":"OFF"); fillbytes(setmode, sizeof (setmode), '\0'); setmode[0] = getmode[2]; /* Copy over old values */ if (do_speedrd >= 0) { if (do_speedrd) setmode[0] |= MBbb_SPEAD_READ; else setmode[0] &= ~MBbb_SPEAD_READ; } if (do_speedrd >= 0 && do_speedrd != is_speedrd) printf("Turning Speed-Read %s.\n", do_speedrd?"on":"off"); if (drivemode_plextor(usalp, NULL, 0, modecode, setmode) < 0) return (-1); fillbytes(getmode, sizeof (getmode), '\0'); if (drivemode_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) return (-1); if (lverbose > 1) usal_prbytes("Modes", getmode, sizeof (getmode)); /* * Set current read speed to new max value. */ if (do_speedrd >= 0 && do_speedrd != is_speedrd) scsi_set_speed(usalp, 0xFFFF, -1, ROTCTL_CAV); return (0); } static int powerrec_plextor(SCSI *usalp, BOOL do_powerrec) { int modecode = 0; Uchar setmode[8]; Uchar getmode[8]; BOOL is_powerrec; int speed; fillbytes(getmode, sizeof (getmode), '\0'); usalp->silent++; if (drivemode2_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) { usalp->silent--; return (-1); } usalp->silent--; if (lverbose > 1) usal_prbytes("Modes", getmode, sizeof (getmode)); is_powerrec = (getmode[2] & 1) != 0; speed = a_to_u_2_byte(&getmode[4]); if (lverbose > 0) { printf("Power-Rec is %s.\n", is_powerrec ? "ON":"OFF"); printf("Power-Rec write speed: %dx (recommended)\n", speed / 176); } fillbytes(setmode, sizeof (setmode), '\0'); setmode[0] = getmode[2]; /* Copy over old values */ if (do_powerrec >= 0) { if (do_powerrec) setmode[0] |= 1; else setmode[0] &= ~1; } if (do_powerrec >= 0 && do_powerrec != is_powerrec) printf("Turning Power-Rec %s.\n", do_powerrec?"on":"off"); if (drivemode2_plextor(usalp, NULL, 0, modecode, setmode) < 0) return (-1); fillbytes(getmode, sizeof (getmode), '\0'); if (drivemode2_plextor(usalp, (caddr_t)getmode, sizeof (getmode), modecode, NULL) < 0) return (-1); if (lverbose > 1) usal_prbytes("Modes", getmode, sizeof (getmode)); return (0); } static int get_speeds_plextor(SCSI *usalp, int *selp, int *maxp, int *lastp) { register struct usal_cmd *scmd = usalp->scmd; char buf[10]; int i; fillbytes((caddr_t)scmd, sizeof (*scmd), '\0'); fillbytes((caddr_t)buf, sizeof (buf), '\0'); scmd->flags = SCG_DISRE_ENA; scmd->flags |= SCG_RECV_DATA; scmd->addr = buf; scmd->size = sizeof (buf); scmd->cdb_len = SC_G5_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g5_cdb.cmd = 0xEB; scmd->cdb.g5_cdb.lun = usal_lun(usalp); i_to_2_byte(&scmd->cdb.g1_cdb.count[1], sizeof (buf)); usalp->cmdname = "plextor get speedlist"; if (usal_cmd(usalp) < 0) return (-1); i = a_to_u_2_byte(&buf[4]); if (selp) *selp = i; i = a_to_u_2_byte(&buf[6]); if (maxp) *maxp = i; i = a_to_u_2_byte(&buf[8]); if (lastp) *lastp = i; return (0); } static int bpc_plextor(SCSI *usalp, int mode, int *bpp) { register struct usal_cmd *scmd = usalp->scmd; char buf[4]; int i; fillbytes((caddr_t)scmd, sizeof (*scmd), '\0'); fillbytes((caddr_t)buf, sizeof (buf), '\0'); scmd->flags = SCG_DISRE_ENA; scmd->flags |= SCG_RECV_DATA; scmd->addr = buf; scmd->size = sizeof (buf); scmd->cdb_len = SC_G5_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g5_cdb.cmd = 0xF5; scmd->cdb.g5_cdb.lun = usal_lun(usalp); scmd->cdb.g5_cdb.addr[1] = 0x08; scmd->cdb.g5_cdb.addr[2] = mode; i_to_2_byte(&scmd->cdb.g1_cdb.count[1], sizeof (buf)); usalp->cmdname = "plextor read bpc"; if (usal_cmd(usalp) < 0) return (-1); if (usal_getresid(usalp) > 2) return (0); i = a_to_u_2_byte(buf); if (bpp) *bpp = i; return (0); } static int set_audiomaster_yamaha(SCSI *usalp, cdr_t *dp, BOOL keep_mode) { Uchar mode[0x100]; int len; int ret = 0; struct cd_mode_page_05 *mp; if (xdebug && !keep_mode) printf("Checking for Yamaha Audio Master feature: "); /* * Do not reset mp->test_write (-dummy) here. */ deflt_writemodes_mmc(usalp, FALSE); fillbytes((caddr_t)mode, sizeof (mode), '\0'); usalp->silent++; if (!get_mode_params(usalp, 0x05, "CD write parameter", mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) { usalp->silent--; return (-1); } if (len == 0) { usalp->silent--; return (-1); } mp = (struct cd_mode_page_05 *) (mode + sizeof (struct scsi_mode_header) + ((struct scsi_mode_header *)mode)->blockdesc_len); #ifdef DEBUG usal_prbytes("CD write parameter:", (Uchar *)mode, len); #endif /* * Do not set mp->test_write (-dummy) here. It should be set * only at one place and only one time. */ mp->BUFE = 0; mp->write_type = 8; mp->track_mode = 0; mp->dbtype = DB_RAW; if (!set_mode_params(usalp, "CD write parameter", mode, len, 0, -1)) ret = -1; /* * Do not reset mp->test_write (-dummy) here. */ if (!keep_mode || ret < 0) deflt_writemodes_mmc(usalp, FALSE); usalp->silent--; return (ret); } struct ricoh_mode_page_30 *get_justlink_ricoh(SCSI *usalp, Uchar *mode) { Uchar modec[0x100]; int len; struct ricoh_mode_page_30 *mp; usalp->silent++; if (!get_mode_params(usalp, 0x30, "Ricoh Vendor Page", mode, modec, NULL, NULL, &len)) { usalp->silent--; return ((struct ricoh_mode_page_30 *)0); } usalp->silent--; /* * SCSI mode header + 6 bytes mode page 30. * This is including the Burn-Free counter. */ if (len < 10) return ((struct ricoh_mode_page_30 *)0); if (xdebug) { fprintf(stderr, "Mode len: %d\n", len); usal_prbytes("Mode Sense Data ", mode, len); usal_prbytes("Mode Sence CData", modec, len); } mp = (struct ricoh_mode_page_30 *) (mode + sizeof (struct scsi_mode_header) + ((struct scsi_mode_header *)mode)->blockdesc_len); /* * 6 bytes mode page 30. * This is including the Burn-Free counter. */ if ((len - ((Uchar *)mp - mode) -1) < 5) return ((struct ricoh_mode_page_30 *)0); if (xdebug) { fprintf(stderr, "Burnfree counter: %d\n", a_to_u_2_byte(mp->link_counter)); } return (mp); } static int force_speed_yamaha(SCSI *usalp, int readspeed, int writespeed) { register struct usal_cmd *scmd = usalp->scmd; fillbytes((caddr_t)scmd, sizeof (*scmd), '\0'); scmd->flags = SCG_DISRE_ENA; scmd->cdb_len = SC_G5_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g5_cdb.cmd = 0xBB; scmd->cdb.g5_cdb.lun = usal_lun(usalp); if (readspeed < 0) i_to_2_byte(&scmd->cdb.g5_cdb.addr[0], 0xFFFF); else i_to_2_byte(&scmd->cdb.g5_cdb.addr[0], readspeed); if (writespeed < 0) i_to_2_byte(&scmd->cdb.g5_cdb.addr[2], 0xFFFF); else i_to_2_byte(&scmd->cdb.g5_cdb.addr[2], writespeed); scmd->cdb.cmd_cdb[11] = 0x80; usalp->cmdname = "yamaha force cd speed"; if (usal_cmd(usalp) < 0) return (-1); return (0); } static BOOL get_tattoo_yamaha(SCSI *usalp, BOOL print, Int32_t *irp, Int32_t *orp) { Uchar mode[0x100]; int len; UInt32_t ival; UInt32_t oval; Uchar *mp; usalp->silent++; if (!get_mode_params(usalp, 0x31, "Yamaha Tattoo Page", mode, NULL, NULL, NULL, &len)) { usalp->silent--; return (FALSE); } usalp->silent--; /* * SCSI mode header + 16 bytes mode page 31. * This is including the Burn-Free counter. */ if (len < 20) return (FALSE); mp = (Uchar *) (mode + sizeof (struct scsi_mode_header) + ((struct scsi_mode_header *)mode)->blockdesc_len); /* * 10 bytes mode page 31. * This is including the Burn-Free counter. */ if ((len - ((Uchar *)mp - mode) -1) < 10) return (FALSE); ival = a_to_u_3_byte(&mp[4]); oval = a_to_u_3_byte(&mp[7]); if (irp) *irp = ival; if (orp) *orp = oval; if (print && ival > 0 && oval > 0) { printf("DiskT@2 inner r: %d\n", (int)ival); printf("DiskT@2 outer r: %d\n", (int)oval); printf("DiskT@2 image size: 3744 x %d pixel.\n", (int)(oval-ival)+1); } return (TRUE); } static int do_tattoo_yamaha(SCSI *usalp, FILE *f) { Int32_t ival = 0; Int32_t oval = 0; Int32_t lines; off_t fsize; char *buf = usalp->bufptr; long bufsize = usalp->maxbuf; long nsecs; long amt; nsecs = bufsize / 2048; bufsize = nsecs * 2048; if (!get_tattoo_yamaha(usalp, FALSE, &ival, &oval)) { errmsgno(EX_BAD, "Cannot get DiskT@2 info.\n"); return (-1); } if (ival == 0 || oval == 0) { errmsgno(EX_BAD, "DiskT@2 info not valid.\n"); return (-1); } lines = oval - ival + 1; fsize = filesize(f); if ((fsize % 3744) != 0 || fsize < (lines*3744)) { errmsgno(EX_BAD, "Illegal DiskT@2 file size.\n"); return (-1); } if (fsize > (lines*3744)) fsize = lines*3744; if (lverbose) printf("Starting to write DiskT@2 data.\n"); fillbytes(buf, bufsize, '\0'); if ((amt = fileread(f, buf, bufsize)) <= 0) { errmsg("DiskT@2 file read error.\n"); return (-1); } if (yamaha_write_buffer(usalp, 1, 0, ival, amt/2048, buf, amt) < 0) { errmsgno(EX_BAD, "DiskT@2 1st write error.\n"); return (-1); } amt = (amt+2047) / 2048 * 2048; fsize -= amt; while (fsize > 0) { fillbytes(buf, bufsize, '\0'); if ((amt = fileread(f, buf, bufsize)) <= 0) { errmsg("DiskT@2 file read error.\n"); return (-1); } amt = (amt+2047) / 2048 * 2048; fsize -= amt; if (yamaha_write_buffer(usalp, 1, 0, 0, amt/2048, buf, amt) < 0) { errmsgno(EX_BAD, "DiskT@2 write error.\n"); return (-1); } } if (yamaha_write_buffer(usalp, 1, 0, oval, 0, buf, 0) < 0) { errmsgno(EX_BAD, "DiskT@2 final error.\n"); return (-1); } wait_unit_ready(usalp, 1000); /* Wait for DiskT@2 */ waitfix_mmc(usalp, 1000); /* Wait for DiskT@2 */ return (0); } /* * Yamaha specific version of 'write buffer' that offers an additional * Parameter Length 'parlen' parameter. */ static int yamaha_write_buffer(SCSI *usalp, int mode, int bufferid, long offset, long parlen, void *buffer, long buflen) { register struct usal_cmd *scmd = usalp->scmd; Uchar *CDB; fillbytes((caddr_t)scmd, sizeof (*scmd), '\0'); scmd->addr = buffer; scmd->size = buflen; scmd->flags = SCG_DISRE_ENA; scmd->cdb_len = SC_G1_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g1_cdb.cmd = 0x3B; CDB = (Uchar *)scmd->cdb.cmd_cdb; CDB[1] = mode & 7; CDB[2] = bufferid; i_to_3_byte(&CDB[3], offset); i_to_3_byte(&CDB[6], parlen); usalp->cmdname = "write_buffer"; if (usal_cmd(usalp) >= 0) return (1); return (0); } static int dvd_dual_layer_split(SCSI *usalp, cdr_t *dp, long tsize) { unsigned char xb[12]; long l0_size; /* Get the Layer 0 defined data zone*/ if (read_dvd_structure(usalp, (caddr_t)xb, 12, 0, 0, 0x20) >= 0) { if ((xb[1] | xb[0] << 8) < 13) { fprintf(stderr, "dvd_dual_layer_split: read_dvd_structure returns invalid data\n"); return 1; } if (xb[4] & 0x80) { printf("L0 zone size already set\n"); return 1; } l0_size = xb[11] | xb[10] << 8 | xb[9] << 16 | xb[8] << 24; if (tsize < l0_size) { fprintf(stderr, "track size smaller than one layer, use --force to force burning."); return 0; } printf("L0 size: %ld (track size %ld)\n", l0_size, tsize); l0_size = tsize / 2; l0_size = l0_size - 1 + 16 - (l0_size - 1) % 16; printf("New L0 size: %ld\n", l0_size); memset (xb, 0, sizeof(xb)); xb[1] = sizeof(xb) - 2; xb[8] = l0_size >> 24; xb[9] = l0_size >> 16; xb[10] = l0_size >> 8; xb[11] = l0_size; if (send_dvd_structure(usalp, (caddr_t)xb, 12, 0, 0x20)) { fprintf(stderr, "dvd_dual_layer_split: send_dvd_structure failed, could not set middle zone location.\n"); return 0; } } return 1; }