diff options
Diffstat (limited to 'scsi/rz_audio.c')
-rw-r--r-- | scsi/rz_audio.c | 1901 |
1 files changed, 0 insertions, 1901 deletions
diff --git a/scsi/rz_audio.c b/scsi/rz_audio.c deleted file mode 100644 index 4d60fa1..0000000 --- a/scsi/rz_audio.c +++ /dev/null @@ -1,1901 +0,0 @@ -/* - * Mach Operating System - * Copyright (c) 1993 Carnegie Mellon University - * All Rights Reserved. - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie Mellon - * the rights to redistribute these changes. - */ -/* - * File: rz_audio.c - * Author: Alessandro Forin, Carnegie Mellon University - * Date: 3/93 - * - * Top layer of the SCSI driver: interface with the MI. - * This file contains operations specific to audio CD-ROM devices. - * Unlike many others, it sits on top of the rz.c module. - */ - -#include <mach/std_types.h> -#include <kern/strings.h> -#include <machine/machspl.h> /* spl definitions */ -#include <vm/vm_kern.h> -#include <device/ds_routines.h> - -#include <scsi/compat_30.h> -#include <scsi/scsi.h> -#include <scsi/scsi2.h> -#include <scsi/scsi_defs.h> -#include <scsi/rz.h> - -#if (NSCSI > 0) - -#define private static - -/* some data is two BCD digits in one byte */ -#define bcd_to_decimal(b) (((b)&0xf) + 10 * (((b) >> 4) & 0xf)) -#define decimal_to_bcd(b) ((((b) / 10) << 4) | ((b) % 10)) - -/* - * Regular use of a CD-ROM is for data, and is handled - * by the default set of operations. Ours is for funtime.. - */ - -extern char *sccdrom_name(); -int cd_strategy(); -void cd_start(); - -private scsi_devsw_t scsi_audio = { - sccdrom_name, 0, 0, 0, cd_strategy, cd_start, 0, 0 -}; - -private char unsupported[] = "Device does not support it."; - -/* - * Unfortunately, none of the vendors appear to - * abide by the SCSI-2 standard and many of them - * violate or stretch even the SCSI-1 one. - * Therefore, we keep a red-list here of the worse - * offendors and how to deal with them. - * The user is notified of the problem and invited - * to solicit his vendor to upgrade the firmware. - * [They had plenty of time to do so] - */ -typedef struct red_list { - char *vendor; - char *product; - char *rev; - /* - * The standard MANDATES [par 13.1.6] the play_audio command - * at least as a way to discover if the device - * supports audio operations at all. This is the only way - * we need to use it. - */ - scsi_ret_t (*can_play_audio)( target_info_t *, char *, io_req_t); - /* - * The standard defines the use of start_stop_unit to - * cause the drive to eject the disk. - */ - scsi_ret_t (*eject)( target_info_t *, char *, io_req_t ); - /* - * The standard defines read_subchannel as a way to - * get the current playing position. - */ - scsi_ret_t (*current_position)( target_info_t *, char *, io_req_t ); - /* - * The standard defines read_table_of_content to get - * the listing of audio tracks available. - */ - scsi_ret_t (*read_toc)( target_info_t *, char *, io_req_t ); - /* - * The standard defines read_subchannel as the way to - * report the current audio status (playing/stopped/...). - */ - scsi_ret_t (*get_status)( target_info_t *, char *, io_req_t ); - /* - * The standard defines two ways to issue a play command, - * depending on the type of addressing used. - */ - scsi_ret_t (*play_msf)( target_info_t *, char *, io_req_t ); - scsi_ret_t (*play_ti)( target_info_t *, char *, io_req_t ); - /* - * The standard defines the pause_resume command to - * suspend or resume playback of audio data. - */ - scsi_ret_t (*pause_resume)( target_info_t *, char *, io_req_t ); - /* - * The standard defines the audio page among the - * mode selection options as a way to control - * both volume and connectivity of the channels - */ - scsi_ret_t (*volume_control)( target_info_t *, char *, io_req_t ); -} red_list_t; - -#define if_it_can_do(some_cmd) \ - if (tgt->dev_info.cdrom.violates_standards && \ - tgt->dev_info.cdrom.violates_standards->some_cmd) \ - rc = (*tgt->dev_info.cdrom.violates_standards->some_cmd) \ - (tgt,cmd,ior); \ - else - -/* - * So now that you know what they should have implemented :-), - * check at the end of the file what the naughty boys did instead. - */ -/* private red_list_t audio_replacements[]; / * at end */ - -/* - * Forward decls - */ -private void decode_status( char *buf, unsigned char audio_status ); -void zero_ior( io_req_t ); - -/* - * Open routine. Does some checking, sets up - * the replacement pointer. - */ -io_return_t -cd_open( - int dev, - dev_mode_t mode, - io_req_t req) -{ - scsi_softc_t *sc = 0; - target_info_t *tgt; - int ret; - scsi_ret_t rc; - io_req_t ior = 0; - vm_offset_t mem = 0; - extern boolean_t rz_check(); - - if (!rz_check(dev, &sc, &tgt)) { - /* - * Probe it again: might have installed a new device - */ - if (!sc || !scsi_probe(sc, &tgt, rzslave(dev), ior)) - return D_NO_SUCH_DEVICE; - bzero(&tgt->dev_info, sizeof(tgt->dev_info)); - } - - /* - * Check this is indeded a CD-ROM - */ - if (tgt->dev_ops != &scsi_devsw[SCSI_CDROM]) { - rz_close(dev); - return D_NO_SUCH_DEVICE; - } - - /* - * Switch to audio ops, unless some wrong - */ - tgt->dev_ops = &scsi_audio; - - /* - * Bring unit online - */ - ret = rz_open(dev, mode, req); - if (ret) goto bad; - - /* Pessimistic */ - ret = D_INVALID_OPERATION; - - /* - * Check if this device is on the red list - */ - { - scsi2_inquiry_data_t *inq; - private void check_red_list(); - - scsi_inquiry(tgt, SCSI_INQ_STD_DATA); - inq = (scsi2_inquiry_data_t*)tgt->cmd_ptr; - - check_red_list( tgt, inq ); - - } - - /* - * Allocate dynamic data - */ - if (kmem_alloc(kernel_map, &mem, PAGE_SIZE) != KERN_SUCCESS) - return D_NO_MEMORY; - tgt->dev_info.cdrom.result = (void *)mem; - tgt->dev_info.cdrom.result_available = FALSE; - - /* - * See if this CDROM can play audio data - */ - io_req_alloc(ior,0); - zero_ior( ior ); - - { - char *cmd = 0; - if_it_can_do(can_play_audio) - rc = scsi_play_audio( tgt, 0, 0, FALSE, ior); - } - - if (rc != SCSI_RET_SUCCESS) goto bad; - - io_req_free(ior); - return D_SUCCESS; - -bad: - if (ior) io_req_free(ior); - if (mem) kmem_free(kernel_map, mem, PAGE_SIZE); - tgt->dev_ops = &scsi_devsw[SCSI_CDROM]; - return ret; -} - -/* - * Close routine. - */ -io_return_t -cd_close( - int dev) -{ - scsi_softc_t *sc; - target_info_t *tgt; - vm_offset_t mem; - - if (!rz_check(dev, &sc, &tgt)) - return D_NO_SUCH_DEVICE; - if (!tgt || (tgt->dev_ops != &scsi_audio)) - return D_NO_SUCH_DEVICE; - - /* - * Cleanup state - */ - mem = (vm_offset_t) tgt->dev_info.cdrom.result; - tgt->dev_info.cdrom.result = (void *)0; - tgt->dev_info.cdrom.result_available = FALSE; - - (void) kmem_free(kernel_map, mem, PAGE_SIZE); - - (void) rz_close(dev); - - tgt->dev_ops = &scsi_devsw[SCSI_CDROM]; - return D_SUCCESS; -} - -/* - * Write routine. It is passed an ASCII string - * with the command to be executed. - */ -io_return_t -cd_write( - int dev, - io_req_t ior) -{ - register kern_return_t rc; - boolean_t wait = FALSE; - io_return_t ret; - int count; - register char *data; - vm_offset_t addr; - - data = ior->io_data; - count = ior->io_count; - if (count == 0) - return D_SUCCESS; - - if (!(ior->io_op & IO_INBAND)) { - /* - * Copy out-of-line data into kernel address space. - * Since data is copied as page list, it will be - * accessible. - */ - vm_map_copy_t copy = (vm_map_copy_t) data; - kern_return_t kr; - - kr = vm_map_copyout(device_io_map, &addr, copy); - if (kr != KERN_SUCCESS) - return kr; - data = (char *) addr; - } - - if (scsi_debug) printf("Got command '%s'\n", data); - - ret = cd_command( dev, data, count, ior); - - if (!(ior->io_op & IO_INBAND)) - (void) vm_deallocate(device_io_map, addr, ior->io_count); - return D_SUCCESS; -} - -/* - * Read routine. Returns an ASCII string with the results - * of the last command executed. - */ -io_return_t -cd_read( - int dev, - io_req_t ior) -{ - target_info_t *tgt; - kern_return_t rc; - natural_t count; - - /* - * Allocate memory for read buffer. - */ - count = (natural_t)ior->io_count; - if (count > PAGE_SIZE) - return D_INVALID_SIZE; /* sanity */ - - rc = device_read_alloc(ior, count); - if (rc != KERN_SUCCESS) - return rc; - - if (scsi_debug) printf("Got read req for %d bytes\n", count); - - /* - * See if last cmd left some to say - */ - tgt = scsi_softc[rzcontroller(dev)]->target[rzslave(dev)]; - if (tgt->dev_info.cdrom.result_available) { - int len; - - tgt->dev_info.cdrom.result_available = FALSE; - len = strlen(tgt->dev_info.cdrom.result)+1; - - if (count > len) - count = len; - bcopy(tgt->dev_info.cdrom.result, ior->io_data, count); - - } else { -# define noway "No results pending" - count = (count > sizeof(noway)) ? sizeof(noway) : count; - bcopy(noway, ior->io_data, count); - } - - ior->io_residual = ior->io_count - count; - return D_SUCCESS; -} - -/* - * This does all the work - */ -io_return_t -cd_command( - int dev, - char *cmd, - int count, - io_req_t req) -{ - target_info_t *tgt; - io_req_t ior; - io_return_t ret = D_INVALID_OPERATION; - scsi_ret_t rc; - char *buf; - - tgt = scsi_softc[rzcontroller(dev)]->target[rzslave(dev)]; - - buf = tgt->dev_info.cdrom.result; - tgt->dev_info.cdrom.result_available = FALSE; - - io_req_alloc(ior,0); - zero_ior( ior ); - - switch (cmd[0]) { - - case 'E': - /* "Eject" */ - /* too many dont support it. Sigh */ - tgt->flags |= TGT_OPTIONAL_CMD; - (void) scsi_medium_removal( tgt, TRUE, ior); - tgt->flags &= ~TGT_OPTIONAL_CMD; - - zero_ior( ior ); - - if_it_can_do(eject) - rc = scsi_start_unit(tgt, SCSI_CMD_SS_EJECT, ior); - break; - - case 'G': - switch (cmd[4]) { - - case 'P': - /* "Get Position MSF|ABS" */ - if_it_can_do(current_position) { - rc = scsi_read_subchannel(tgt, - cmd[13] == 'M', - SCSI_CMD_RS_FMT_CURPOS, - 0, - ior); - if (rc == SCSI_RET_SUCCESS) { - cdrom_chan_curpos_t *st; - st = (cdrom_chan_curpos_t *)tgt->cmd_ptr; - if (cmd[13] == 'M') - sprintf(buf, "MSF Position %d %d %d %d %d %d", - (integer_t)st->subQ.absolute_address.msf.minute, - (integer_t)st->subQ.absolute_address.msf.second, - (integer_t)st->subQ.absolute_address.msf.frame, - (integer_t)st->subQ.relative_address.msf.minute, - (integer_t)st->subQ.relative_address.msf.second, - (integer_t)st->subQ.relative_address.msf.frame); - else - sprintf(buf, "ABS Position %d %d", (integer_t) - (st->subQ.absolute_address.lba.lba1<<24)+ - (st->subQ.absolute_address.lba.lba2<<16)+ - (st->subQ.absolute_address.lba.lba3<< 8)+ - st->subQ.absolute_address.lba.lba4, - (integer_t) - (st->subQ.relative_address.lba.lba1<<24)+ - (st->subQ.relative_address.lba.lba2<<16)+ - (st->subQ.relative_address.lba.lba3<< 8)+ - st->subQ.relative_address.lba.lba4); - tgt->dev_info.cdrom.result_available = TRUE; - } - } - break; - - case 'T': - /* "Get TH" */ - if_it_can_do(read_toc) { - rc = scsi_read_toc(tgt, TRUE, 1, PAGE_SIZE, ior); - if (rc == SCSI_RET_SUCCESS) { - cdrom_toc_t *toc = (cdrom_toc_t *)tgt->cmd_ptr; - sprintf(buf, "toc header: %d %d %d", - (toc->len1 << 8) + toc->len2, - toc->first_track, - toc->last_track); - tgt->dev_info.cdrom.result_available = TRUE; - } - } - break; - - case 'S': - /* "Get Status" */ - if_it_can_do(get_status) { - rc = scsi_read_subchannel(tgt, - TRUE, - SCSI_CMD_RS_FMT_CURPOS, - 0, - ior); - if (rc == SCSI_RET_SUCCESS) { - cdrom_chan_curpos_t *st; - st = (cdrom_chan_curpos_t *)tgt->cmd_ptr; - decode_status(buf, st->audio_status); - tgt->dev_info.cdrom.result_available = TRUE; - } - } - break; - } - break; - - case 'P': - switch (cmd[5]) { - case 'A': - /* "Play A startM startS startF endM endS endF" */ - if_it_can_do(play_msf) { - - int sm, ss, sf, em, es, ef; - - sscanf(&cmd[7], "%d %d %d %d %d %d", - &sm, &ss, &sf, &em, &es, &ef); - - rc = scsi_play_audio_msf(tgt, - sm, ss, sf, - em, es, ef, - ior); - } - break; - - case 'T': - /* "Play TI startT startI endT endI" */ - if_it_can_do(play_ti) { - - int st, si, et, ei; - - sscanf(&cmd[8], "%d %d %d %d", - &st, &si, &et, &ei); - - rc = scsi_play_audio_track_index(tgt, - st, si, et, ei, ior); - } - break; - } - break; - - case 'R': - /* "Resume" */ - if_it_can_do(pause_resume) - rc = scsi_pause_resume(tgt, FALSE, ior); - break; - - case 'S': - switch (cmd[2]) { - - case 'a': - /* "Start" */ - rc = scsi_start_unit(tgt, SCSI_CMD_SS_START, ior); - break; - - case 'o': - /* "Stop" */ - if_it_can_do(pause_resume) - rc = scsi_pause_resume(tgt, TRUE, ior); - break; - - case 't': - /* "Set V chan0vol chan1vol chan2vol chan3vol" */ - if_it_can_do(volume_control) { - - int v0, v1, v2, v3; - cdrom_audio_page_t au, *aup; - - rc = scsi_mode_sense(tgt, - SCSI_CD_AUDIO_PAGE, - sizeof(au), - ior); - if (rc == SCSI_RET_SUCCESS) { - - sscanf(&cmd[6], "%d %d %d %d", - &v0, &v1, &v2, &v3); - - aup = (cdrom_audio_page_t *) tgt->cmd_ptr; - au = *aup; - /* au.h.bdesc ... */ - au.vol0 = v0; - au.vol1 = v1; - au.vol2 = v2; - au.vol3 = v3; - au.imm = 1; - au.aprv = 0; - - zero_ior( ior ); - - rc = scsi2_mode_select(tgt, FALSE, - &au, sizeof(au), ior); - } - } - break; - } - break; - - case 'T': - /* "Toc MSF|ABS trackno" */ - if_it_can_do(read_toc) { - - int t, m; - - sscanf(&cmd[8], "%d", &t); - rc = scsi_read_toc( tgt, cmd[4]=='M', t, PAGE_SIZE, ior); - - if (rc == SCSI_RET_SUCCESS) { - - cdrom_toc_t *toc = (cdrom_toc_t *)tgt->cmd_ptr; - - sprintf(buf, "TOC from track %d:\n", t); - m = (toc->len1 << 8) + toc->len2; - m -= 4; /* header */ - for (t = 0; m > 0; t++, m -= sizeof(struct cdrom_toc_desc)) { - buf += strlen(buf); - if (cmd[4] == 'M') - sprintf(buf, "%d %d %d %d %d %d\n", - toc->descs[t].control, - toc->descs[t].adr, - toc->descs[t].trackno, - (integer_t)toc->descs[t].absolute_address.msf.minute, - (integer_t)toc->descs[t].absolute_address.msf.second, - (integer_t)toc->descs[t].absolute_address.msf.frame); - else - sprintf(buf, "%d %d %d %d\n", - toc->descs[t].control, - toc->descs[t].adr, - toc->descs[t].trackno, - (toc->descs[t].absolute_address.lba.lba1<<24)+ - (toc->descs[t].absolute_address.lba.lba2<<16)+ - (toc->descs[t].absolute_address.lba.lba3<<8)+ - toc->descs[t].absolute_address.lba.lba4); - } - tgt->dev_info.cdrom.result_available = TRUE; - } - } - break; - } - - if (rc == SCSI_RET_SUCCESS) - ret = D_SUCCESS; - - /* We are stateless, but.. */ - if (rc == SCSI_RET_NEED_SENSE) { - zero_ior( ior ); - tgt->ior = ior; - scsi_request_sense(tgt, ior, 0); - iowait(ior); - if (scsi_check_sense_data(tgt, tgt->cmd_ptr)) - scsi_print_sense_data(tgt->cmd_ptr); - } - - io_req_free(ior); - return ret; -} - -private char st_invalid [] = "Drive would not say"; -private char st_playing [] = "Playing"; -private char st_paused [] = "Suspended"; -private char st_complete[] = "Done playing"; -private char st_error [] = "Stopped in error"; -private char st_nothing [] = "Idle"; - -private void -decode_status( - char *buf, - unsigned char audio_status) -{ - switch (audio_status) { - case SCSI_CDST_INVALID: - sprintf(buf, st_invalid); break; - case SCSI_CDST_PLAYING: - sprintf(buf, st_playing); break; - case SCSI_CDST_PAUSED: - sprintf(buf, st_paused); break; - case SCSI_CDST_COMPLETED: - sprintf(buf, st_complete); break; - case SCSI_CDST_ERROR: - sprintf(buf, st_error); break; - case SCSI_CDST_NO_STATUS: - sprintf(buf, st_nothing); break; - } -} - -/* some vendor specific use this instead */ -private void -decode_status_1( - char *buf, - unsigned char audio_status) -{ - switch (audio_status) { - case 0: sprintf(buf, st_playing ); break; - case 1: - case 2: sprintf(buf, st_paused ); break; - case 3: sprintf(buf, st_complete ); break; - default: - sprintf(buf, "Unknown status" ); break; - } -} - - -private void -curse_the_vendor( - red_list_t *list, - boolean_t not_really) -{ - if (not_really) return; - - printf("%s\n%s\n%s\n%s\n", - "The CDROM you use is not fully SCSI-2 compliant.", - "We invite You to contact Your vendor and ask", - "that they provide You with a firmware upgrade.", - "Here is a list of some known deficiencies"); - - printf("Vendor: %s Product: %s.. Revision: %s..\n", - list->vendor, list->product, list->rev); - -#define check(x,y,z) \ - if (list->x) printf("Command code x%x %s not supported\n", y, z); - - check(can_play_audio, SCSI_CMD_PLAY_AUDIO, "PLAY_AUDIO"); - check(eject, SCSI_CMD_START_STOP_UNIT, - "START_STOP_UNIT, flag EJECT(0x2) in byte 5"); - check(current_position, SCSI_CMD_READ_SUBCH, "READ_SUBCHANNEL"); - check(read_toc, SCSI_CMD_READ_TOC, "READ_TOC"); -/* check(get_status, ...); duplicate of current_position */ - check(play_msf, SCSI_CMD_PLAY_AUDIO_MSF, "PLAY_AUDIO_MSF"); - check(play_ti, SCSI_CMD_PLAY_AUDIO_TI, "PLAY_AUDIO_TRACK_INDEX"); - check(pause_resume, SCSI_CMD_PAUSE_RESUME, "PAUSE_RESUME"); - check(volume_control, SCSI_CMD_MODE_SELECT, - "MODE_SELECT, AUDIO page(0xe)"); - -#undef check - printf("Will work around these problems...\n"); -} - -/* - * Ancillaries - */ -cd_strategy(ior) - register io_req_t ior; -{ - return rz_simpleq_strategy( ior, cd_start); -} - -void cd_start( tgt, done) - target_info_t *tgt; - boolean_t done; -{ - io_req_t ior; - - ior = tgt->ior; - if (done && ior) { - tgt->ior = 0; - iodone(ior); - return; - } - panic("cd start"); /* uhu? */ -} - -/* - * When the hardware cannot - */ -private scsi_ret_t -op_not_supported( - target_info_t *tgt, - char *cmd, - io_req_t ior) -{ - /* - * The command is not implemented, no way around it - */ - sprintf(tgt->dev_info.cdrom.result, unsupported); - tgt->dev_info.cdrom.result_available = TRUE; - return SCSI_RET_SUCCESS; -} - -/****************************************/ -/* Vendor Specific Operations */ -/****************************************/ - - /* DEC RRD42 */ - -#define SCSI_CMD_DEC_SET_ADDRESS_FORMAT 0xc0 -# define scsi_cmd_saf_fmt scsi_cmd_xfer_len_2 - -#define SCSI_CMD_DEC_PLAYBACK_STATUS 0xc4 -typedef struct { - unsigned char xxx; - BITFIELD_2(unsigned char, - is_msf: 1, - xxx1: 7); - unsigned char data_len1; - unsigned char data_len0; - unsigned char audio_status; - BITFIELD_2(unsigned char, - control : 4, - xxx2 : 4); - cdrom_addr_t address; - BITFIELD_2(unsigned char, - chan0_select : 4, - xxx3 : 4); - unsigned char chan0_volume; - BITFIELD_2(unsigned char, - chan1_select : 4, - xxx4 : 4); - unsigned char chan1_volume; - BITFIELD_2(unsigned char, - chan2_select : 4, - xxx5 : 4); - unsigned char chan2_volume; - BITFIELD_2(unsigned char, - chan3_select : 4, - xxx6 : 4); - unsigned char chan3_volume; -} dec_playback_status_t; - -#define SCSI_CMD_DEC_PLAYBACK_CONTROL 0xc9 -typedef struct { - unsigned char xxx0; - BITFIELD_2(unsigned char, - fmt : 1, - xxx1 : 7); - unsigned char xxx[8]; - BITFIELD_2(unsigned char, - chan0_select : 4, - xxx3 : 4); - unsigned char chan0_volume; - BITFIELD_2(unsigned char, - chan1_select : 4, - xxx4 : 4); - unsigned char chan1_volume; - BITFIELD_2(unsigned char, - chan2_select : 4, - xxx5 : 4); - unsigned char chan2_volume; - BITFIELD_2(unsigned char, - chan3_select : 4, - xxx6 : 4); - unsigned char chan3_volume; -} dec_playback_control_t; - - -#if 0 - -private scsi_ret_t -rrd42_status( - target_info_t *tgt, - char *cmd, - io_req_t ior) -{ - scsi_ret_t rc; - char *buf = tgt->dev_info.cdrom.result; - scsi_command_group_2 c; - dec_playback_status_t *st; - - /* We might have to specify addressing fmt */ - if (cmd[4] == 'P') { - scsi_command_group_2 saf; - - bzero(&saf, sizeof(saf)); - saf.scsi_cmd_code = SCSI_CMD_DEC_SET_ADDRESS_FORMAT; - saf.scsi_cmd_saf_fmt = (cmd[13] == 'A') ? 0 : 1; - - rc = cdrom_vendor_specific(tgt, &saf, 0, 0, 0, ior); - - if (rc != SCSI_RET_SUCCESS) return rc; - - zero_ior( ior ); - } - - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_DEC_PLAYBACK_STATUS; - c.scsi_cmd_xfer_len_2 = sizeof(*st); - rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(*st), ior); - - if (rc != SCSI_RET_SUCCESS) return rc; - - st = (dec_playback_status_t *) tgt->cmd_ptr; - - if (cmd[4] == 'S') - decode_status( buf, st->audio_status+0x11 ); - else { - if (st->is_msf) - sprintf(buf, "MSF Position %d %d %d", - (integer_t)st->address.msf.minute, - (integer_t)st->address.msf.second, - (integer_t)st->address.msf.frame); - else - sprintf(buf, "ABS Position %d", (integer_t) - (st->address.lba.lba1<<24)+ - (st->address.lba.lba2<<16)+ - (st->address.lba.lba3<< 8)+ - st->address.lba.lba4); - } - tgt->dev_info.cdrom.result_available = TRUE; - return rc; -} -#endif - -private scsi_ret_t -rrd42_set_volume( - target_info_t *tgt, - char *cmd, - io_req_t ior) -{ - scsi_command_group_2 c; - dec_playback_control_t req; - int v0, v1, v2, v3; - - sscanf(&cmd[6], "%d %d %d %d", &v0, &v1, &v2, &v3); - - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_DEC_PLAYBACK_CONTROL; - c.scsi_cmd_xfer_len_2 = sizeof(req); - bzero(&req, sizeof(req)); - if (v0) { - req.chan0_select = 1; - req.chan0_volume = v0; - } - if (v1) { - req.chan1_select = 2; - req.chan1_volume = v1; - } - if (v2) { - req.chan2_select = 4; - req.chan2_volume = v2; - } - if (v3) { - req.chan3_select = 8; - req.chan3_volume = v3; - } - return cdrom_vendor_specific(tgt, &c, &req, sizeof(req), 0, ior); -} - - /* NEC CD-ROM */ - -#define SCSI_CMD_NEC_READ_TOC 0xde -typedef struct { - unsigned char xxx[9]; - unsigned char first_track; - unsigned char xxx1[9]; - unsigned char last_track; - unsigned char xxx2[9]; - unsigned char lead_out_addr[3]; - struct { - BITFIELD_2(unsigned char, - adr : 4, - ctrl : 4); - unsigned char xxx3[6]; - unsigned char address[3]; - } track_info[1]; /* VARSIZE */ -} nec_toc_data_t; - -#define SCSI_CMD_NEC_SEEK_TRK 0xd8 -#define SCSI_CMD_NEC_PLAY_AUDIO 0xd9 -#define SCSI_CMD_NEC_PAUSE 0xda -#define SCSI_CMD_NEC_EJECT 0xdc - -#define SCSI_CMD_NEC_READ_SUBCH_Q 0xdd -typedef struct { - unsigned char audio_status; /* see decode_status_1 */ - BITFIELD_2(unsigned char, - ctrl : 4, - xxx1 : 4); - unsigned char trackno; - unsigned char indexno; - unsigned char relative_address[3]; - unsigned char absolute_address[3]; -} nec_subch_data_t; - -/* - * Reserved bits in byte1 - */ -#define NEC_LR_PLAY_MODE 0x01 /* RelAdr bit overload */ -#define NEC_LR_STEREO 0x02 /* mono/stereo */ - -/* - * Vendor specific bits in the control byte. - * NEC uses them to specify the addressing mode - */ -#define NEC_CTRL_A_ABS 0x00 /* XXX not sure about this */ -#define NEC_CTRL_A_MSF 0x40 /* min/sec/frame */ -#define NEC_CTRL_A_TI 0x80 /* track/index */ -#define NEC_CTRL_A_CURRENT 0xc0 /* same as last specified */ - -private scsi_ret_t -nec_eject( - target_info_t *tgt, - char *cmd, - io_req_t ior) -{ - scsi_command_group_2 c; - - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_NEC_EJECT; - - return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); -} - -private scsi_ret_t -nec_subchannel( - target_info_t *tgt, - char *cmd, - io_req_t ior) -{ - scsi_command_group_2 c; - nec_subch_data_t *st; - char *buf = tgt->dev_info.cdrom.result; - scsi_ret_t rc; - - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_NEC_READ_SUBCH_Q; - c.scsi_cmd_lun_and_relbit = sizeof(*st); /* Sic! */ - - rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(*st), ior); - if (rc != SCSI_RET_SUCCESS) return rc; - - st = (nec_subch_data_t *) tgt->cmd_ptr; - - /* Status or Position ? */ - - if (cmd[4] == 'S') { - decode_status_1( buf, st->audio_status); - } else { - - /* XXX can it do ABS addressing e.g. 'logical' ? */ - - sprintf(buf, "MSF Position %d %d %d %d %d %d", - (integer_t)bcd_to_decimal(st->absolute_address[0]), /* min */ - (integer_t)bcd_to_decimal(st->absolute_address[1]), /* sec */ - (integer_t)bcd_to_decimal(st->absolute_address[2]), /* frm */ - (integer_t)bcd_to_decimal(st->relative_address[0]), /* min */ - (integer_t)bcd_to_decimal(st->relative_address[1]), /* sec */ - (integer_t)bcd_to_decimal(st->relative_address[2])); /* frm */ - } - - tgt->dev_info.cdrom.result_available = TRUE; - return SCSI_RET_SUCCESS; -} - -private scsi_ret_t -nec_read_toc( - target_info_t *tgt, - char *cmd, - io_req_t ior) -{ - scsi_command_group_2 c; - nec_toc_data_t *t; - char *buf = tgt->dev_info.cdrom.result; - scsi_ret_t rc; - int first, last, i; - - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_NEC_READ_TOC; - c.scsi_cmd_lun_and_relbit = NEC_LR_PLAY_MODE|NEC_LR_STEREO; - - rc = cdrom_vendor_specific(tgt, &c, 0, 0, 512/*XXX*/, ior); - if (rc != SCSI_RET_SUCCESS) return rc; - - t = (nec_toc_data_t *) tgt->cmd_ptr; - - first = bcd_to_decimal(t->first_track); - last = bcd_to_decimal(t->last_track); - - /* - * "Get TH" wants summary, "TOC MSF|ABS from_track" wants all - */ - if (cmd[0] == 'G') { - sprintf(buf, "toc header: %d %d %d", - sizeof(*t) + sizeof(t->track_info) * (last - first - 1), - first, last); - goto out; - } - - /* - * The whole shebang - */ - sscanf(&cmd[8], "%d", &i); - sprintf(buf, "TOC from track %d:\n", i); - - last -= first; - i -= first; - while ((i >= 0) && (i <= last)) { - buf += strlen(buf); - if (cmd[4] == 'M') - sprintf(buf, "%d %d %d %d %d %d\n", - t->track_info[i].ctrl, - t->track_info[i].adr, - first + i, - bcd_to_decimal(t->track_info[i].address[0]), - bcd_to_decimal(t->track_info[i].address[1]), - bcd_to_decimal(t->track_info[i].address[2])); - else -/* THIS IS WRONG */ - sprintf(buf, "%d %d %d %d\n", - t->track_info[i].ctrl, - t->track_info[i].adr, - first + i, - bcd_to_decimal(t->track_info[i].address[0]) * 10000 + - bcd_to_decimal(t->track_info[i].address[1]) * 100 + - bcd_to_decimal(t->track_info[i].address[2])); - i++; - } - /* To know how long the last track is */ - buf += strlen(buf); - if (cmd[4] == 'M') - sprintf(buf, "%d %d %d %d %d %d\n", - 0, 1, 0xaa /* User expects this */, - bcd_to_decimal(t->lead_out_addr[0]), - bcd_to_decimal(t->lead_out_addr[1]), - bcd_to_decimal(t->lead_out_addr[2])); - else -/* THIS IS WRONG */ - sprintf(buf, "%d %d %d %d\n", - 0, 1, 0xaa /* User expects this */, - bcd_to_decimal(t->lead_out_addr[0]) * 10000 + - bcd_to_decimal(t->lead_out_addr[1]) * 100 + - bcd_to_decimal(t->lead_out_addr[2])); -out: - tgt->dev_info.cdrom.result_available = TRUE; - return SCSI_RET_SUCCESS; -} - - -private scsi_ret_t -nec_play( - target_info_t *tgt, - char *cmd, - io_req_t ior) -{ - scsi_command_group_2 c; - int sm, ss, sf, em, es, ef; - int st, si, et, ei; - scsi_ret_t rc; - - /* - * Seek to desired position - */ - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_NEC_SEEK_TRK; - c.scsi_cmd_lun_and_relbit = NEC_LR_PLAY_MODE; - - /* - * Play_msf or Play_ti - */ - if (cmd[5] == 'A') { - /* "Play A startM startS startF endM endS endF" */ - - sscanf(&cmd[7], "%d %d %d %d %d %d", - &sm, &ss, &sf, &em, &es, &ef); - - c.scsi_cmd_lba1 = decimal_to_bcd(sm); - c.scsi_cmd_lba2 = decimal_to_bcd(ss); - c.scsi_cmd_lba3 = decimal_to_bcd(sf); - c.scsi_cmd_ctrl_byte = NEC_CTRL_A_MSF; - - } else { - /* "Play TI startT startI endT endI" */ - - sscanf(&cmd[8], "%d %d %d %d", &st, &si, &et, &ei); - - c.scsi_cmd_lba1 = decimal_to_bcd(st); - c.scsi_cmd_lba2 = decimal_to_bcd(si); - c.scsi_cmd_lba3 = 0; - c.scsi_cmd_ctrl_byte = NEC_CTRL_A_TI; - - } - - rc = cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); - if (rc != SCSI_RET_SUCCESS) return rc; - - /* - * Now ask it to play until.. - */ - zero_ior( ior ); - - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_NEC_PLAY_AUDIO; - c.scsi_cmd_lun_and_relbit = NEC_LR_PLAY_MODE|NEC_LR_STEREO; - - if (cmd[5] == 'A') { - c.scsi_cmd_lba1 = decimal_to_bcd(em); - c.scsi_cmd_lba2 = decimal_to_bcd(es); - c.scsi_cmd_lba3 = decimal_to_bcd(ef); - c.scsi_cmd_ctrl_byte = NEC_CTRL_A_MSF; - } else { - c.scsi_cmd_lba1 = decimal_to_bcd(et); - c.scsi_cmd_lba2 = decimal_to_bcd(ei); - c.scsi_cmd_lba3 = 0; - c.scsi_cmd_ctrl_byte = NEC_CTRL_A_TI; - } - - return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); -} - -private scsi_ret_t -nec_pause_resume( - target_info_t *tgt, - char *cmd, - io_req_t ior) -{ - scsi_command_group_2 c; - - bzero(&c, sizeof(c)); - /* - * "Resume" or "Stop" - */ - if (cmd[0] == 'R') { - c.scsi_cmd_code = SCSI_CMD_NEC_PLAY_AUDIO; - c.scsi_cmd_lun_and_relbit = NEC_LR_PLAY_MODE|NEC_LR_STEREO; - c.scsi_cmd_ctrl_byte = NEC_CTRL_A_CURRENT; - } else { - c.scsi_cmd_code = SCSI_CMD_NEC_PAUSE; - } - - return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); -} - - /* TOSHIBA CD-ROM DRIVE:XM 3232 */ - -#define SCSI_CMD_TOSHIBA_SEEK_TRK 0xc0 -#define SCSI_CMD_TOSHIBA_PLAY_AUDIO 0xc1 -#define SCSI_CMD_TOSHIBA_PAUSE_AUDIO 0xc2 -#define SCSI_CMD_TOSHIBA_EJECT 0xc4 - -#define SCSI_CMD_TOSHIBA_READ_SUBCH_Q 0xc6 -typedef nec_subch_data_t toshiba_subch_data_t; -/* audio status -> decode_status_1 */ - -#define SCSI_CMD_TOSHIBA_READ_TOC_ENTRY 0xc7 -typedef struct { - unsigned char first_track; - unsigned char last_track; - unsigned char xxx[2]; -} toshiba_toc_header_t; -typedef struct { - unsigned char address[4]; -} toshiba_toc_data_t; - - -private scsi_ret_t -toshiba_eject( - target_info_t *tgt, - char *cmd, - io_req_t ior) -{ - scsi_command_group_2 c; - - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_TOSHIBA_EJECT; - - return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); -} - -private scsi_ret_t -toshiba_subchannel( - target_info_t *tgt, - char *cmd, - io_req_t ior) -{ - scsi_command_group_2 c; - toshiba_subch_data_t *st; - char *buf = tgt->dev_info.cdrom.result; - scsi_ret_t rc; - - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_TOSHIBA_READ_SUBCH_Q; - c.scsi_cmd_lun_and_relbit = sizeof(*st); /* Sic! */ - - rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(*st), ior); - if (rc != SCSI_RET_SUCCESS) return rc; - - st = (toshiba_subch_data_t *) tgt->cmd_ptr; - - /* Status or Position ? */ - - if (cmd[4] == 'S') { - decode_status_1( buf, st->audio_status); - } else { - - /* XXX can it do ABS addressing e.g. 'logical' ? */ - - sprintf(buf, "MSF Position %d %d %d %d %d %d", - (integer_t)bcd_to_decimal(st->absolute_address[0]), /* min */ - (integer_t)bcd_to_decimal(st->absolute_address[1]), /* sec */ - (integer_t)bcd_to_decimal(st->absolute_address[2]), /* frm */ - (integer_t)bcd_to_decimal(st->relative_address[0]), /* min */ - (integer_t)bcd_to_decimal(st->relative_address[1]), /* sec */ - (integer_t)bcd_to_decimal(st->relative_address[2])); /* frm */ - } - - tgt->dev_info.cdrom.result_available = TRUE; - return SCSI_RET_SUCCESS; -} - -private scsi_ret_t -toshiba_read_toc( - target_info_t *tgt, - char *cmd, - io_req_t ior) -{ - scsi_command_group_2 c; - toshiba_toc_data_t *t; - toshiba_toc_header_t *th; - char *buf = tgt->dev_info.cdrom.result; - scsi_ret_t rc; - int first, last, i; - - /* TOC header first */ - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_TOSHIBA_READ_TOC_ENTRY; - c.scsi_cmd_lun_and_relbit = 0; - c.scsi_cmd_lba1 = 0; - - rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(*th), ior); - if (rc != SCSI_RET_SUCCESS) return rc; - - th = (toshiba_toc_header_t *) tgt->cmd_ptr; - - first = bcd_to_decimal(th->first_track); - last = bcd_to_decimal(th->last_track); - - /* - * "Get TH" wants summary, "TOC MSF|ABS from_track" wants all - */ - if (cmd[0] == 'G') { - sprintf(buf, "toc header: %d %d %d", - sizeof(*th) + sizeof(*t) * (last - first + 1), - first, last); - goto out; - } - - /* - * The whole shebang - */ - sscanf(&cmd[8], "%d", &i); - sprintf(buf, "TOC from track %d:\n", i); - - while (i <= last) { - bzero(&c, sizeof(c)); - - c.scsi_cmd_code = SCSI_CMD_TOSHIBA_READ_TOC_ENTRY; - c.scsi_cmd_lun_and_relbit = 2; - c.scsi_cmd_lba1 = decimal_to_bcd(i); - - zero_ior( ior ); - rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(*t), ior); - if (rc != SCSI_RET_SUCCESS) break; - - t = (toshiba_toc_data_t *) tgt->cmd_ptr; - - buf += strlen(buf); - if (cmd[4] == 'M') - sprintf(buf, "0 0 %d %d %d %d\n", - i, - bcd_to_decimal(t->address[0]), - bcd_to_decimal(t->address[1]), - bcd_to_decimal(t->address[2])); - else -/* THIS IS WRONG */ - sprintf(buf, "0 0 %d %d\n", - i, - bcd_to_decimal(t->address[0]) * 10000 + - bcd_to_decimal(t->address[1]) * 100 + - bcd_to_decimal(t->address[2])); - i++; - } - - /* Must simulate the lead-out track */ - bzero(&c, sizeof(c)); - - c.scsi_cmd_code = SCSI_CMD_TOSHIBA_READ_TOC_ENTRY; - c.scsi_cmd_lun_and_relbit = 1; - c.scsi_cmd_lba1 = 0; - - zero_ior( ior ); - rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(*t), ior); - if (rc != SCSI_RET_SUCCESS) goto out; - - t = (toshiba_toc_data_t *) tgt->cmd_ptr; - - buf += strlen(buf); - if (cmd[4] == 'M') - sprintf(buf, "0 0 %d %d %d %d\n", - i, - bcd_to_decimal(t->address[0]), - bcd_to_decimal(t->address[1]), - bcd_to_decimal(t->address[2])); - else -/* THIS IS WRONG */ - sprintf(buf, "0 0 %d %d\n", - i, - bcd_to_decimal(t->address[0]) * 10000 + - bcd_to_decimal(t->address[1]) * 100 + - bcd_to_decimal(t->address[2])); - i++; - -out: - tgt->dev_info.cdrom.result_available = TRUE; - return SCSI_RET_SUCCESS; -} - - -private scsi_ret_t -toshiba_play( - target_info_t *tgt, - char *cmd, - io_req_t ior) -{ - scsi_command_group_2 c; - int sm, ss, sf, em, es, ef; - int st, si, et, ei; - scsi_ret_t rc; - - /* - * Seek to desired position - */ - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_TOSHIBA_SEEK_TRK; - - /* - * Play_msf or Play_ti - */ - if (cmd[5] == 'A') { - /* "Play A startM startS startF endM endS endF" */ - - sscanf(&cmd[7], "%d %d %d %d %d %d", - &sm, &ss, &sf, &em, &es, &ef); - - c.scsi_cmd_lba1 = decimal_to_bcd(sm); - c.scsi_cmd_lba2 = decimal_to_bcd(ss); - c.scsi_cmd_lba3 = decimal_to_bcd(sf); - c.scsi_cmd_ctrl_byte = NEC_CTRL_A_MSF; - - } else { - /* "Play TI startT startI endT endI" */ - - sscanf(&cmd[8], "%d %d %d %d", &st, &si, &et, &ei); - - c.scsi_cmd_lba1 = decimal_to_bcd(st); - c.scsi_cmd_lba2 = decimal_to_bcd(si); - c.scsi_cmd_lba3 = 0; - c.scsi_cmd_ctrl_byte = NEC_CTRL_A_TI; - - } - - rc = cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); - if (rc != SCSI_RET_SUCCESS) return rc; - - /* - * Now ask it to play until.. - */ - zero_ior( ior ); - - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_TOSHIBA_PLAY_AUDIO; - c.scsi_cmd_lun_and_relbit = NEC_LR_PLAY_MODE|NEC_LR_STEREO; - - if (cmd[5] == 'A') { - c.scsi_cmd_lba1 = decimal_to_bcd(em); - c.scsi_cmd_lba2 = decimal_to_bcd(es); - c.scsi_cmd_lba3 = decimal_to_bcd(ef); - c.scsi_cmd_ctrl_byte = NEC_CTRL_A_MSF; - } else { - c.scsi_cmd_lba1 = decimal_to_bcd(et); - c.scsi_cmd_lba2 = decimal_to_bcd(ei); - c.scsi_cmd_lba3 = 0; - c.scsi_cmd_ctrl_byte = NEC_CTRL_A_TI; - } - - return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); -} - -private scsi_ret_t -toshiba_pause_resume( - target_info_t *tgt, - char *cmd, - io_req_t ior) -{ - scsi_command_group_2 c; - - bzero(&c, sizeof(c)); - /* - * "Resume" or "Stop" - */ - if (cmd[0] == 'R') { - /* ???? would have to remember last cmd ???? */ -/* broken ! */ - c.scsi_cmd_code = SCSI_CMD_TOSHIBA_PLAY_AUDIO; - c.scsi_cmd_lun_and_relbit = NEC_LR_PLAY_MODE|NEC_LR_STEREO; - c.scsi_cmd_ctrl_byte = NEC_CTRL_A_CURRENT; - } else { - c.scsi_cmd_code = SCSI_CMD_TOSHIBA_PAUSE_AUDIO; - } - - return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); -} - - -#if 0 - /* I have info on these drives, but no drive to test */ - - /* PIONEER DRM-600 */ - -#define SCSI_CMD_PIONEER_EJECT 0xc0 - -#define SCSI_CMD_PIONEER_READ_TOC 0xc1 -typedef struct { - unsigned char first_track; - unsigned char last_track; - unsigned char xxx[2]; -} pioneer_toc_hdr_t; -typedef struct { - unsigned char ctrl; - unsigned char address[3]; -} pioneer_toc_info_t; - -#define SCSI_CMD_PIONEER_READ_SUBCH 0xc2 -typedef struct { - BITFIELD_2(unsigned char, - ctrl : 4, - xxx1 : 4); - unsigned char trackno; - unsigned char indexno; - unsigned char relative_address[3]; - unsigned char absolute_address[3]; -} pioneer_subch_data_t; - -#define SCSI_CMD_PIONEER_SEEK_TRK 0xc8 -#define SCSI_CMD_PIONEER_PLAY_AUDIO 0xc9 -#define SCSI_CMD_PIONEER_PAUSE 0xca - -#define SCSI_CMD_PIONEER_AUDIO_STATUS 0xcc -typedef struct { - unsigned char audio_status; - unsigned char xxx[5]; -} pioneer_status_t; - -/* - * Reserved bits in byte1 - */ -#define PIONEER_LR_END_ADDR 0x10 -#define PIONEER_LR_PAUSE 0x10 -#define PIONEER_LR_RESUME 0x00 - -/* - * Vendor specific bits in the control byte. - */ -#define PIONEER_CTRL_TH 0x00 /* TOC header */ -#define PIONEER_CTRL_TE 0x80 /* one TOC entry */ -#define PIONEER_CTRL_LO 0x40 /* lead-out track info */ - -#define PIONEER_CTRL_A_MSF 0x40 /* min/sec/frame addr */ - -private scsi_ret_t -pioneer_eject( - target_info_t *tgt, - char *cmd, - io_req_t ior) -{ - scsi_command_group_2 c; - - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_PIONEER_EJECT; - - return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); -} - -private scsi_ret_t -pioneer_position( - target_info_t *tgt, - char *cmd, - io_req_t ior) -{ - scsi_command_group_2 c; - scsi_ret_t rc; - char *buf = tgt->dev_info.cdrom.result; - pioneer_subch_data_t *st; - - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_PIONEER_READ_SUBCH; - c.scsi_cmd_xfer_len_2 = sizeof(pioneer_subch_data_t); /* 9 bytes */ - - rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(pioneer_subch_data_t), ior); - if (rc != SCSI_RET_SUCCESS) return rc; - - st = (pioneer_subch_data_t *) tgt->cmd_ptr; - - /* XXX can it do ABS addressing e.g. 'logical' ? */ - - sprintf(buf, "MSF Position %d %d %d %d %d %d", - (integer_t)bcd_to_decimal(st->absolute_address[0]), /* min */ - (integer_t)bcd_to_decimal(st->absolute_address[1]), /* sec */ - (integer_t)bcd_to_decimal(st->absolute_address[2]), /* frm */ - (integer_t)bcd_to_decimal(st->relative_address[0]), /* min */ - (integer_t)bcd_to_decimal(st->relative_address[1]), /* sec */ - (integer_t)bcd_to_decimal(st->relative_address[2])); /* frm */ - - tgt->dev_info.cdrom.result_available = TRUE; - return SCSI_RET_SUCCESS; -} - -private scsi_ret_t -pioneer_toc( - target_info_t *tgt, - char *cmd, - io_req_t ior) -{ - scsi_command_group_2 c; - pioneer_toc_hdr_t *th; - pioneer_toc_info_t *t; - char *buf = tgt->dev_info.cdrom.result; - scsi_ret_t rc; - int first, last, i; - - /* Read header first */ - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_PIONEER_READ_TOC; - c.scsi_cmd_xfer_len_2 = sizeof(pioneer_toc_hdr_t); - c.scsi_cmd_ctrl_byte = PIONEER_CTRL_TH; - - rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(pioneer_toc_hdr_t), ior); - if (rc != SCSI_RET_SUCCESS) return rc; - - th = (pioneer_toc_hdr_t *)tgt->cmd_ptr; - first = bcd_to_decimal(th->first_track); - last = bcd_to_decimal(th->last_track); - - /* - * "Get TH" wants summary, "TOC MSF|ABS from_track" wants all - */ - if (cmd[0] == 'G') { - sprintf(buf, "toc header: %d %d %d", 0, first, last); - goto out; - } - - /* - * Must do it one track at a time - */ - sscanf(&cmd[8], "%d", &i); - sprintf(buf, "TOC from track %d:\n", i); - - for ( ; i <= last; i++) { - zero_ior(ior); - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_PIONEER_READ_TOC; - c.scsi_cmd_lba4 = decimal_to_bcd(i); - c.scsi_cmd_xfer_len_2 = sizeof(pioneer_toc_info_t); - c.scsi_cmd_ctrl_byte = PIONEER_CTRL_TE; - - rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(pioneer_toc_info_t), ior); - if (rc != SCSI_RET_SUCCESS) break; - - t = (pioneer_toc_info_t *)tgt->cmd_ptr; - - buf += strlen(buf); - if (cmd[4] == 'M') - sprintf(buf, "%d %d %d %d %d %d\n", - t->ctrl, 0, i, - bcd_to_decimal(t->address[0]), - bcd_to_decimal(t->address[1]), - bcd_to_decimal(t->address[2])); - else -/* THIS IS WRONG */ - sprintf(buf, "%d %d %d %d\n", - t->ctrl, 0, i, - bcd_to_decimal(t->address[0]) * 10000 + - bcd_to_decimal(t->address[1]) * 100 + - bcd_to_decimal(t->address[2])); - } - /* To know how long the last track is */ - zero_ior(ior); - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_PIONEER_READ_TOC; - c.scsi_cmd_xfer_len_2 = sizeof(pioneer_toc_info_t); - c.scsi_cmd_ctrl_byte = PIONEER_CTRL_LO; - - rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(pioneer_toc_info_t), ior); - if (rc != SCSI_RET_SUCCESS) return rc; - - buf += strlen(buf); - t = (pioneer_toc_info_t *)tgt->cmd_ptr; - if (cmd[4] == 'M') - sprintf(buf, "%d %d %d %d %d %d\n", - t->ctrl, 0, 0xaa /* User expects this */, - bcd_to_decimal(t->address[0]), - bcd_to_decimal(t->address[1]), - bcd_to_decimal(t->address[2])); - else -/* THIS IS WRONG */ - sprintf(buf, "%d %d %d %d\n", - t->ctrl, 0, 0xaa /* User expects this */, - bcd_to_decimal(t->address[0]) * 10000 + - bcd_to_decimal(t->address[1]) * 100 + - bcd_to_decimal(t->address[2])); - -out: - tgt->dev_info.cdrom.result_available = TRUE; - return SCSI_RET_SUCCESS; -} - -private scsi_ret_t -pioneer_status( - target_info_t *tgt, - char *cmd, - io_req_t ior) -{ - scsi_command_group_2 c; - pioneer_status_t *st; - char *buf = tgt->dev_info.cdrom.result; - scsi_ret_t rc; - - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_PIONEER_AUDIO_STATUS; - c.scsi_cmd_xfer_len_2 = sizeof(pioneer_status_t); /* 6 bytes */ - - rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(pioneer_status_t), ior); - if (rc != SCSI_RET_SUCCESS) return rc; - - st = (pioneer_status_t*) tgt->cmd_ptr; - decode_status_1( buf, st->audio_status); - - tgt->dev_info.cdrom.result_available = TRUE; - return SCSI_RET_SUCCESS; -} - -private scsi_ret_t -pioneer_play( - target_info_t *tgt, - char *cmd, - io_req_t ior) -{ - scsi_command_group_2 c; - int sm, ss, sf, em, es, ef; - int st, si, et, ei; - scsi_ret_t rc; - - /* - * Seek to desired position - */ - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_PIONEER_SEEK_TRK; - /* - * Play_msf or Play_ti - */ - if (cmd[5] == 'A') { - /* "Play A startM startS startF endM endS endF" */ - - sscanf(&cmd[7], "%d %d %d %d %d %d", - &sm, &ss, &sf, &em, &es, &ef); - - c.scsi_cmd_lba2 = decimal_to_bcd(sm); - c.scsi_cmd_lba3 = decimal_to_bcd(ss); - c.scsi_cmd_lba4 = decimal_to_bcd(sf); - c.scsi_cmd_ctrl_byte = PIONEER_CTRL_A_MSF; - - } else { - /* "Play TI startT startI endT endI" */ - - sscanf(&cmd[8], "%d %d %d %d", &st, &si, &et, &ei); - - c.scsi_cmd_lba3 = decimal_to_bcd(st); - c.scsi_cmd_lba4 = decimal_to_bcd(si); - c.scsi_cmd_ctrl_byte = 0x80; /* Pure speculation!! */ - - } - - rc = cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); - if (rc != SCSI_RET_SUCCESS) return rc; - - /* - * Now ask it to play until.. - */ - zero_ior( ior ); - - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_PIONEER_PLAY_AUDIO; - c.scsi_cmd_lun_and_relbit = PIONEER_LR_END_ADDR; - - if (cmd[5] == 'A') { - c.scsi_cmd_lba2 = decimal_to_bcd(em); - c.scsi_cmd_lba3 = decimal_to_bcd(es); - c.scsi_cmd_lba4 = decimal_to_bcd(ef); - c.scsi_cmd_ctrl_byte = PIONEER_CTRL_A_MSF; - } else { - c.scsi_cmd_lba3 = decimal_to_bcd(et); - c.scsi_cmd_lba4 = decimal_to_bcd(ei); - c.scsi_cmd_ctrl_byte = 0x80; /* Pure speculation! */ - } - - return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); -} - -private scsi_ret_t -pioneer_pause_resume( - target_info_t *tgt, - char *cmd, - io_req_t ior) -{ - scsi_command_group_2 c; - - bzero(&c, sizeof(c)); - c.scsi_cmd_code = SCSI_CMD_PIONEER_PAUSE; - /* - * "Resume" or "Stop" - */ - if (cmd[0] == 'S') - c.scsi_cmd_lun_and_relbit = PIONEER_LR_PAUSE; - else - c.scsi_cmd_lun_and_relbit = PIONEER_LR_RESUME; - - return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); -} - - /* DENON DRD-253 */ - -#define SCSI_CMD_DENON_PLAY_AUDIO 0x22 -#define SCSI_CMD_DENON_EJECT 0xe6 -#define SCSI_CMD_DENON_PAUSE_AUDIO 0xe7 -#define SCSI_CMD_DENON_READ_TOC 0xe9 -#define SCSI_CMD_DENON_READ_SUBCH 0xeb - - - /* HITACHI 1750 */ - -#define SCSI_CMD_HITACHI_PLAY_AUDIO_MSF 0xe0 -#define SCSI_CMD_HITACHI_PAUSE_AUDIO 0xe1 -#define SCSI_CMD_HITACHI_EJECT 0xe4 -#define SCSI_CMD_HITACHI_READ_SUBCH 0xe5 -#define SCSI_CMD_HITACHI_READ_TOC 0xe8 - -#endif - -/* - * Tabulate all of the above - */ -private red_list_t cdrom_exceptions[] = { - -#if 0 - For documentation purposes, here are some SCSI-2 compliant drives: - - Vendor Product Rev Comments - - "SONY " "CD-ROMCDU-541 " "2.6a" The NeXT drive -#endif - - /* vendor, product, rev */ - /* can_play_audio */ - /* eject */ - /* current_position */ - /* read_toc */ - /* get_status */ - /* play_msf */ - /* play_ti */ - /* pause_resume */ - /* volume_control */ - - /* We have seen a "RRD42(C)DEC " "4.5d" */ - { "DEC ", "RRD42", "", - 0, 0, 0, 0, 0, 0, 0, 0, rrd42_set_volume }, - - /* We have seen a "CD-ROM DRIVE:84 " "1.0 " */ - { "NEC ", "CD-ROM DRIVE:84", "", - op_not_supported, nec_eject, nec_subchannel, nec_read_toc, - nec_subchannel, nec_play, nec_play, nec_pause_resume, - op_not_supported }, - - /* We have seen a "CD-ROM DRIVE:XM " "3232" */ - { "TOSHIBA ", "CD-ROM DRIVE:XM", "32", - op_not_supported, toshiba_eject, toshiba_subchannel, toshiba_read_toc, - toshiba_subchannel, toshiba_play, toshiba_play, toshiba_pause_resume, - op_not_supported }, - - { "TOSHIBA ", "CD-ROM DRIVE:XM", "33", - op_not_supported, toshiba_eject, toshiba_subchannel, toshiba_read_toc, - toshiba_subchannel, toshiba_play, toshiba_play, toshiba_pause_resume, - op_not_supported }, - -#if 0 - { "PIONEER ", "???????DRM-6", "", - op_not_supported, pioneer_eject, pioneer_position, pioneer_toc, - pioneer_status, pioneer_play, pioneer_play, pioneer_pause_resume, - op_not_supported }, - - { "DENON ", "DRD 25X", "", ...}, - { "HITACHI ", "CDR 1750S", "", ...}, - { "HITACHI ", "CDR 1650S", "", ...}, - { "HITACHI ", "CDR 3650", "", ...}, - -#endif - - /* Zero terminate this list */ - { 0, } -}; - -private void -check_red_list( - target_info_t *tgt, - scsi2_inquiry_data_t *inq) - -{ - red_list_t *list; - - for (list = &cdrom_exceptions[0]; list->vendor; list++) { - - /* - * Prefix-Match all strings - */ - if ((strncmp(list->vendor, (const char *)inq->vendor_id, - strlen(list->vendor)) == 0) && - (strncmp(list->product, (const char *)inq->product_id, - strlen(list->product)) == 0) && - (strncmp(list->rev, (const char *)inq->product_rev, - strlen(list->rev)) == 0)) { - /* - * One of them.. - */ - if (tgt->dev_info.cdrom.violates_standards != list) { - tgt->dev_info.cdrom.violates_standards = list; - curse_the_vendor( list, TRUE ); - } - return; - } - } -} -#endif /* NSCSI > 0 */ |