Annotation of Gnu-Mach/scsi/rz_audio.c, revision 1.1

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 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.