|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1993 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: /* ! 27: * File: rz_audio.c ! 28: * Author: Alessandro Forin, Carnegie Mellon University ! 29: * Date: 3/93 ! 30: * ! 31: * Top layer of the SCSI driver: interface with the MI. ! 32: * This file contains operations specific to audio CD-ROM devices. ! 33: * Unlike many others, it sits on top of the rz.c module. ! 34: */ ! 35: ! 36: #include <mach/std_types.h> ! 37: #include <kern/strings.h> ! 38: #include <machine/machspl.h> /* spl definitions */ ! 39: #include <vm/vm_kern.h> ! 40: #include <device/ds_routines.h> ! 41: ! 42: #include <scsi/compat_30.h> ! 43: #include <scsi/scsi.h> ! 44: #include <scsi/scsi2.h> ! 45: #include <scsi/scsi_defs.h> ! 46: #include <scsi/rz.h> ! 47: ! 48: #if (NSCSI > 0) ! 49: ! 50: #define private static ! 51: ! 52: /* some data is two BCD digits in one byte */ ! 53: #define bcd_to_decimal(b) (((b)&0xf) + 10 * (((b) >> 4) & 0xf)) ! 54: #define decimal_to_bcd(b) ((((b) / 10) << 4) | ((b) % 10)) ! 55: ! 56: /* ! 57: * Regular use of a CD-ROM is for data, and is handled ! 58: * by the default set of operations. Ours is for funtime.. ! 59: */ ! 60: ! 61: extern char *sccdrom_name(); ! 62: int cd_strategy(); ! 63: void cd_start(); ! 64: ! 65: private scsi_devsw_t scsi_audio = { ! 66: sccdrom_name, 0, 0, 0, cd_strategy, cd_start, 0, 0 ! 67: }; ! 68: ! 69: private char unsupported[] = "Device does not support it."; ! 70: ! 71: /* ! 72: * Unfortunately, none of the vendors appear to ! 73: * abide by the SCSI-2 standard and many of them ! 74: * violate or stretch even the SCSI-1 one. ! 75: * Therefore, we keep a red-list here of the worse ! 76: * offendors and how to deal with them. ! 77: * The user is notified of the problem and invited ! 78: * to solicit his vendor to upgrade the firmware. ! 79: * [They had plenty of time to do so] ! 80: */ ! 81: typedef struct red_list { ! 82: char *vendor; ! 83: char *product; ! 84: char *rev; ! 85: /* ! 86: * The standard MANDATES [par 13.1.6] the play_audio command ! 87: * at least as a way to discover if the device ! 88: * supports audio operations at all. This is the only way ! 89: * we need to use it. ! 90: */ ! 91: scsi_ret_t (*can_play_audio)( target_info_t *, char *, io_req_t); ! 92: /* ! 93: * The standard defines the use of start_stop_unit to ! 94: * cause the drive to eject the disk. ! 95: */ ! 96: scsi_ret_t (*eject)( target_info_t *, char *, io_req_t ); ! 97: /* ! 98: * The standard defines read_subchannel as a way to ! 99: * get the current playing position. ! 100: */ ! 101: scsi_ret_t (*current_position)( target_info_t *, char *, io_req_t ); ! 102: /* ! 103: * The standard defines read_table_of_content to get ! 104: * the listing of audio tracks available. ! 105: */ ! 106: scsi_ret_t (*read_toc)( target_info_t *, char *, io_req_t ); ! 107: /* ! 108: * The standard defines read_subchannel as the way to ! 109: * report the current audio status (playing/stopped/...). ! 110: */ ! 111: scsi_ret_t (*get_status)( target_info_t *, char *, io_req_t ); ! 112: /* ! 113: * The standard defines two ways to issue a play command, ! 114: * depending on the type of addressing used. ! 115: */ ! 116: scsi_ret_t (*play_msf)( target_info_t *, char *, io_req_t ); ! 117: scsi_ret_t (*play_ti)( target_info_t *, char *, io_req_t ); ! 118: /* ! 119: * The standard defines the pause_resume command to ! 120: * suspend or resume playback of audio data. ! 121: */ ! 122: scsi_ret_t (*pause_resume)( target_info_t *, char *, io_req_t ); ! 123: /* ! 124: * The standard defines the audio page among the ! 125: * mode selection options as a way to control ! 126: * both volume and connectivity of the channels ! 127: */ ! 128: scsi_ret_t (*volume_control)( target_info_t *, char *, io_req_t ); ! 129: } red_list_t; ! 130: ! 131: #define if_it_can_do(some_cmd) \ ! 132: if (tgt->dev_info.cdrom.violates_standards && \ ! 133: tgt->dev_info.cdrom.violates_standards->some_cmd) \ ! 134: rc = (*tgt->dev_info.cdrom.violates_standards->some_cmd) \ ! 135: (tgt,cmd,ior); \ ! 136: else ! 137: ! 138: /* ! 139: * So now that you know what they should have implemented :-), ! 140: * check at the end of the file what the naughty boys did instead. ! 141: */ ! 142: /* private red_list_t audio_replacements[]; / * at end */ ! 143: ! 144: /* ! 145: * Forward decls ! 146: */ ! 147: private void decode_status( char *buf, unsigned char audio_status ); ! 148: void zero_ior( io_req_t ); ! 149: ! 150: /* ! 151: * Open routine. Does some checking, sets up ! 152: * the replacement pointer. ! 153: */ ! 154: io_return_t ! 155: cd_open( ! 156: int dev, ! 157: dev_mode_t mode, ! 158: io_req_t req) ! 159: { ! 160: scsi_softc_t *sc = 0; ! 161: target_info_t *tgt; ! 162: int ret; ! 163: scsi_ret_t rc; ! 164: io_req_t ior = 0; ! 165: vm_offset_t mem = 0; ! 166: extern boolean_t rz_check(); ! 167: ! 168: if (!rz_check(dev, &sc, &tgt)) { ! 169: /* ! 170: * Probe it again: might have installed a new device ! 171: */ ! 172: if (!sc || !scsi_probe(sc, &tgt, rzslave(dev), ior)) ! 173: return D_NO_SUCH_DEVICE; ! 174: bzero(&tgt->dev_info, sizeof(tgt->dev_info)); ! 175: } ! 176: ! 177: /* ! 178: * Check this is indeded a CD-ROM ! 179: */ ! 180: if (tgt->dev_ops != &scsi_devsw[SCSI_CDROM]) { ! 181: rz_close(dev); ! 182: return D_NO_SUCH_DEVICE; ! 183: } ! 184: ! 185: /* ! 186: * Switch to audio ops, unless some wrong ! 187: */ ! 188: tgt->dev_ops = &scsi_audio; ! 189: ! 190: /* ! 191: * Bring unit online ! 192: */ ! 193: ret = rz_open(dev, mode, req); ! 194: if (ret) goto bad; ! 195: ! 196: /* Pessimistic */ ! 197: ret = D_INVALID_OPERATION; ! 198: ! 199: /* ! 200: * Check if this device is on the red list ! 201: */ ! 202: { ! 203: scsi2_inquiry_data_t *inq; ! 204: private void check_red_list(); ! 205: ! 206: scsi_inquiry(tgt, SCSI_INQ_STD_DATA); ! 207: inq = (scsi2_inquiry_data_t*)tgt->cmd_ptr; ! 208: ! 209: check_red_list( tgt, inq ); ! 210: ! 211: } ! 212: ! 213: /* ! 214: * Allocate dynamic data ! 215: */ ! 216: if (kmem_alloc(kernel_map, &mem, PAGE_SIZE) != KERN_SUCCESS) ! 217: return D_NO_MEMORY; ! 218: tgt->dev_info.cdrom.result = (void *)mem; ! 219: tgt->dev_info.cdrom.result_available = FALSE; ! 220: ! 221: /* ! 222: * See if this CDROM can play audio data ! 223: */ ! 224: io_req_alloc(ior,0); ! 225: zero_ior( ior ); ! 226: ! 227: { ! 228: char *cmd = 0; ! 229: if_it_can_do(can_play_audio) ! 230: rc = scsi_play_audio( tgt, 0, 0, FALSE, ior); ! 231: } ! 232: ! 233: if (rc != SCSI_RET_SUCCESS) goto bad; ! 234: ! 235: io_req_free(ior); ! 236: return D_SUCCESS; ! 237: ! 238: bad: ! 239: if (ior) io_req_free(ior); ! 240: if (mem) kmem_free(kernel_map, mem, PAGE_SIZE); ! 241: tgt->dev_ops = &scsi_devsw[SCSI_CDROM]; ! 242: return ret; ! 243: } ! 244: ! 245: /* ! 246: * Close routine. ! 247: */ ! 248: io_return_t ! 249: cd_close( ! 250: int dev) ! 251: { ! 252: scsi_softc_t *sc; ! 253: target_info_t *tgt; ! 254: vm_offset_t mem; ! 255: ! 256: if (!rz_check(dev, &sc, &tgt)) ! 257: return D_NO_SUCH_DEVICE; ! 258: if (!tgt || (tgt->dev_ops != &scsi_audio)) ! 259: return D_NO_SUCH_DEVICE; ! 260: ! 261: /* ! 262: * Cleanup state ! 263: */ ! 264: mem = (vm_offset_t) tgt->dev_info.cdrom.result; ! 265: tgt->dev_info.cdrom.result = (void *)0; ! 266: tgt->dev_info.cdrom.result_available = FALSE; ! 267: ! 268: (void) kmem_free(kernel_map, mem, PAGE_SIZE); ! 269: ! 270: (void) rz_close(dev); ! 271: ! 272: tgt->dev_ops = &scsi_devsw[SCSI_CDROM]; ! 273: return D_SUCCESS; ! 274: } ! 275: ! 276: /* ! 277: * Write routine. It is passed an ASCII string ! 278: * with the command to be executed. ! 279: */ ! 280: io_return_t ! 281: cd_write( ! 282: int dev, ! 283: io_req_t ior) ! 284: { ! 285: register kern_return_t rc; ! 286: boolean_t wait = FALSE; ! 287: io_return_t ret; ! 288: int count; ! 289: register char *data; ! 290: vm_offset_t addr; ! 291: ! 292: data = ior->io_data; ! 293: count = ior->io_count; ! 294: if (count == 0) ! 295: return D_SUCCESS; ! 296: ! 297: if (!(ior->io_op & IO_INBAND)) { ! 298: /* ! 299: * Copy out-of-line data into kernel address space. ! 300: * Since data is copied as page list, it will be ! 301: * accessible. ! 302: */ ! 303: vm_map_copy_t copy = (vm_map_copy_t) data; ! 304: kern_return_t kr; ! 305: ! 306: kr = vm_map_copyout(device_io_map, &addr, copy); ! 307: if (kr != KERN_SUCCESS) ! 308: return kr; ! 309: data = (char *) addr; ! 310: } ! 311: ! 312: if (scsi_debug) printf("Got command '%s'\n", data); ! 313: ! 314: ret = cd_command( dev, data, count, ior); ! 315: ! 316: if (!(ior->io_op & IO_INBAND)) ! 317: (void) vm_deallocate(device_io_map, addr, ior->io_count); ! 318: return D_SUCCESS; ! 319: } ! 320: ! 321: /* ! 322: * Read routine. Returns an ASCII string with the results ! 323: * of the last command executed. ! 324: */ ! 325: io_return_t ! 326: cd_read( ! 327: int dev, ! 328: io_req_t ior) ! 329: { ! 330: target_info_t *tgt; ! 331: kern_return_t rc; ! 332: natural_t count; ! 333: ! 334: /* ! 335: * Allocate memory for read buffer. ! 336: */ ! 337: count = (natural_t)ior->io_count; ! 338: if (count > PAGE_SIZE) ! 339: return D_INVALID_SIZE; /* sanity */ ! 340: ! 341: rc = device_read_alloc(ior, count); ! 342: if (rc != KERN_SUCCESS) ! 343: return rc; ! 344: ! 345: if (scsi_debug) printf("Got read req for %d bytes\n", count); ! 346: ! 347: /* ! 348: * See if last cmd left some to say ! 349: */ ! 350: tgt = scsi_softc[rzcontroller(dev)]->target[rzslave(dev)]; ! 351: if (tgt->dev_info.cdrom.result_available) { ! 352: int len; ! 353: ! 354: tgt->dev_info.cdrom.result_available = FALSE; ! 355: len = strlen(tgt->dev_info.cdrom.result)+1; ! 356: ! 357: if (count > len) ! 358: count = len; ! 359: bcopy(tgt->dev_info.cdrom.result, ior->io_data, count); ! 360: ! 361: } else { ! 362: # define noway "No results pending" ! 363: count = (count > sizeof(noway)) ? sizeof(noway) : count; ! 364: bcopy(noway, ior->io_data, count); ! 365: } ! 366: ! 367: ior->io_residual = ior->io_count - count; ! 368: return D_SUCCESS; ! 369: } ! 370: ! 371: /* ! 372: * This does all the work ! 373: */ ! 374: io_return_t ! 375: cd_command( ! 376: int dev, ! 377: char *cmd, ! 378: int count, ! 379: io_req_t req) ! 380: { ! 381: target_info_t *tgt; ! 382: io_req_t ior; ! 383: io_return_t ret = D_INVALID_OPERATION; ! 384: scsi_ret_t rc; ! 385: char *buf; ! 386: ! 387: tgt = scsi_softc[rzcontroller(dev)]->target[rzslave(dev)]; ! 388: ! 389: buf = tgt->dev_info.cdrom.result; ! 390: tgt->dev_info.cdrom.result_available = FALSE; ! 391: ! 392: io_req_alloc(ior,0); ! 393: zero_ior( ior ); ! 394: ! 395: switch (cmd[0]) { ! 396: ! 397: case 'E': ! 398: /* "Eject" */ ! 399: /* too many dont support it. Sigh */ ! 400: tgt->flags |= TGT_OPTIONAL_CMD; ! 401: (void) scsi_medium_removal( tgt, TRUE, ior); ! 402: tgt->flags &= ~TGT_OPTIONAL_CMD; ! 403: ! 404: zero_ior( ior ); ! 405: ! 406: if_it_can_do(eject) ! 407: rc = scsi_start_unit(tgt, SCSI_CMD_SS_EJECT, ior); ! 408: break; ! 409: ! 410: case 'G': ! 411: switch (cmd[4]) { ! 412: ! 413: case 'P': ! 414: /* "Get Position MSF|ABS" */ ! 415: if_it_can_do(current_position) { ! 416: rc = scsi_read_subchannel(tgt, ! 417: cmd[13] == 'M', ! 418: SCSI_CMD_RS_FMT_CURPOS, ! 419: 0, ! 420: ior); ! 421: if (rc == SCSI_RET_SUCCESS) { ! 422: cdrom_chan_curpos_t *st; ! 423: st = (cdrom_chan_curpos_t *)tgt->cmd_ptr; ! 424: if (cmd[13] == 'M') ! 425: sprintf(buf, "MSF Position %d %d %d %d %d %d", ! 426: (integer_t)st->subQ.absolute_address.msf.minute, ! 427: (integer_t)st->subQ.absolute_address.msf.second, ! 428: (integer_t)st->subQ.absolute_address.msf.frame, ! 429: (integer_t)st->subQ.relative_address.msf.minute, ! 430: (integer_t)st->subQ.relative_address.msf.second, ! 431: (integer_t)st->subQ.relative_address.msf.frame); ! 432: else ! 433: sprintf(buf, "ABS Position %d %d", (integer_t) ! 434: (st->subQ.absolute_address.lba.lba1<<24)+ ! 435: (st->subQ.absolute_address.lba.lba2<<16)+ ! 436: (st->subQ.absolute_address.lba.lba3<< 8)+ ! 437: st->subQ.absolute_address.lba.lba4, ! 438: (integer_t) ! 439: (st->subQ.relative_address.lba.lba1<<24)+ ! 440: (st->subQ.relative_address.lba.lba2<<16)+ ! 441: (st->subQ.relative_address.lba.lba3<< 8)+ ! 442: st->subQ.relative_address.lba.lba4); ! 443: tgt->dev_info.cdrom.result_available = TRUE; ! 444: } ! 445: } ! 446: break; ! 447: ! 448: case 'T': ! 449: /* "Get TH" */ ! 450: if_it_can_do(read_toc) { ! 451: rc = scsi_read_toc(tgt, TRUE, 1, PAGE_SIZE, ior); ! 452: if (rc == SCSI_RET_SUCCESS) { ! 453: cdrom_toc_t *toc = (cdrom_toc_t *)tgt->cmd_ptr; ! 454: sprintf(buf, "toc header: %d %d %d", ! 455: (toc->len1 << 8) + toc->len2, ! 456: toc->first_track, ! 457: toc->last_track); ! 458: tgt->dev_info.cdrom.result_available = TRUE; ! 459: } ! 460: } ! 461: break; ! 462: ! 463: case 'S': ! 464: /* "Get Status" */ ! 465: if_it_can_do(get_status) { ! 466: rc = scsi_read_subchannel(tgt, ! 467: TRUE, ! 468: SCSI_CMD_RS_FMT_CURPOS, ! 469: 0, ! 470: ior); ! 471: if (rc == SCSI_RET_SUCCESS) { ! 472: cdrom_chan_curpos_t *st; ! 473: st = (cdrom_chan_curpos_t *)tgt->cmd_ptr; ! 474: decode_status(buf, st->audio_status); ! 475: tgt->dev_info.cdrom.result_available = TRUE; ! 476: } ! 477: } ! 478: break; ! 479: } ! 480: break; ! 481: ! 482: case 'P': ! 483: switch (cmd[5]) { ! 484: case 'A': ! 485: /* "Play A startM startS startF endM endS endF" */ ! 486: if_it_can_do(play_msf) { ! 487: ! 488: int sm, ss, sf, em, es, ef; ! 489: ! 490: sscanf(&cmd[7], "%d %d %d %d %d %d", ! 491: &sm, &ss, &sf, &em, &es, &ef); ! 492: ! 493: rc = scsi_play_audio_msf(tgt, ! 494: sm, ss, sf, ! 495: em, es, ef, ! 496: ior); ! 497: } ! 498: break; ! 499: ! 500: case 'T': ! 501: /* "Play TI startT startI endT endI" */ ! 502: if_it_can_do(play_ti) { ! 503: ! 504: int st, si, et, ei; ! 505: ! 506: sscanf(&cmd[8], "%d %d %d %d", ! 507: &st, &si, &et, &ei); ! 508: ! 509: rc = scsi_play_audio_track_index(tgt, ! 510: st, si, et, ei, ior); ! 511: } ! 512: break; ! 513: } ! 514: break; ! 515: ! 516: case 'R': ! 517: /* "Resume" */ ! 518: if_it_can_do(pause_resume) ! 519: rc = scsi_pause_resume(tgt, FALSE, ior); ! 520: break; ! 521: ! 522: case 'S': ! 523: switch (cmd[2]) { ! 524: ! 525: case 'a': ! 526: /* "Start" */ ! 527: rc = scsi_start_unit(tgt, SCSI_CMD_SS_START, ior); ! 528: break; ! 529: ! 530: case 'o': ! 531: /* "Stop" */ ! 532: if_it_can_do(pause_resume) ! 533: rc = scsi_pause_resume(tgt, TRUE, ior); ! 534: break; ! 535: ! 536: case 't': ! 537: /* "Set V chan0vol chan1vol chan2vol chan3vol" */ ! 538: if_it_can_do(volume_control) { ! 539: ! 540: int v0, v1, v2, v3; ! 541: cdrom_audio_page_t au, *aup; ! 542: ! 543: rc = scsi_mode_sense(tgt, ! 544: SCSI_CD_AUDIO_PAGE, ! 545: sizeof(au), ! 546: ior); ! 547: if (rc == SCSI_RET_SUCCESS) { ! 548: ! 549: sscanf(&cmd[6], "%d %d %d %d", ! 550: &v0, &v1, &v2, &v3); ! 551: ! 552: aup = (cdrom_audio_page_t *) tgt->cmd_ptr; ! 553: au = *aup; ! 554: /* au.h.bdesc ... */ ! 555: au.vol0 = v0; ! 556: au.vol1 = v1; ! 557: au.vol2 = v2; ! 558: au.vol3 = v3; ! 559: au.imm = 1; ! 560: au.aprv = 0; ! 561: ! 562: zero_ior( ior ); ! 563: ! 564: rc = scsi2_mode_select(tgt, FALSE, ! 565: &au, sizeof(au), ior); ! 566: } ! 567: } ! 568: break; ! 569: } ! 570: break; ! 571: ! 572: case 'T': ! 573: /* "Toc MSF|ABS trackno" */ ! 574: if_it_can_do(read_toc) { ! 575: ! 576: int t, m; ! 577: ! 578: sscanf(&cmd[8], "%d", &t); ! 579: rc = scsi_read_toc( tgt, cmd[4]=='M', t, PAGE_SIZE, ior); ! 580: ! 581: if (rc == SCSI_RET_SUCCESS) { ! 582: ! 583: cdrom_toc_t *toc = (cdrom_toc_t *)tgt->cmd_ptr; ! 584: ! 585: sprintf(buf, "TOC from track %d:\n", t); ! 586: m = (toc->len1 << 8) + toc->len2; ! 587: m -= 4; /* header */ ! 588: for (t = 0; m > 0; t++, m -= sizeof(struct cdrom_toc_desc)) { ! 589: buf += strlen(buf); ! 590: if (cmd[4] == 'M') ! 591: sprintf(buf, "%d %d %d %d %d %d\n", ! 592: toc->descs[t].control, ! 593: toc->descs[t].adr, ! 594: toc->descs[t].trackno, ! 595: (integer_t)toc->descs[t].absolute_address.msf.minute, ! 596: (integer_t)toc->descs[t].absolute_address.msf.second, ! 597: (integer_t)toc->descs[t].absolute_address.msf.frame); ! 598: else ! 599: sprintf(buf, "%d %d %d %d\n", ! 600: toc->descs[t].control, ! 601: toc->descs[t].adr, ! 602: toc->descs[t].trackno, ! 603: (toc->descs[t].absolute_address.lba.lba1<<24)+ ! 604: (toc->descs[t].absolute_address.lba.lba2<<16)+ ! 605: (toc->descs[t].absolute_address.lba.lba3<<8)+ ! 606: toc->descs[t].absolute_address.lba.lba4); ! 607: } ! 608: tgt->dev_info.cdrom.result_available = TRUE; ! 609: } ! 610: } ! 611: break; ! 612: } ! 613: ! 614: if (rc == SCSI_RET_SUCCESS) ! 615: ret = D_SUCCESS; ! 616: ! 617: /* We are stateless, but.. */ ! 618: if (rc == SCSI_RET_NEED_SENSE) { ! 619: zero_ior( ior ); ! 620: tgt->ior = ior; ! 621: scsi_request_sense(tgt, ior, 0); ! 622: iowait(ior); ! 623: if (scsi_check_sense_data(tgt, tgt->cmd_ptr)) ! 624: scsi_print_sense_data(tgt->cmd_ptr); ! 625: } ! 626: ! 627: io_req_free(ior); ! 628: return ret; ! 629: } ! 630: ! 631: private char st_invalid [] = "Drive would not say"; ! 632: private char st_playing [] = "Playing"; ! 633: private char st_paused [] = "Suspended"; ! 634: private char st_complete[] = "Done playing"; ! 635: private char st_error [] = "Stopped in error"; ! 636: private char st_nothing [] = "Idle"; ! 637: ! 638: private void ! 639: decode_status( ! 640: char *buf, ! 641: unsigned char audio_status) ! 642: { ! 643: switch (audio_status) { ! 644: case SCSI_CDST_INVALID: ! 645: sprintf(buf, st_invalid); break; ! 646: case SCSI_CDST_PLAYING: ! 647: sprintf(buf, st_playing); break; ! 648: case SCSI_CDST_PAUSED: ! 649: sprintf(buf, st_paused); break; ! 650: case SCSI_CDST_COMPLETED: ! 651: sprintf(buf, st_complete); break; ! 652: case SCSI_CDST_ERROR: ! 653: sprintf(buf, st_error); break; ! 654: case SCSI_CDST_NO_STATUS: ! 655: sprintf(buf, st_nothing); break; ! 656: } ! 657: } ! 658: ! 659: /* some vendor specific use this instead */ ! 660: private void ! 661: decode_status_1( ! 662: char *buf, ! 663: unsigned char audio_status) ! 664: { ! 665: switch (audio_status) { ! 666: case 0: sprintf(buf, st_playing ); break; ! 667: case 1: ! 668: case 2: sprintf(buf, st_paused ); break; ! 669: case 3: sprintf(buf, st_complete ); break; ! 670: default: ! 671: sprintf(buf, "Unknown status" ); break; ! 672: } ! 673: } ! 674: ! 675: ! 676: private void ! 677: curse_the_vendor( ! 678: red_list_t *list, ! 679: boolean_t not_really) ! 680: { ! 681: if (not_really) return; ! 682: ! 683: printf("%s\n%s\n%s\n%s\n", ! 684: "The CDROM you use is not fully SCSI-2 compliant.", ! 685: "We invite You to contact Your vendor and ask", ! 686: "that they provide You with a firmware upgrade.", ! 687: "Here is a list of some known deficiencies"); ! 688: ! 689: printf("Vendor: %s Product: %s.. Revision: %s..\n", ! 690: list->vendor, list->product, list->rev); ! 691: ! 692: #define check(x,y,z) \ ! 693: if (list->x) printf("Command code x%x %s not supported\n", y, z); ! 694: ! 695: check(can_play_audio, SCSI_CMD_PLAY_AUDIO, "PLAY_AUDIO"); ! 696: check(eject, SCSI_CMD_START_STOP_UNIT, ! 697: "START_STOP_UNIT, flag EJECT(0x2) in byte 5"); ! 698: check(current_position, SCSI_CMD_READ_SUBCH, "READ_SUBCHANNEL"); ! 699: check(read_toc, SCSI_CMD_READ_TOC, "READ_TOC"); ! 700: /* check(get_status, ...); duplicate of current_position */ ! 701: check(play_msf, SCSI_CMD_PLAY_AUDIO_MSF, "PLAY_AUDIO_MSF"); ! 702: check(play_ti, SCSI_CMD_PLAY_AUDIO_TI, "PLAY_AUDIO_TRACK_INDEX"); ! 703: check(pause_resume, SCSI_CMD_PAUSE_RESUME, "PAUSE_RESUME"); ! 704: check(volume_control, SCSI_CMD_MODE_SELECT, ! 705: "MODE_SELECT, AUDIO page(0xe)"); ! 706: ! 707: #undef check ! 708: printf("Will work around these problems...\n"); ! 709: } ! 710: ! 711: /* ! 712: * Ancillaries ! 713: */ ! 714: cd_strategy(ior) ! 715: register io_req_t ior; ! 716: { ! 717: return rz_simpleq_strategy( ior, cd_start); ! 718: } ! 719: ! 720: void cd_start( tgt, done) ! 721: target_info_t *tgt; ! 722: boolean_t done; ! 723: { ! 724: io_req_t ior; ! 725: ! 726: ior = tgt->ior; ! 727: if (done && ior) { ! 728: tgt->ior = 0; ! 729: iodone(ior); ! 730: return; ! 731: } ! 732: panic("cd start"); /* uhu? */ ! 733: } ! 734: ! 735: /* ! 736: * When the hardware cannot ! 737: */ ! 738: private scsi_ret_t ! 739: op_not_supported( ! 740: target_info_t *tgt, ! 741: char *cmd, ! 742: io_req_t ior) ! 743: { ! 744: /* ! 745: * The command is not implemented, no way around it ! 746: */ ! 747: sprintf(tgt->dev_info.cdrom.result, unsupported); ! 748: tgt->dev_info.cdrom.result_available = TRUE; ! 749: return SCSI_RET_SUCCESS; ! 750: } ! 751: ! 752: /****************************************/ ! 753: /* Vendor Specific Operations */ ! 754: /****************************************/ ! 755: ! 756: /* DEC RRD42 */ ! 757: ! 758: #define SCSI_CMD_DEC_SET_ADDRESS_FORMAT 0xc0 ! 759: # define scsi_cmd_saf_fmt scsi_cmd_xfer_len_2 ! 760: ! 761: #define SCSI_CMD_DEC_PLAYBACK_STATUS 0xc4 ! 762: typedef struct { ! 763: unsigned char xxx; ! 764: BITFIELD_2(unsigned char, ! 765: is_msf: 1, ! 766: xxx1: 7); ! 767: unsigned char data_len1; ! 768: unsigned char data_len0; ! 769: unsigned char audio_status; ! 770: BITFIELD_2(unsigned char, ! 771: control : 4, ! 772: xxx2 : 4); ! 773: cdrom_addr_t address; ! 774: BITFIELD_2(unsigned char, ! 775: chan0_select : 4, ! 776: xxx3 : 4); ! 777: unsigned char chan0_volume; ! 778: BITFIELD_2(unsigned char, ! 779: chan1_select : 4, ! 780: xxx4 : 4); ! 781: unsigned char chan1_volume; ! 782: BITFIELD_2(unsigned char, ! 783: chan2_select : 4, ! 784: xxx5 : 4); ! 785: unsigned char chan2_volume; ! 786: BITFIELD_2(unsigned char, ! 787: chan3_select : 4, ! 788: xxx6 : 4); ! 789: unsigned char chan3_volume; ! 790: } dec_playback_status_t; ! 791: ! 792: #define SCSI_CMD_DEC_PLAYBACK_CONTROL 0xc9 ! 793: typedef struct { ! 794: unsigned char xxx0; ! 795: BITFIELD_2(unsigned char, ! 796: fmt : 1, ! 797: xxx1 : 7); ! 798: unsigned char xxx[8]; ! 799: BITFIELD_2(unsigned char, ! 800: chan0_select : 4, ! 801: xxx3 : 4); ! 802: unsigned char chan0_volume; ! 803: BITFIELD_2(unsigned char, ! 804: chan1_select : 4, ! 805: xxx4 : 4); ! 806: unsigned char chan1_volume; ! 807: BITFIELD_2(unsigned char, ! 808: chan2_select : 4, ! 809: xxx5 : 4); ! 810: unsigned char chan2_volume; ! 811: BITFIELD_2(unsigned char, ! 812: chan3_select : 4, ! 813: xxx6 : 4); ! 814: unsigned char chan3_volume; ! 815: } dec_playback_control_t; ! 816: ! 817: ! 818: #if 0 ! 819: ! 820: private scsi_ret_t ! 821: rrd42_status( ! 822: target_info_t *tgt, ! 823: char *cmd, ! 824: io_req_t ior) ! 825: { ! 826: scsi_ret_t rc; ! 827: char *buf = tgt->dev_info.cdrom.result; ! 828: scsi_command_group_2 c; ! 829: dec_playback_status_t *st; ! 830: ! 831: /* We might have to specify addressing fmt */ ! 832: if (cmd[4] == 'P') { ! 833: scsi_command_group_2 saf; ! 834: ! 835: bzero(&saf, sizeof(saf)); ! 836: saf.scsi_cmd_code = SCSI_CMD_DEC_SET_ADDRESS_FORMAT; ! 837: saf.scsi_cmd_saf_fmt = (cmd[13] == 'A') ? 0 : 1; ! 838: ! 839: rc = cdrom_vendor_specific(tgt, &saf, 0, 0, 0, ior); ! 840: ! 841: if (rc != SCSI_RET_SUCCESS) return rc; ! 842: ! 843: zero_ior( ior ); ! 844: } ! 845: ! 846: bzero(&c, sizeof(c)); ! 847: c.scsi_cmd_code = SCSI_CMD_DEC_PLAYBACK_STATUS; ! 848: c.scsi_cmd_xfer_len_2 = sizeof(*st); ! 849: rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(*st), ior); ! 850: ! 851: if (rc != SCSI_RET_SUCCESS) return rc; ! 852: ! 853: st = (dec_playback_status_t *) tgt->cmd_ptr; ! 854: ! 855: if (cmd[4] == 'S') ! 856: decode_status( buf, st->audio_status+0x11 ); ! 857: else { ! 858: if (st->is_msf) ! 859: sprintf(buf, "MSF Position %d %d %d", ! 860: (integer_t)st->address.msf.minute, ! 861: (integer_t)st->address.msf.second, ! 862: (integer_t)st->address.msf.frame); ! 863: else ! 864: sprintf(buf, "ABS Position %d", (integer_t) ! 865: (st->address.lba.lba1<<24)+ ! 866: (st->address.lba.lba2<<16)+ ! 867: (st->address.lba.lba3<< 8)+ ! 868: st->address.lba.lba4); ! 869: } ! 870: tgt->dev_info.cdrom.result_available = TRUE; ! 871: return rc; ! 872: } ! 873: #endif ! 874: ! 875: private scsi_ret_t ! 876: rrd42_set_volume( ! 877: target_info_t *tgt, ! 878: char *cmd, ! 879: io_req_t ior) ! 880: { ! 881: scsi_command_group_2 c; ! 882: dec_playback_control_t req; ! 883: int v0, v1, v2, v3; ! 884: ! 885: sscanf(&cmd[6], "%d %d %d %d", &v0, &v1, &v2, &v3); ! 886: ! 887: bzero(&c, sizeof(c)); ! 888: c.scsi_cmd_code = SCSI_CMD_DEC_PLAYBACK_CONTROL; ! 889: c.scsi_cmd_xfer_len_2 = sizeof(req); ! 890: bzero(&req, sizeof(req)); ! 891: if (v0) { ! 892: req.chan0_select = 1; ! 893: req.chan0_volume = v0; ! 894: } ! 895: if (v1) { ! 896: req.chan1_select = 2; ! 897: req.chan1_volume = v1; ! 898: } ! 899: if (v2) { ! 900: req.chan2_select = 4; ! 901: req.chan2_volume = v2; ! 902: } ! 903: if (v3) { ! 904: req.chan3_select = 8; ! 905: req.chan3_volume = v3; ! 906: } ! 907: return cdrom_vendor_specific(tgt, &c, &req, sizeof(req), 0, ior); ! 908: } ! 909: ! 910: /* NEC CD-ROM */ ! 911: ! 912: #define SCSI_CMD_NEC_READ_TOC 0xde ! 913: typedef struct { ! 914: unsigned char xxx[9]; ! 915: unsigned char first_track; ! 916: unsigned char xxx1[9]; ! 917: unsigned char last_track; ! 918: unsigned char xxx2[9]; ! 919: unsigned char lead_out_addr[3]; ! 920: struct { ! 921: BITFIELD_2(unsigned char, ! 922: adr : 4, ! 923: ctrl : 4); ! 924: unsigned char xxx3[6]; ! 925: unsigned char address[3]; ! 926: } track_info[1]; /* VARSIZE */ ! 927: } nec_toc_data_t; ! 928: ! 929: #define SCSI_CMD_NEC_SEEK_TRK 0xd8 ! 930: #define SCSI_CMD_NEC_PLAY_AUDIO 0xd9 ! 931: #define SCSI_CMD_NEC_PAUSE 0xda ! 932: #define SCSI_CMD_NEC_EJECT 0xdc ! 933: ! 934: #define SCSI_CMD_NEC_READ_SUBCH_Q 0xdd ! 935: typedef struct { ! 936: unsigned char audio_status; /* see decode_status_1 */ ! 937: BITFIELD_2(unsigned char, ! 938: ctrl : 4, ! 939: xxx1 : 4); ! 940: unsigned char trackno; ! 941: unsigned char indexno; ! 942: unsigned char relative_address[3]; ! 943: unsigned char absolute_address[3]; ! 944: } nec_subch_data_t; ! 945: ! 946: /* ! 947: * Reserved bits in byte1 ! 948: */ ! 949: #define NEC_LR_PLAY_MODE 0x01 /* RelAdr bit overload */ ! 950: #define NEC_LR_STEREO 0x02 /* mono/stereo */ ! 951: ! 952: /* ! 953: * Vendor specific bits in the control byte. ! 954: * NEC uses them to specify the addressing mode ! 955: */ ! 956: #define NEC_CTRL_A_ABS 0x00 /* XXX not sure about this */ ! 957: #define NEC_CTRL_A_MSF 0x40 /* min/sec/frame */ ! 958: #define NEC_CTRL_A_TI 0x80 /* track/index */ ! 959: #define NEC_CTRL_A_CURRENT 0xc0 /* same as last specified */ ! 960: ! 961: private scsi_ret_t ! 962: nec_eject( ! 963: target_info_t *tgt, ! 964: char *cmd, ! 965: io_req_t ior) ! 966: { ! 967: scsi_command_group_2 c; ! 968: ! 969: bzero(&c, sizeof(c)); ! 970: c.scsi_cmd_code = SCSI_CMD_NEC_EJECT; ! 971: ! 972: return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); ! 973: } ! 974: ! 975: private scsi_ret_t ! 976: nec_subchannel( ! 977: target_info_t *tgt, ! 978: char *cmd, ! 979: io_req_t ior) ! 980: { ! 981: scsi_command_group_2 c; ! 982: nec_subch_data_t *st; ! 983: char *buf = tgt->dev_info.cdrom.result; ! 984: scsi_ret_t rc; ! 985: ! 986: bzero(&c, sizeof(c)); ! 987: c.scsi_cmd_code = SCSI_CMD_NEC_READ_SUBCH_Q; ! 988: c.scsi_cmd_lun_and_relbit = sizeof(*st); /* Sic! */ ! 989: ! 990: rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(*st), ior); ! 991: if (rc != SCSI_RET_SUCCESS) return rc; ! 992: ! 993: st = (nec_subch_data_t *) tgt->cmd_ptr; ! 994: ! 995: /* Status or Position ? */ ! 996: ! 997: if (cmd[4] == 'S') { ! 998: decode_status_1( buf, st->audio_status); ! 999: } else { ! 1000: ! 1001: /* XXX can it do ABS addressing e.g. 'logical' ? */ ! 1002: ! 1003: sprintf(buf, "MSF Position %d %d %d %d %d %d", ! 1004: (integer_t)bcd_to_decimal(st->absolute_address[0]), /* min */ ! 1005: (integer_t)bcd_to_decimal(st->absolute_address[1]), /* sec */ ! 1006: (integer_t)bcd_to_decimal(st->absolute_address[2]), /* frm */ ! 1007: (integer_t)bcd_to_decimal(st->relative_address[0]), /* min */ ! 1008: (integer_t)bcd_to_decimal(st->relative_address[1]), /* sec */ ! 1009: (integer_t)bcd_to_decimal(st->relative_address[2])); /* frm */ ! 1010: } ! 1011: ! 1012: tgt->dev_info.cdrom.result_available = TRUE; ! 1013: return SCSI_RET_SUCCESS; ! 1014: } ! 1015: ! 1016: private scsi_ret_t ! 1017: nec_read_toc( ! 1018: target_info_t *tgt, ! 1019: char *cmd, ! 1020: io_req_t ior) ! 1021: { ! 1022: scsi_command_group_2 c; ! 1023: nec_toc_data_t *t; ! 1024: char *buf = tgt->dev_info.cdrom.result; ! 1025: scsi_ret_t rc; ! 1026: int first, last, i; ! 1027: ! 1028: bzero(&c, sizeof(c)); ! 1029: c.scsi_cmd_code = SCSI_CMD_NEC_READ_TOC; ! 1030: c.scsi_cmd_lun_and_relbit = NEC_LR_PLAY_MODE|NEC_LR_STEREO; ! 1031: ! 1032: rc = cdrom_vendor_specific(tgt, &c, 0, 0, 512/*XXX*/, ior); ! 1033: if (rc != SCSI_RET_SUCCESS) return rc; ! 1034: ! 1035: t = (nec_toc_data_t *) tgt->cmd_ptr; ! 1036: ! 1037: first = bcd_to_decimal(t->first_track); ! 1038: last = bcd_to_decimal(t->last_track); ! 1039: ! 1040: /* ! 1041: * "Get TH" wants summary, "TOC MSF|ABS from_track" wants all ! 1042: */ ! 1043: if (cmd[0] == 'G') { ! 1044: sprintf(buf, "toc header: %d %d %d", ! 1045: sizeof(*t) + sizeof(t->track_info) * (last - first - 1), ! 1046: first, last); ! 1047: goto out; ! 1048: } ! 1049: ! 1050: /* ! 1051: * The whole shebang ! 1052: */ ! 1053: sscanf(&cmd[8], "%d", &i); ! 1054: sprintf(buf, "TOC from track %d:\n", i); ! 1055: ! 1056: last -= first; ! 1057: i -= first; ! 1058: while ((i >= 0) && (i <= last)) { ! 1059: buf += strlen(buf); ! 1060: if (cmd[4] == 'M') ! 1061: sprintf(buf, "%d %d %d %d %d %d\n", ! 1062: t->track_info[i].ctrl, ! 1063: t->track_info[i].adr, ! 1064: first + i, ! 1065: bcd_to_decimal(t->track_info[i].address[0]), ! 1066: bcd_to_decimal(t->track_info[i].address[1]), ! 1067: bcd_to_decimal(t->track_info[i].address[2])); ! 1068: else ! 1069: /* THIS IS WRONG */ ! 1070: sprintf(buf, "%d %d %d %d\n", ! 1071: t->track_info[i].ctrl, ! 1072: t->track_info[i].adr, ! 1073: first + i, ! 1074: bcd_to_decimal(t->track_info[i].address[0]) * 10000 + ! 1075: bcd_to_decimal(t->track_info[i].address[1]) * 100 + ! 1076: bcd_to_decimal(t->track_info[i].address[2])); ! 1077: i++; ! 1078: } ! 1079: /* To know how long the last track is */ ! 1080: buf += strlen(buf); ! 1081: if (cmd[4] == 'M') ! 1082: sprintf(buf, "%d %d %d %d %d %d\n", ! 1083: 0, 1, 0xaa /* User expects this */, ! 1084: bcd_to_decimal(t->lead_out_addr[0]), ! 1085: bcd_to_decimal(t->lead_out_addr[1]), ! 1086: bcd_to_decimal(t->lead_out_addr[2])); ! 1087: else ! 1088: /* THIS IS WRONG */ ! 1089: sprintf(buf, "%d %d %d %d\n", ! 1090: 0, 1, 0xaa /* User expects this */, ! 1091: bcd_to_decimal(t->lead_out_addr[0]) * 10000 + ! 1092: bcd_to_decimal(t->lead_out_addr[1]) * 100 + ! 1093: bcd_to_decimal(t->lead_out_addr[2])); ! 1094: out: ! 1095: tgt->dev_info.cdrom.result_available = TRUE; ! 1096: return SCSI_RET_SUCCESS; ! 1097: } ! 1098: ! 1099: ! 1100: private scsi_ret_t ! 1101: nec_play( ! 1102: target_info_t *tgt, ! 1103: char *cmd, ! 1104: io_req_t ior) ! 1105: { ! 1106: scsi_command_group_2 c; ! 1107: int sm, ss, sf, em, es, ef; ! 1108: int st, si, et, ei; ! 1109: scsi_ret_t rc; ! 1110: ! 1111: /* ! 1112: * Seek to desired position ! 1113: */ ! 1114: bzero(&c, sizeof(c)); ! 1115: c.scsi_cmd_code = SCSI_CMD_NEC_SEEK_TRK; ! 1116: c.scsi_cmd_lun_and_relbit = NEC_LR_PLAY_MODE; ! 1117: ! 1118: /* ! 1119: * Play_msf or Play_ti ! 1120: */ ! 1121: if (cmd[5] == 'A') { ! 1122: /* "Play A startM startS startF endM endS endF" */ ! 1123: ! 1124: sscanf(&cmd[7], "%d %d %d %d %d %d", ! 1125: &sm, &ss, &sf, &em, &es, &ef); ! 1126: ! 1127: c.scsi_cmd_lba1 = decimal_to_bcd(sm); ! 1128: c.scsi_cmd_lba2 = decimal_to_bcd(ss); ! 1129: c.scsi_cmd_lba3 = decimal_to_bcd(sf); ! 1130: c.scsi_cmd_ctrl_byte = NEC_CTRL_A_MSF; ! 1131: ! 1132: } else { ! 1133: /* "Play TI startT startI endT endI" */ ! 1134: ! 1135: sscanf(&cmd[8], "%d %d %d %d", &st, &si, &et, &ei); ! 1136: ! 1137: c.scsi_cmd_lba1 = decimal_to_bcd(st); ! 1138: c.scsi_cmd_lba2 = decimal_to_bcd(si); ! 1139: c.scsi_cmd_lba3 = 0; ! 1140: c.scsi_cmd_ctrl_byte = NEC_CTRL_A_TI; ! 1141: ! 1142: } ! 1143: ! 1144: rc = cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); ! 1145: if (rc != SCSI_RET_SUCCESS) return rc; ! 1146: ! 1147: /* ! 1148: * Now ask it to play until.. ! 1149: */ ! 1150: zero_ior( ior ); ! 1151: ! 1152: bzero(&c, sizeof(c)); ! 1153: c.scsi_cmd_code = SCSI_CMD_NEC_PLAY_AUDIO; ! 1154: c.scsi_cmd_lun_and_relbit = NEC_LR_PLAY_MODE|NEC_LR_STEREO; ! 1155: ! 1156: if (cmd[5] == 'A') { ! 1157: c.scsi_cmd_lba1 = decimal_to_bcd(em); ! 1158: c.scsi_cmd_lba2 = decimal_to_bcd(es); ! 1159: c.scsi_cmd_lba3 = decimal_to_bcd(ef); ! 1160: c.scsi_cmd_ctrl_byte = NEC_CTRL_A_MSF; ! 1161: } else { ! 1162: c.scsi_cmd_lba1 = decimal_to_bcd(et); ! 1163: c.scsi_cmd_lba2 = decimal_to_bcd(ei); ! 1164: c.scsi_cmd_lba3 = 0; ! 1165: c.scsi_cmd_ctrl_byte = NEC_CTRL_A_TI; ! 1166: } ! 1167: ! 1168: return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); ! 1169: } ! 1170: ! 1171: private scsi_ret_t ! 1172: nec_pause_resume( ! 1173: target_info_t *tgt, ! 1174: char *cmd, ! 1175: io_req_t ior) ! 1176: { ! 1177: scsi_command_group_2 c; ! 1178: ! 1179: bzero(&c, sizeof(c)); ! 1180: /* ! 1181: * "Resume" or "Stop" ! 1182: */ ! 1183: if (cmd[0] == 'R') { ! 1184: c.scsi_cmd_code = SCSI_CMD_NEC_PLAY_AUDIO; ! 1185: c.scsi_cmd_lun_and_relbit = NEC_LR_PLAY_MODE|NEC_LR_STEREO; ! 1186: c.scsi_cmd_ctrl_byte = NEC_CTRL_A_CURRENT; ! 1187: } else { ! 1188: c.scsi_cmd_code = SCSI_CMD_NEC_PAUSE; ! 1189: } ! 1190: ! 1191: return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); ! 1192: } ! 1193: ! 1194: /* TOSHIBA CD-ROM DRIVE:XM 3232 */ ! 1195: ! 1196: #define SCSI_CMD_TOSHIBA_SEEK_TRK 0xc0 ! 1197: #define SCSI_CMD_TOSHIBA_PLAY_AUDIO 0xc1 ! 1198: #define SCSI_CMD_TOSHIBA_PAUSE_AUDIO 0xc2 ! 1199: #define SCSI_CMD_TOSHIBA_EJECT 0xc4 ! 1200: ! 1201: #define SCSI_CMD_TOSHIBA_READ_SUBCH_Q 0xc6 ! 1202: typedef nec_subch_data_t toshiba_subch_data_t; ! 1203: /* audio status -> decode_status_1 */ ! 1204: ! 1205: #define SCSI_CMD_TOSHIBA_READ_TOC_ENTRY 0xc7 ! 1206: typedef struct { ! 1207: unsigned char first_track; ! 1208: unsigned char last_track; ! 1209: unsigned char xxx[2]; ! 1210: } toshiba_toc_header_t; ! 1211: typedef struct { ! 1212: unsigned char address[4]; ! 1213: } toshiba_toc_data_t; ! 1214: ! 1215: ! 1216: private scsi_ret_t ! 1217: toshiba_eject( ! 1218: target_info_t *tgt, ! 1219: char *cmd, ! 1220: io_req_t ior) ! 1221: { ! 1222: scsi_command_group_2 c; ! 1223: ! 1224: bzero(&c, sizeof(c)); ! 1225: c.scsi_cmd_code = SCSI_CMD_TOSHIBA_EJECT; ! 1226: ! 1227: return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); ! 1228: } ! 1229: ! 1230: private scsi_ret_t ! 1231: toshiba_subchannel( ! 1232: target_info_t *tgt, ! 1233: char *cmd, ! 1234: io_req_t ior) ! 1235: { ! 1236: scsi_command_group_2 c; ! 1237: toshiba_subch_data_t *st; ! 1238: char *buf = tgt->dev_info.cdrom.result; ! 1239: scsi_ret_t rc; ! 1240: ! 1241: bzero(&c, sizeof(c)); ! 1242: c.scsi_cmd_code = SCSI_CMD_TOSHIBA_READ_SUBCH_Q; ! 1243: c.scsi_cmd_lun_and_relbit = sizeof(*st); /* Sic! */ ! 1244: ! 1245: rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(*st), ior); ! 1246: if (rc != SCSI_RET_SUCCESS) return rc; ! 1247: ! 1248: st = (toshiba_subch_data_t *) tgt->cmd_ptr; ! 1249: ! 1250: /* Status or Position ? */ ! 1251: ! 1252: if (cmd[4] == 'S') { ! 1253: decode_status_1( buf, st->audio_status); ! 1254: } else { ! 1255: ! 1256: /* XXX can it do ABS addressing e.g. 'logical' ? */ ! 1257: ! 1258: sprintf(buf, "MSF Position %d %d %d %d %d %d", ! 1259: (integer_t)bcd_to_decimal(st->absolute_address[0]), /* min */ ! 1260: (integer_t)bcd_to_decimal(st->absolute_address[1]), /* sec */ ! 1261: (integer_t)bcd_to_decimal(st->absolute_address[2]), /* frm */ ! 1262: (integer_t)bcd_to_decimal(st->relative_address[0]), /* min */ ! 1263: (integer_t)bcd_to_decimal(st->relative_address[1]), /* sec */ ! 1264: (integer_t)bcd_to_decimal(st->relative_address[2])); /* frm */ ! 1265: } ! 1266: ! 1267: tgt->dev_info.cdrom.result_available = TRUE; ! 1268: return SCSI_RET_SUCCESS; ! 1269: } ! 1270: ! 1271: private scsi_ret_t ! 1272: toshiba_read_toc( ! 1273: target_info_t *tgt, ! 1274: char *cmd, ! 1275: io_req_t ior) ! 1276: { ! 1277: scsi_command_group_2 c; ! 1278: toshiba_toc_data_t *t; ! 1279: toshiba_toc_header_t *th; ! 1280: char *buf = tgt->dev_info.cdrom.result; ! 1281: scsi_ret_t rc; ! 1282: int first, last, i; ! 1283: ! 1284: /* TOC header first */ ! 1285: bzero(&c, sizeof(c)); ! 1286: c.scsi_cmd_code = SCSI_CMD_TOSHIBA_READ_TOC_ENTRY; ! 1287: c.scsi_cmd_lun_and_relbit = 0; ! 1288: c.scsi_cmd_lba1 = 0; ! 1289: ! 1290: rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(*th), ior); ! 1291: if (rc != SCSI_RET_SUCCESS) return rc; ! 1292: ! 1293: th = (toshiba_toc_header_t *) tgt->cmd_ptr; ! 1294: ! 1295: first = bcd_to_decimal(th->first_track); ! 1296: last = bcd_to_decimal(th->last_track); ! 1297: ! 1298: /* ! 1299: * "Get TH" wants summary, "TOC MSF|ABS from_track" wants all ! 1300: */ ! 1301: if (cmd[0] == 'G') { ! 1302: sprintf(buf, "toc header: %d %d %d", ! 1303: sizeof(*th) + sizeof(*t) * (last - first + 1), ! 1304: first, last); ! 1305: goto out; ! 1306: } ! 1307: ! 1308: /* ! 1309: * The whole shebang ! 1310: */ ! 1311: sscanf(&cmd[8], "%d", &i); ! 1312: sprintf(buf, "TOC from track %d:\n", i); ! 1313: ! 1314: while (i <= last) { ! 1315: bzero(&c, sizeof(c)); ! 1316: ! 1317: c.scsi_cmd_code = SCSI_CMD_TOSHIBA_READ_TOC_ENTRY; ! 1318: c.scsi_cmd_lun_and_relbit = 2; ! 1319: c.scsi_cmd_lba1 = decimal_to_bcd(i); ! 1320: ! 1321: zero_ior( ior ); ! 1322: rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(*t), ior); ! 1323: if (rc != SCSI_RET_SUCCESS) break; ! 1324: ! 1325: t = (toshiba_toc_data_t *) tgt->cmd_ptr; ! 1326: ! 1327: buf += strlen(buf); ! 1328: if (cmd[4] == 'M') ! 1329: sprintf(buf, "0 0 %d %d %d %d\n", ! 1330: i, ! 1331: bcd_to_decimal(t->address[0]), ! 1332: bcd_to_decimal(t->address[1]), ! 1333: bcd_to_decimal(t->address[2])); ! 1334: else ! 1335: /* THIS IS WRONG */ ! 1336: sprintf(buf, "0 0 %d %d\n", ! 1337: i, ! 1338: bcd_to_decimal(t->address[0]) * 10000 + ! 1339: bcd_to_decimal(t->address[1]) * 100 + ! 1340: bcd_to_decimal(t->address[2])); ! 1341: i++; ! 1342: } ! 1343: ! 1344: /* Must simulate the lead-out track */ ! 1345: bzero(&c, sizeof(c)); ! 1346: ! 1347: c.scsi_cmd_code = SCSI_CMD_TOSHIBA_READ_TOC_ENTRY; ! 1348: c.scsi_cmd_lun_and_relbit = 1; ! 1349: c.scsi_cmd_lba1 = 0; ! 1350: ! 1351: zero_ior( ior ); ! 1352: rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(*t), ior); ! 1353: if (rc != SCSI_RET_SUCCESS) goto out; ! 1354: ! 1355: t = (toshiba_toc_data_t *) tgt->cmd_ptr; ! 1356: ! 1357: buf += strlen(buf); ! 1358: if (cmd[4] == 'M') ! 1359: sprintf(buf, "0 0 %d %d %d %d\n", ! 1360: i, ! 1361: bcd_to_decimal(t->address[0]), ! 1362: bcd_to_decimal(t->address[1]), ! 1363: bcd_to_decimal(t->address[2])); ! 1364: else ! 1365: /* THIS IS WRONG */ ! 1366: sprintf(buf, "0 0 %d %d\n", ! 1367: i, ! 1368: bcd_to_decimal(t->address[0]) * 10000 + ! 1369: bcd_to_decimal(t->address[1]) * 100 + ! 1370: bcd_to_decimal(t->address[2])); ! 1371: i++; ! 1372: ! 1373: out: ! 1374: tgt->dev_info.cdrom.result_available = TRUE; ! 1375: return SCSI_RET_SUCCESS; ! 1376: } ! 1377: ! 1378: ! 1379: private scsi_ret_t ! 1380: toshiba_play( ! 1381: target_info_t *tgt, ! 1382: char *cmd, ! 1383: io_req_t ior) ! 1384: { ! 1385: scsi_command_group_2 c; ! 1386: int sm, ss, sf, em, es, ef; ! 1387: int st, si, et, ei; ! 1388: scsi_ret_t rc; ! 1389: ! 1390: /* ! 1391: * Seek to desired position ! 1392: */ ! 1393: bzero(&c, sizeof(c)); ! 1394: c.scsi_cmd_code = SCSI_CMD_TOSHIBA_SEEK_TRK; ! 1395: ! 1396: /* ! 1397: * Play_msf or Play_ti ! 1398: */ ! 1399: if (cmd[5] == 'A') { ! 1400: /* "Play A startM startS startF endM endS endF" */ ! 1401: ! 1402: sscanf(&cmd[7], "%d %d %d %d %d %d", ! 1403: &sm, &ss, &sf, &em, &es, &ef); ! 1404: ! 1405: c.scsi_cmd_lba1 = decimal_to_bcd(sm); ! 1406: c.scsi_cmd_lba2 = decimal_to_bcd(ss); ! 1407: c.scsi_cmd_lba3 = decimal_to_bcd(sf); ! 1408: c.scsi_cmd_ctrl_byte = NEC_CTRL_A_MSF; ! 1409: ! 1410: } else { ! 1411: /* "Play TI startT startI endT endI" */ ! 1412: ! 1413: sscanf(&cmd[8], "%d %d %d %d", &st, &si, &et, &ei); ! 1414: ! 1415: c.scsi_cmd_lba1 = decimal_to_bcd(st); ! 1416: c.scsi_cmd_lba2 = decimal_to_bcd(si); ! 1417: c.scsi_cmd_lba3 = 0; ! 1418: c.scsi_cmd_ctrl_byte = NEC_CTRL_A_TI; ! 1419: ! 1420: } ! 1421: ! 1422: rc = cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); ! 1423: if (rc != SCSI_RET_SUCCESS) return rc; ! 1424: ! 1425: /* ! 1426: * Now ask it to play until.. ! 1427: */ ! 1428: zero_ior( ior ); ! 1429: ! 1430: bzero(&c, sizeof(c)); ! 1431: c.scsi_cmd_code = SCSI_CMD_TOSHIBA_PLAY_AUDIO; ! 1432: c.scsi_cmd_lun_and_relbit = NEC_LR_PLAY_MODE|NEC_LR_STEREO; ! 1433: ! 1434: if (cmd[5] == 'A') { ! 1435: c.scsi_cmd_lba1 = decimal_to_bcd(em); ! 1436: c.scsi_cmd_lba2 = decimal_to_bcd(es); ! 1437: c.scsi_cmd_lba3 = decimal_to_bcd(ef); ! 1438: c.scsi_cmd_ctrl_byte = NEC_CTRL_A_MSF; ! 1439: } else { ! 1440: c.scsi_cmd_lba1 = decimal_to_bcd(et); ! 1441: c.scsi_cmd_lba2 = decimal_to_bcd(ei); ! 1442: c.scsi_cmd_lba3 = 0; ! 1443: c.scsi_cmd_ctrl_byte = NEC_CTRL_A_TI; ! 1444: } ! 1445: ! 1446: return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); ! 1447: } ! 1448: ! 1449: private scsi_ret_t ! 1450: toshiba_pause_resume( ! 1451: target_info_t *tgt, ! 1452: char *cmd, ! 1453: io_req_t ior) ! 1454: { ! 1455: scsi_command_group_2 c; ! 1456: ! 1457: bzero(&c, sizeof(c)); ! 1458: /* ! 1459: * "Resume" or "Stop" ! 1460: */ ! 1461: if (cmd[0] == 'R') { ! 1462: /* ???? would have to remember last cmd ???? */ ! 1463: /* broken ! */ ! 1464: c.scsi_cmd_code = SCSI_CMD_TOSHIBA_PLAY_AUDIO; ! 1465: c.scsi_cmd_lun_and_relbit = NEC_LR_PLAY_MODE|NEC_LR_STEREO; ! 1466: c.scsi_cmd_ctrl_byte = NEC_CTRL_A_CURRENT; ! 1467: } else { ! 1468: c.scsi_cmd_code = SCSI_CMD_TOSHIBA_PAUSE_AUDIO; ! 1469: } ! 1470: ! 1471: return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); ! 1472: } ! 1473: ! 1474: ! 1475: #if 0 ! 1476: /* I have info on these drives, but no drive to test */ ! 1477: ! 1478: /* PIONEER DRM-600 */ ! 1479: ! 1480: #define SCSI_CMD_PIONEER_EJECT 0xc0 ! 1481: ! 1482: #define SCSI_CMD_PIONEER_READ_TOC 0xc1 ! 1483: typedef struct { ! 1484: unsigned char first_track; ! 1485: unsigned char last_track; ! 1486: unsigned char xxx[2]; ! 1487: } pioneer_toc_hdr_t; ! 1488: typedef struct { ! 1489: unsigned char ctrl; ! 1490: unsigned char address[3]; ! 1491: } pioneer_toc_info_t; ! 1492: ! 1493: #define SCSI_CMD_PIONEER_READ_SUBCH 0xc2 ! 1494: typedef struct { ! 1495: BITFIELD_2(unsigned char, ! 1496: ctrl : 4, ! 1497: xxx1 : 4); ! 1498: unsigned char trackno; ! 1499: unsigned char indexno; ! 1500: unsigned char relative_address[3]; ! 1501: unsigned char absolute_address[3]; ! 1502: } pioneer_subch_data_t; ! 1503: ! 1504: #define SCSI_CMD_PIONEER_SEEK_TRK 0xc8 ! 1505: #define SCSI_CMD_PIONEER_PLAY_AUDIO 0xc9 ! 1506: #define SCSI_CMD_PIONEER_PAUSE 0xca ! 1507: ! 1508: #define SCSI_CMD_PIONEER_AUDIO_STATUS 0xcc ! 1509: typedef struct { ! 1510: unsigned char audio_status; ! 1511: unsigned char xxx[5]; ! 1512: } pioneer_status_t; ! 1513: ! 1514: /* ! 1515: * Reserved bits in byte1 ! 1516: */ ! 1517: #define PIONEER_LR_END_ADDR 0x10 ! 1518: #define PIONEER_LR_PAUSE 0x10 ! 1519: #define PIONEER_LR_RESUME 0x00 ! 1520: ! 1521: /* ! 1522: * Vendor specific bits in the control byte. ! 1523: */ ! 1524: #define PIONEER_CTRL_TH 0x00 /* TOC header */ ! 1525: #define PIONEER_CTRL_TE 0x80 /* one TOC entry */ ! 1526: #define PIONEER_CTRL_LO 0x40 /* lead-out track info */ ! 1527: ! 1528: #define PIONEER_CTRL_A_MSF 0x40 /* min/sec/frame addr */ ! 1529: ! 1530: private scsi_ret_t ! 1531: pioneer_eject( ! 1532: target_info_t *tgt, ! 1533: char *cmd, ! 1534: io_req_t ior) ! 1535: { ! 1536: scsi_command_group_2 c; ! 1537: ! 1538: bzero(&c, sizeof(c)); ! 1539: c.scsi_cmd_code = SCSI_CMD_PIONEER_EJECT; ! 1540: ! 1541: return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); ! 1542: } ! 1543: ! 1544: private scsi_ret_t ! 1545: pioneer_position( ! 1546: target_info_t *tgt, ! 1547: char *cmd, ! 1548: io_req_t ior) ! 1549: { ! 1550: scsi_command_group_2 c; ! 1551: scsi_ret_t rc; ! 1552: char *buf = tgt->dev_info.cdrom.result; ! 1553: pioneer_subch_data_t *st; ! 1554: ! 1555: bzero(&c, sizeof(c)); ! 1556: c.scsi_cmd_code = SCSI_CMD_PIONEER_READ_SUBCH; ! 1557: c.scsi_cmd_xfer_len_2 = sizeof(pioneer_subch_data_t); /* 9 bytes */ ! 1558: ! 1559: rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(pioneer_subch_data_t), ior); ! 1560: if (rc != SCSI_RET_SUCCESS) return rc; ! 1561: ! 1562: st = (pioneer_subch_data_t *) tgt->cmd_ptr; ! 1563: ! 1564: /* XXX can it do ABS addressing e.g. 'logical' ? */ ! 1565: ! 1566: sprintf(buf, "MSF Position %d %d %d %d %d %d", ! 1567: (integer_t)bcd_to_decimal(st->absolute_address[0]), /* min */ ! 1568: (integer_t)bcd_to_decimal(st->absolute_address[1]), /* sec */ ! 1569: (integer_t)bcd_to_decimal(st->absolute_address[2]), /* frm */ ! 1570: (integer_t)bcd_to_decimal(st->relative_address[0]), /* min */ ! 1571: (integer_t)bcd_to_decimal(st->relative_address[1]), /* sec */ ! 1572: (integer_t)bcd_to_decimal(st->relative_address[2])); /* frm */ ! 1573: ! 1574: tgt->dev_info.cdrom.result_available = TRUE; ! 1575: return SCSI_RET_SUCCESS; ! 1576: } ! 1577: ! 1578: private scsi_ret_t ! 1579: pioneer_toc( ! 1580: target_info_t *tgt, ! 1581: char *cmd, ! 1582: io_req_t ior) ! 1583: { ! 1584: scsi_command_group_2 c; ! 1585: pioneer_toc_hdr_t *th; ! 1586: pioneer_toc_info_t *t; ! 1587: char *buf = tgt->dev_info.cdrom.result; ! 1588: scsi_ret_t rc; ! 1589: int first, last, i; ! 1590: ! 1591: /* Read header first */ ! 1592: bzero(&c, sizeof(c)); ! 1593: c.scsi_cmd_code = SCSI_CMD_PIONEER_READ_TOC; ! 1594: c.scsi_cmd_xfer_len_2 = sizeof(pioneer_toc_hdr_t); ! 1595: c.scsi_cmd_ctrl_byte = PIONEER_CTRL_TH; ! 1596: ! 1597: rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(pioneer_toc_hdr_t), ior); ! 1598: if (rc != SCSI_RET_SUCCESS) return rc; ! 1599: ! 1600: th = (pioneer_toc_hdr_t *)tgt->cmd_ptr; ! 1601: first = bcd_to_decimal(th->first_track); ! 1602: last = bcd_to_decimal(th->last_track); ! 1603: ! 1604: /* ! 1605: * "Get TH" wants summary, "TOC MSF|ABS from_track" wants all ! 1606: */ ! 1607: if (cmd[0] == 'G') { ! 1608: sprintf(buf, "toc header: %d %d %d", 0, first, last); ! 1609: goto out; ! 1610: } ! 1611: ! 1612: /* ! 1613: * Must do it one track at a time ! 1614: */ ! 1615: sscanf(&cmd[8], "%d", &i); ! 1616: sprintf(buf, "TOC from track %d:\n", i); ! 1617: ! 1618: for ( ; i <= last; i++) { ! 1619: zero_ior(ior); ! 1620: bzero(&c, sizeof(c)); ! 1621: c.scsi_cmd_code = SCSI_CMD_PIONEER_READ_TOC; ! 1622: c.scsi_cmd_lba4 = decimal_to_bcd(i); ! 1623: c.scsi_cmd_xfer_len_2 = sizeof(pioneer_toc_info_t); ! 1624: c.scsi_cmd_ctrl_byte = PIONEER_CTRL_TE; ! 1625: ! 1626: rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(pioneer_toc_info_t), ior); ! 1627: if (rc != SCSI_RET_SUCCESS) break; ! 1628: ! 1629: t = (pioneer_toc_info_t *)tgt->cmd_ptr; ! 1630: ! 1631: buf += strlen(buf); ! 1632: if (cmd[4] == 'M') ! 1633: sprintf(buf, "%d %d %d %d %d %d\n", ! 1634: t->ctrl, 0, i, ! 1635: bcd_to_decimal(t->address[0]), ! 1636: bcd_to_decimal(t->address[1]), ! 1637: bcd_to_decimal(t->address[2])); ! 1638: else ! 1639: /* THIS IS WRONG */ ! 1640: sprintf(buf, "%d %d %d %d\n", ! 1641: t->ctrl, 0, i, ! 1642: bcd_to_decimal(t->address[0]) * 10000 + ! 1643: bcd_to_decimal(t->address[1]) * 100 + ! 1644: bcd_to_decimal(t->address[2])); ! 1645: } ! 1646: /* To know how long the last track is */ ! 1647: zero_ior(ior); ! 1648: bzero(&c, sizeof(c)); ! 1649: c.scsi_cmd_code = SCSI_CMD_PIONEER_READ_TOC; ! 1650: c.scsi_cmd_xfer_len_2 = sizeof(pioneer_toc_info_t); ! 1651: c.scsi_cmd_ctrl_byte = PIONEER_CTRL_LO; ! 1652: ! 1653: rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(pioneer_toc_info_t), ior); ! 1654: if (rc != SCSI_RET_SUCCESS) return rc; ! 1655: ! 1656: buf += strlen(buf); ! 1657: t = (pioneer_toc_info_t *)tgt->cmd_ptr; ! 1658: if (cmd[4] == 'M') ! 1659: sprintf(buf, "%d %d %d %d %d %d\n", ! 1660: t->ctrl, 0, 0xaa /* User expects this */, ! 1661: bcd_to_decimal(t->address[0]), ! 1662: bcd_to_decimal(t->address[1]), ! 1663: bcd_to_decimal(t->address[2])); ! 1664: else ! 1665: /* THIS IS WRONG */ ! 1666: sprintf(buf, "%d %d %d %d\n", ! 1667: t->ctrl, 0, 0xaa /* User expects this */, ! 1668: bcd_to_decimal(t->address[0]) * 10000 + ! 1669: bcd_to_decimal(t->address[1]) * 100 + ! 1670: bcd_to_decimal(t->address[2])); ! 1671: ! 1672: out: ! 1673: tgt->dev_info.cdrom.result_available = TRUE; ! 1674: return SCSI_RET_SUCCESS; ! 1675: } ! 1676: ! 1677: private scsi_ret_t ! 1678: pioneer_status( ! 1679: target_info_t *tgt, ! 1680: char *cmd, ! 1681: io_req_t ior) ! 1682: { ! 1683: scsi_command_group_2 c; ! 1684: pioneer_status_t *st; ! 1685: char *buf = tgt->dev_info.cdrom.result; ! 1686: scsi_ret_t rc; ! 1687: ! 1688: bzero(&c, sizeof(c)); ! 1689: c.scsi_cmd_code = SCSI_CMD_PIONEER_AUDIO_STATUS; ! 1690: c.scsi_cmd_xfer_len_2 = sizeof(pioneer_status_t); /* 6 bytes */ ! 1691: ! 1692: rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(pioneer_status_t), ior); ! 1693: if (rc != SCSI_RET_SUCCESS) return rc; ! 1694: ! 1695: st = (pioneer_status_t*) tgt->cmd_ptr; ! 1696: decode_status_1( buf, st->audio_status); ! 1697: ! 1698: tgt->dev_info.cdrom.result_available = TRUE; ! 1699: return SCSI_RET_SUCCESS; ! 1700: } ! 1701: ! 1702: private scsi_ret_t ! 1703: pioneer_play( ! 1704: target_info_t *tgt, ! 1705: char *cmd, ! 1706: io_req_t ior) ! 1707: { ! 1708: scsi_command_group_2 c; ! 1709: int sm, ss, sf, em, es, ef; ! 1710: int st, si, et, ei; ! 1711: scsi_ret_t rc; ! 1712: ! 1713: /* ! 1714: * Seek to desired position ! 1715: */ ! 1716: bzero(&c, sizeof(c)); ! 1717: c.scsi_cmd_code = SCSI_CMD_PIONEER_SEEK_TRK; ! 1718: /* ! 1719: * Play_msf or Play_ti ! 1720: */ ! 1721: if (cmd[5] == 'A') { ! 1722: /* "Play A startM startS startF endM endS endF" */ ! 1723: ! 1724: sscanf(&cmd[7], "%d %d %d %d %d %d", ! 1725: &sm, &ss, &sf, &em, &es, &ef); ! 1726: ! 1727: c.scsi_cmd_lba2 = decimal_to_bcd(sm); ! 1728: c.scsi_cmd_lba3 = decimal_to_bcd(ss); ! 1729: c.scsi_cmd_lba4 = decimal_to_bcd(sf); ! 1730: c.scsi_cmd_ctrl_byte = PIONEER_CTRL_A_MSF; ! 1731: ! 1732: } else { ! 1733: /* "Play TI startT startI endT endI" */ ! 1734: ! 1735: sscanf(&cmd[8], "%d %d %d %d", &st, &si, &et, &ei); ! 1736: ! 1737: c.scsi_cmd_lba3 = decimal_to_bcd(st); ! 1738: c.scsi_cmd_lba4 = decimal_to_bcd(si); ! 1739: c.scsi_cmd_ctrl_byte = 0x80; /* Pure speculation!! */ ! 1740: ! 1741: } ! 1742: ! 1743: rc = cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); ! 1744: if (rc != SCSI_RET_SUCCESS) return rc; ! 1745: ! 1746: /* ! 1747: * Now ask it to play until.. ! 1748: */ ! 1749: zero_ior( ior ); ! 1750: ! 1751: bzero(&c, sizeof(c)); ! 1752: c.scsi_cmd_code = SCSI_CMD_PIONEER_PLAY_AUDIO; ! 1753: c.scsi_cmd_lun_and_relbit = PIONEER_LR_END_ADDR; ! 1754: ! 1755: if (cmd[5] == 'A') { ! 1756: c.scsi_cmd_lba2 = decimal_to_bcd(em); ! 1757: c.scsi_cmd_lba3 = decimal_to_bcd(es); ! 1758: c.scsi_cmd_lba4 = decimal_to_bcd(ef); ! 1759: c.scsi_cmd_ctrl_byte = PIONEER_CTRL_A_MSF; ! 1760: } else { ! 1761: c.scsi_cmd_lba3 = decimal_to_bcd(et); ! 1762: c.scsi_cmd_lba4 = decimal_to_bcd(ei); ! 1763: c.scsi_cmd_ctrl_byte = 0x80; /* Pure speculation! */ ! 1764: } ! 1765: ! 1766: return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); ! 1767: } ! 1768: ! 1769: private scsi_ret_t ! 1770: pioneer_pause_resume( ! 1771: target_info_t *tgt, ! 1772: char *cmd, ! 1773: io_req_t ior) ! 1774: { ! 1775: scsi_command_group_2 c; ! 1776: ! 1777: bzero(&c, sizeof(c)); ! 1778: c.scsi_cmd_code = SCSI_CMD_PIONEER_PAUSE; ! 1779: /* ! 1780: * "Resume" or "Stop" ! 1781: */ ! 1782: if (cmd[0] == 'S') ! 1783: c.scsi_cmd_lun_and_relbit = PIONEER_LR_PAUSE; ! 1784: else ! 1785: c.scsi_cmd_lun_and_relbit = PIONEER_LR_RESUME; ! 1786: ! 1787: return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior); ! 1788: } ! 1789: ! 1790: /* DENON DRD-253 */ ! 1791: ! 1792: #define SCSI_CMD_DENON_PLAY_AUDIO 0x22 ! 1793: #define SCSI_CMD_DENON_EJECT 0xe6 ! 1794: #define SCSI_CMD_DENON_PAUSE_AUDIO 0xe7 ! 1795: #define SCSI_CMD_DENON_READ_TOC 0xe9 ! 1796: #define SCSI_CMD_DENON_READ_SUBCH 0xeb ! 1797: ! 1798: ! 1799: /* HITACHI 1750 */ ! 1800: ! 1801: #define SCSI_CMD_HITACHI_PLAY_AUDIO_MSF 0xe0 ! 1802: #define SCSI_CMD_HITACHI_PAUSE_AUDIO 0xe1 ! 1803: #define SCSI_CMD_HITACHI_EJECT 0xe4 ! 1804: #define SCSI_CMD_HITACHI_READ_SUBCH 0xe5 ! 1805: #define SCSI_CMD_HITACHI_READ_TOC 0xe8 ! 1806: ! 1807: #endif ! 1808: ! 1809: /* ! 1810: * Tabulate all of the above ! 1811: */ ! 1812: private red_list_t cdrom_exceptions[] = { ! 1813: ! 1814: #if 0 ! 1815: For documentation purposes, here are some SCSI-2 compliant drives: ! 1816: ! 1817: Vendor Product Rev Comments ! 1818: ! 1819: "SONY " "CD-ROMCDU-541 " "2.6a" The NeXT drive ! 1820: #endif ! 1821: ! 1822: /* vendor, product, rev */ ! 1823: /* can_play_audio */ ! 1824: /* eject */ ! 1825: /* current_position */ ! 1826: /* read_toc */ ! 1827: /* get_status */ ! 1828: /* play_msf */ ! 1829: /* play_ti */ ! 1830: /* pause_resume */ ! 1831: /* volume_control */ ! 1832: ! 1833: /* We have seen a "RRD42(C)DEC " "4.5d" */ ! 1834: { "DEC ", "RRD42", "", ! 1835: 0, 0, 0, 0, 0, 0, 0, 0, rrd42_set_volume }, ! 1836: ! 1837: /* We have seen a "CD-ROM DRIVE:84 " "1.0 " */ ! 1838: { "NEC ", "CD-ROM DRIVE:84", "", ! 1839: op_not_supported, nec_eject, nec_subchannel, nec_read_toc, ! 1840: nec_subchannel, nec_play, nec_play, nec_pause_resume, ! 1841: op_not_supported }, ! 1842: ! 1843: /* We have seen a "CD-ROM DRIVE:XM " "3232" */ ! 1844: { "TOSHIBA ", "CD-ROM DRIVE:XM", "32", ! 1845: op_not_supported, toshiba_eject, toshiba_subchannel, toshiba_read_toc, ! 1846: toshiba_subchannel, toshiba_play, toshiba_play, toshiba_pause_resume, ! 1847: op_not_supported }, ! 1848: ! 1849: { "TOSHIBA ", "CD-ROM DRIVE:XM", "33", ! 1850: op_not_supported, toshiba_eject, toshiba_subchannel, toshiba_read_toc, ! 1851: toshiba_subchannel, toshiba_play, toshiba_play, toshiba_pause_resume, ! 1852: op_not_supported }, ! 1853: ! 1854: #if 0 ! 1855: { "PIONEER ", "???????DRM-6", "", ! 1856: op_not_supported, pioneer_eject, pioneer_position, pioneer_toc, ! 1857: pioneer_status, pioneer_play, pioneer_play, pioneer_pause_resume, ! 1858: op_not_supported }, ! 1859: ! 1860: { "DENON ", "DRD 25X", "", ...}, ! 1861: { "HITACHI ", "CDR 1750S", "", ...}, ! 1862: { "HITACHI ", "CDR 1650S", "", ...}, ! 1863: { "HITACHI ", "CDR 3650", "", ...}, ! 1864: ! 1865: #endif ! 1866: ! 1867: /* Zero terminate this list */ ! 1868: { 0, } ! 1869: }; ! 1870: ! 1871: private void ! 1872: check_red_list( ! 1873: target_info_t *tgt, ! 1874: scsi2_inquiry_data_t *inq) ! 1875: ! 1876: { ! 1877: red_list_t *list; ! 1878: ! 1879: for (list = &cdrom_exceptions[0]; list->vendor; list++) { ! 1880: ! 1881: /* ! 1882: * Prefix-Match all strings ! 1883: */ ! 1884: if ((strncmp(list->vendor, (const char *)inq->vendor_id, ! 1885: strlen(list->vendor)) == 0) && ! 1886: (strncmp(list->product, (const char *)inq->product_id, ! 1887: strlen(list->product)) == 0) && ! 1888: (strncmp(list->rev, (const char *)inq->product_rev, ! 1889: strlen(list->rev)) == 0)) { ! 1890: /* ! 1891: * One of them.. ! 1892: */ ! 1893: if (tgt->dev_info.cdrom.violates_standards != list) { ! 1894: tgt->dev_info.cdrom.violates_standards = list; ! 1895: curse_the_vendor( list, TRUE ); ! 1896: } ! 1897: return; ! 1898: } ! 1899: } ! 1900: } ! 1901: #endif /* NSCSI > 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.