Annotation of Gnu-Mach/scsi/rz_audio.c, revision 1.1.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.