The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/scsi/rz_audio.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 6fca613f7515a7f23f64b47999bb0e53


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.