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/i386/isa/wd_cd.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  * Copyright (c) 1998, 1999 Søren Schmidt
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer,
   10  *    without modification, immediately at the beginning of the file.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. The name of the author may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  *
   28  * $FreeBSD$
   29  */
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/kernel.h>
   34 #include <sys/proc.h>
   35 #include <sys/malloc.h>
   36 #include <sys/buf.h>
   37 #include <sys/disklabel.h>
   38 #include <sys/devicestat.h>
   39 #include <sys/cdio.h>
   40 #include <sys/wormio.h>
   41 #include <sys/fcntl.h>
   42 #include <sys/conf.h>
   43 #include <sys/stat.h>
   44 #include <i386/isa/atapi.h>
   45 #include <i386/isa/wd_cd.h>
   46 
   47 static d_open_t         acdopen;
   48 static d_close_t        acdclose;
   49 static d_ioctl_t        acdioctl;
   50 static d_strategy_t     acdstrategy;
   51 
   52 #define CDEV_MAJOR 69
   53 #define BDEV_MAJOR 19
   54 static struct cdevsw acd_cdevsw = {
   55         /* open */      acdopen,
   56         /* close */     acdclose,
   57         /* read */      physread,
   58         /* write */     physwrite,
   59         /* ioctl */     acdioctl,
   60         /* poll */      nopoll,
   61         /* mmap */      nommap,
   62         /* strategy */  acdstrategy,
   63         /* name */      "wcd",
   64         /* maj */       CDEV_MAJOR,
   65         /* dump */      nodump,
   66         /* psize */     nopsize,
   67         /* flags */     D_DISK,
   68         /* bmaj */      BDEV_MAJOR
   69 };
   70 
   71 #define NUNIT   16              /* Max # of devices */
   72 
   73 #define F_BOPEN         0x0001  /* The block device is opened */
   74 #define F_MEDIA_CHANGED 0x0002  /* The media have changed since open */
   75 #define F_DEBUG         0x0004  /* Print debug info */
   76 #define F_LOCKED        0x0008  /* This unit is locked (or should be) */
   77 #define F_TRACK_PREP    0x0010  /* Track should be prep'ed */
   78 #define F_TRACK_PREPED  0x0020  /* Track has been prep'ed */
   79 #define F_DISK_PREPED   0x0040  /* Disk has been prep'ed */
   80 #define F_WRITTEN       0x0080  /* The medium has been written to */
   81 
   82 static struct acd *acdtab[NUNIT];
   83 static int acdnlun = 0;         /* Number of configured drives */
   84 
   85 int acdattach(struct atapi *, int, struct atapi_params *, int);
   86 static struct acd *acd_init_lun(struct atapi *, int, struct atapi_params *, int,
   87 struct devstat *);
   88 static void acd_start(struct acd *);
   89 static void acd_done(struct acd *, struct buf *, int, struct atapires);
   90 static int acd_read_toc(struct acd *);
   91 static int acd_request_wait(struct acd *, u_char, u_char, u_char, u_char, u_char, u_char, u_char, u_char, u_char, u_char, char *, int);
   92 static void acd_describe(struct acd *);
   93 static int acd_setchan(struct acd *, u_char, u_char, u_char, u_char);
   94 static int acd_eject(struct acd *, int);
   95 static void acd_select_slot(struct acd *);
   96 static int acd_open_disk(struct acd *, int);
   97 static int acd_open_track(struct acd *, struct wormio_prepare_track *);
   98 static int acd_close_track(struct acd *);
   99 static int acd_close_disk(struct acd *);
  100 static int acd_read_track_info(struct acd *cdp, int lba, struct acd_track_info *info);
  101 static int acd_blank_disk(struct acd *);
  102 static void atapi_dump(int ctrlr, int lun, char *label, void *data, int len);
  103 static void atapi_error(struct atapi *ata, int unit, struct atapires result);
  104 
  105 struct acd *
  106 acd_init_lun(struct atapi *ata, int unit, struct atapi_params *ap, int lun,
  107              struct devstat *device_stats)
  108 {
  109     struct acd *ptr;
  110 
  111     if (!(ptr = malloc(sizeof(struct acd), M_TEMP, M_NOWAIT)))
  112         return NULL;
  113     bzero(ptr, sizeof(struct acd));
  114     bufq_init(&ptr->buf_queue);
  115     ptr->ata = ata;
  116     ptr->unit = unit;
  117     ptr->lun = lun;
  118     ptr->param = ap;
  119     ptr->flags = F_MEDIA_CHANGED;
  120     ptr->flags &= ~(F_WRITTEN|F_TRACK_PREP|F_TRACK_PREPED);
  121     ptr->block_size = 2048;
  122     ptr->refcnt = 0;
  123     ptr->slot = -1;
  124     ptr->changer_info = NULL;
  125     if (device_stats == NULL) {
  126         if (!(ptr->device_stats = malloc(sizeof(struct devstat), 
  127                                          M_TEMP, M_NOWAIT)))
  128             return NULL;
  129         bzero(ptr->device_stats, sizeof(struct devstat));
  130     }
  131     else
  132         ptr->device_stats = device_stats;
  133     make_dev(&acd_cdevsw, dkmakeminor(lun, 0, 0),
  134         UID_ROOT, GID_OPERATOR, 0640, "rwcd%da", lun);
  135     make_dev(&acd_cdevsw, dkmakeminor(lun, 0, RAW_PART),
  136         UID_ROOT, GID_OPERATOR, 0640, "rwcd%dc", lun);
  137     make_dev(&acd_cdevsw, dkmakeminor(lun, 0, 0),
  138         UID_ROOT, GID_OPERATOR, 0640, "wcd%da", lun);
  139     make_dev(&acd_cdevsw, dkmakeminor(lun, 0, RAW_PART),
  140         UID_ROOT, GID_OPERATOR, 0640, "wcd%dc", lun);
  141     return ptr;
  142 }
  143 
  144 int
  145 acdattach(struct atapi *ata, int unit, struct atapi_params *ap, int debug)
  146 {
  147     struct acd *cdp;
  148     struct atapires result;
  149     struct changer *chp;
  150     int i, count;
  151 
  152     if (acdnlun >= NUNIT) {
  153         printf("wcd: too many units\n");
  154         return 0;
  155     }
  156     if (!atapi_request_immediate) {
  157         printf("wcd: configuration error, ATAPI code not present!\n");
  158         return 0;
  159     }
  160     if ((cdp = acd_init_lun(ata, unit, ap, acdnlun, NULL)) == NULL) {
  161         printf("wcd: out of memory\n");
  162         return 0;
  163     }
  164     acdtab[acdnlun] = cdp;
  165 
  166     if (debug) {
  167         cdp->flags |= F_DEBUG;
  168         atapi_dump(cdp->ata->ctrlr, cdp->lun, "info", ap, sizeof(*ap));
  169     }
  170 
  171     /* Get drive capabilities, some drives needs this repeated */
  172     for (count = 0 ; count < 5 ; count++) {
  173         result = atapi_request_immediate(ata, unit,
  174                                          ATAPI_MODE_SENSE,
  175                                          0, ATAPI_CDROM_CAP_PAGE,
  176                                          0, 0, 0, 0, 
  177                                          sizeof(cdp->cap)>>8, sizeof(cdp->cap),
  178                                          0, 0, 0, 0, 0, 0, 0, 
  179                                          (char *)&cdp->cap, sizeof(cdp->cap));
  180         if (result.code == 0 || result.code == RES_UNDERRUN)
  181             break;
  182     }
  183 
  184     /* Some drives have shorter capabilities page. */
  185     if (result.code == RES_UNDERRUN)
  186         result.code = 0;
  187 
  188     if (result.code == 0) {
  189         cdp->cap.max_speed = ntohs(cdp->cap.max_speed);
  190         cdp->cap.max_vol_levels = ntohs(cdp->cap.max_vol_levels);
  191         cdp->cap.buf_size = ntohs(cdp->cap.buf_size);
  192         cdp->cap.cur_speed = ntohs(cdp->cap.cur_speed);
  193         acd_describe(cdp);
  194         if (cdp->flags & F_DEBUG)
  195             atapi_dump(cdp->ata->ctrlr, cdp->lun, "cap", &cdp->cap,
  196                        sizeof(cdp->cap));
  197     }
  198     /* If this is a changer device, allocate the neeeded lun's */
  199     if (cdp->cap.mech == MST_MECH_CHANGER) {
  200         char string[16];
  201         struct acd *tmpcdp = cdp;
  202 
  203         chp = malloc(sizeof(struct changer), M_TEMP, M_NOWAIT);
  204         if (chp == NULL) {
  205             printf("wcd: out of memory\n");
  206             return 0;
  207         }
  208         bzero(chp, sizeof(struct changer));
  209         result = atapi_request_immediate(ata, unit, ATAPI_MECH_STATUS,
  210                                          0, 0, 0, 0, 0, 0, 0,
  211                                          sizeof(struct changer)>>8,
  212                                          sizeof(struct changer),
  213                                          0, 0, 0, 0, 0, 0,
  214                                          (char *)chp, sizeof(struct changer));
  215         if (cdp->flags & F_DEBUG) {
  216             printf("result.code=%d curr=%02x slots=%d len=%d\n",
  217                 result.code, chp->current_slot, chp->slots,
  218                 htons(chp->table_length));
  219         }
  220         if (result.code == RES_UNDERRUN)
  221             result.code = 0;
  222 
  223         if (result.code == 0) {
  224             chp->table_length = htons(chp->table_length);
  225             for (i = 0; i < chp->slots && acdnlun < NUNIT; i++) {
  226                 if (i > 0) {
  227                     tmpcdp = acd_init_lun(ata, unit, ap, acdnlun, 
  228                                           cdp->device_stats);
  229                     if (!tmpcdp) {
  230                         printf("wcd: out of memory\n");
  231                         return 0;
  232                     }
  233                 }
  234                 tmpcdp->slot = i;
  235                 tmpcdp->changer_info = chp;
  236                 printf("wcd%d: changer slot %d %s\n", acdnlun, i,
  237                        (chp->slot[i].present ? "disk present" : "no disk"));
  238                 acdtab[acdnlun++] = tmpcdp;
  239             }
  240             if (acdnlun >= NUNIT) {
  241                 printf("wcd: too many units\n");
  242                 return 0;
  243             }
  244         }
  245         sprintf(string, "wcd%d-", cdp->lun);
  246         devstat_add_entry(cdp->device_stats, string, tmpcdp->lun, DEV_BSIZE,
  247                           DEVSTAT_NO_ORDERED_TAGS,
  248                           DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_IDE,
  249                           DEVSTAT_PRIORITY_CD);
  250     }
  251     else {
  252         acdnlun++;
  253         devstat_add_entry(cdp->device_stats, "wcd", cdp->lun, DEV_BSIZE,
  254                           DEVSTAT_NO_ORDERED_TAGS,
  255                           DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_IDE,
  256                           DEVSTAT_PRIORITY_CD);
  257     }
  258     return 1;
  259 }
  260 
  261 void 
  262 acd_describe(struct acd *cdp)
  263 {
  264     int comma;
  265     char *mechanism;
  266 
  267     printf("wcd%d: drive speed ", cdp->lun);
  268     if (cdp->cap.cur_speed != cdp->cap.max_speed)
  269         printf("%d - ", cdp->cap.cur_speed * 1000 / 1024);
  270     printf("%dKB/sec", cdp->cap.max_speed * 1000 / 1024);
  271     if (cdp->cap.buf_size)
  272         printf(", %dKB cache\n", cdp->cap.buf_size);
  273 
  274     printf("wcd%d: supported read types:", cdp->lun);
  275     comma = 0;
  276     if (cdp->cap.read_cdr) {
  277         printf(" CD-R"); comma = 1;
  278     }
  279     if (cdp->cap.read_cdrw) {
  280         printf("%s CD-RW", comma ? "," : ""); comma = 1;
  281     }
  282     if (cdp->cap.cd_da) {
  283         printf("%s CD-DA", comma ? "," : ""); comma = 1;
  284     }
  285     if (cdp->cap.method2)
  286         printf("%s packet track", comma ? "," : "");
  287     if (cdp->cap.write_cdr || cdp->cap.write_cdrw) {
  288         printf("\nwcd%d: supported write types:", cdp->lun);
  289         comma = 0;
  290         if (cdp->cap.write_cdr) {
  291             printf(" CD-R" ); comma = 1;
  292         }
  293         if (cdp->cap.write_cdrw) {
  294             printf("%s CD-RW", comma ? "," : ""); comma = 1;
  295         }
  296         if (cdp->cap.test_write) {
  297             printf("%s test write", comma ? "," : ""); comma = 1;
  298         }
  299     }
  300     if (cdp->cap.audio_play) {
  301         printf("\nwcd%d: Audio: ", cdp->lun);
  302         if (cdp->cap.audio_play)
  303             printf("play");
  304         if (cdp->cap.max_vol_levels)
  305             printf(", %d volume levels", cdp->cap.max_vol_levels);
  306     }
  307     printf("\nwcd%d: Mechanism: ", cdp->lun);
  308     switch (cdp->cap.mech) {
  309     case MST_MECH_CADDY:
  310         mechanism = "caddy"; break;
  311     case MST_MECH_TRAY:
  312         mechanism = "tray"; break;
  313     case MST_MECH_POPUP:
  314         mechanism = "popup"; break;
  315     case MST_MECH_CHANGER:
  316         mechanism = "changer"; break;
  317     case MST_MECH_CARTRIDGE:
  318         mechanism = "cartridge"; break;
  319     default:
  320         mechanism = 0; break;
  321     }
  322     if (mechanism)
  323         printf("%s%s", cdp->cap.eject ? "ejectable " : "", mechanism);
  324     else if (cdp->cap.eject)
  325         printf("ejectable");
  326 
  327     if (cdp->cap.mech != MST_MECH_CHANGER) {
  328         printf("\nwcd%d: Medium: ", cdp->lun);
  329         switch (cdp->cap.medium_type & MST_TYPE_MASK_HIGH) {
  330         case MST_CDROM:
  331             printf("CD-ROM "); break;
  332         case MST_CDR:
  333             printf("CD-R "); break;
  334         case MST_CDRW:
  335             printf("CD-RW "); break;
  336         case MST_DOOR_OPEN:
  337             printf("door open"); break;
  338         case MST_NO_DISC:
  339             printf("no/blank disc inside"); break;
  340         case MST_FMT_ERROR:
  341             printf("medium format error"); break;
  342         }
  343         if ((cdp->cap.medium_type & MST_TYPE_MASK_HIGH) < MST_TYPE_MASK_HIGH) {
  344             switch (cdp->cap.medium_type & MST_TYPE_MASK_LOW) {
  345             case MST_DATA_120:
  346                 printf("120mm data disc loaded"); break;
  347             case MST_AUDIO_120:
  348                 printf("120mm audio disc loaded"); break;
  349             case MST_COMB_120:
  350                 printf("120mm data/audio disc loaded"); break;
  351             case MST_PHOTO_120:
  352                 printf("120mm photo disc loaded"); break;
  353             case MST_DATA_80:
  354                 printf("80mm data disc loaded"); break;
  355             case MST_AUDIO_80:
  356                 printf("80mm audio disc loaded"); break;
  357             case MST_COMB_80:
  358                 printf("80mm data/audio disc loaded"); break;
  359             case MST_PHOTO_80:
  360                 printf("80mm photo disc loaded"); break;
  361             case MST_FMT_NONE:
  362                 switch (cdp->cap.medium_type & MST_TYPE_MASK_HIGH) {
  363                 case MST_CDROM:
  364                     printf("unknown medium"); break;
  365                 case MST_CDR:
  366                 case MST_CDRW:
  367                     printf("blank medium"); break;
  368                 }
  369                 break;
  370             default:
  371                 printf("unknown type=0x%x", cdp->cap.medium_type); break;
  372             }
  373         }
  374     }
  375     if (cdp->cap.lock)
  376         printf(cdp->cap.locked ? ", locked" : ", unlocked");
  377     if (cdp->cap.prevent)
  378         printf(", lock protected");
  379     printf("\n");
  380 }
  381 
  382 static int
  383 acdopen(dev_t dev, int flags, int fmt, struct proc *p)
  384 {
  385     int lun = dkunit(dev);
  386     struct acd *cdp;
  387 
  388     if (lun >= acdnlun || !atapi_request_immediate)
  389         return ENXIO;
  390     cdp = acdtab[lun];
  391 
  392     if (!(cdp->flags & F_BOPEN) && !cdp->refcnt) {
  393         /* Prevent user eject */
  394         acd_request_wait(cdp, ATAPI_PREVENT_ALLOW,
  395             0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
  396         cdp->flags |= F_LOCKED;
  397     }
  398     if (fmt == S_IFBLK)
  399         cdp->flags |= F_BOPEN;
  400     else
  401         ++cdp->refcnt;
  402     dev->si_bsize_phys = cdp->block_size;
  403     if (!(flags & O_NONBLOCK) && acd_read_toc(cdp) && !(flags & FWRITE))
  404         printf("acd%d: read_toc failed\n", lun);
  405     return 0;
  406 }
  407 
  408 int 
  409 acdclose(dev_t dev, int flags, int fmt, struct proc *p)
  410 {
  411     struct acd *cdp = acdtab[dkunit(dev)];
  412 
  413     if (fmt == S_IFBLK)
  414         cdp->flags &= ~F_BOPEN;
  415     else
  416         --cdp->refcnt;
  417 
  418     /* Are we the last open ?? */
  419     if (!(cdp->flags & F_BOPEN) && !cdp->refcnt) {
  420         /* Yup, do we need to close any written tracks */
  421         if ((flags & FWRITE) != 0) {
  422             if ((cdp->flags & F_TRACK_PREPED) != 0) {
  423                 acd_close_track(cdp);
  424                 cdp->flags &= ~(F_TRACK_PREPED | F_TRACK_PREP);
  425             }
  426         }
  427         /* Allow the user eject */
  428         acd_request_wait(cdp, ATAPI_PREVENT_ALLOW,
  429                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  430     }
  431     cdp->flags &= ~F_LOCKED;
  432     return 0;
  433 }
  434 
  435 void 
  436 acdstrategy(struct buf *bp)
  437 {
  438     int lun = dkunit(bp->b_dev);
  439     struct acd *cdp = acdtab[lun];
  440     int x;
  441 
  442 #ifdef NOTYET
  443     /* allow write only on CD-R/RW media */   /* all for now SOS */
  444     if (!(bp->b_flags & B_READ) && !(writeable_media)) {
  445         bp->b_error = EROFS;
  446         bp->b_flags |= B_ERROR;
  447         biodone(bp);
  448         return;
  449     }
  450 #endif
  451 
  452     if (bp->b_bcount == 0) {
  453         bp->b_resid = 0;
  454         biodone(bp);
  455         return;
  456     }
  457     
  458     bp->b_pblkno = bp->b_blkno;
  459     bp->b_resid = bp->b_bcount;
  460 
  461     x = splbio();
  462     bufqdisksort(&cdp->buf_queue, bp);
  463     acd_start(cdp);
  464     splx(x);
  465 }
  466 
  467 static void 
  468 acd_start(struct acd *cdp)
  469 {
  470     struct buf *bp = bufq_first(&cdp->buf_queue);
  471     u_long lba, blocks;
  472     int cmd;
  473     int count;
  474 
  475     if (!bp)
  476         return;
  477 
  478     bufq_remove(&cdp->buf_queue, bp);
  479 
  480     /* Should reject all queued entries if media have changed. */
  481     if (cdp->flags & F_MEDIA_CHANGED) {
  482         bp->b_error = EIO;
  483         bp->b_flags |= B_ERROR;
  484         biodone(bp);
  485         return;
  486     }
  487 
  488     acd_select_slot(cdp);
  489 
  490     if ((bp->b_flags & B_READ) == B_WRITE) {
  491         if ((cdp->flags & F_TRACK_PREPED) == 0) {
  492             if ((cdp->flags & F_TRACK_PREP) == 0) {
  493                 printf("wcd%d: sequence error\n", cdp->lun);
  494                 bp->b_error = EIO;
  495                 bp->b_flags |= B_ERROR;
  496                 biodone(bp);
  497                 return;
  498             } else {
  499                 if (acd_open_track(cdp, &cdp->preptrack) != 0) {
  500                     biodone(bp);
  501                     return;
  502                 }
  503                 cdp->flags |= F_TRACK_PREPED;
  504             }
  505         }
  506     }
  507 
  508     if (bp->b_flags & B_READ)
  509 #ifdef NOTYET
  510         lba = bp->b_offset / cdp->block_size;
  511 #else
  512         lba = bp->b_blkno / (cdp->block_size / DEV_BSIZE);
  513 #endif
  514     else 
  515         lba = cdp->next_writeable_lba + (bp->b_offset / cdp->block_size);
  516     blocks = (bp->b_bcount + (cdp->block_size - 1)) / cdp->block_size;
  517 
  518     if ((bp->b_flags & B_READ) == B_WRITE) {
  519         cmd = ATAPI_WRITE_BIG;
  520         count = -bp->b_bcount;
  521     } else {
  522         cmd = ATAPI_READ_BIG;
  523         count = bp->b_bcount;
  524     }
  525 
  526     devstat_start_transaction(cdp->device_stats);
  527 
  528     atapi_request_callback(cdp->ata, cdp->unit, cmd, 0,
  529                            lba>>24, lba>>16, lba>>8, lba, 0, 
  530                            blocks>>8, blocks, 0, 0, 0, 0, 0, 0, 0, 
  531                            (u_char *)bp->b_data, count, 
  532                            (atapi_callback_t *)acd_done, cdp, bp);
  533 }
  534 
  535 static void 
  536 acd_done(struct acd *cdp, struct buf *bp, int resid, struct atapires result)
  537 {
  538 
  539     if (result.code) {
  540         atapi_error(cdp->ata, cdp->unit, result);
  541         bp->b_error = EIO;
  542         bp->b_flags |= B_ERROR;
  543     } else {
  544         bp->b_resid = resid;
  545         if ((bp->b_flags & B_READ) == B_WRITE)
  546             cdp->flags |= F_WRITTEN;
  547     }
  548     devstat_end_transaction_buf(cdp->device_stats, bp);
  549     biodone(bp);
  550     acd_start(cdp);
  551 }
  552 
  553 static int 
  554 acd_request_wait(struct acd *cdp, u_char cmd, u_char a1, u_char a2,
  555     u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
  556     u_char a9, char *addr, int count)
  557 {
  558     struct atapires result;
  559 
  560     result = atapi_request_wait(cdp->ata, cdp->unit, cmd, a1, a2, a3, a4, a5,
  561                                 a6, a7, a8, a9, 0, 0, 0, 0, 0, 0, addr, count);
  562     if (result.code) {
  563         atapi_error(cdp->ata, cdp->unit, result);
  564         return EIO;
  565     }
  566     return 0;
  567 }
  568 
  569 static __inline void 
  570 lba2msf(int lba, u_char *m, u_char *s, u_char *f)
  571 {
  572     lba += 150;
  573     lba &= 0xffffff;
  574     *m = lba / (60 * 75);
  575     lba %= (60 * 75);
  576     *s = lba / 75;
  577     *f = lba % 75;
  578 }
  579 
  580 static __inline int 
  581 msf2lba(u_char m, u_char s, u_char f)
  582 {
  583     return (m * 60 + s) * 75 + f - 150;
  584 }
  585 
  586 int 
  587 acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
  588 {
  589     int lun = dkunit(dev);
  590     struct acd *cdp = acdtab[lun];
  591     int error = 0;
  592 
  593     if (cdp->flags & F_MEDIA_CHANGED)
  594         switch (cmd) {
  595         case CDIOCRESET:
  596             break;
  597         default:
  598             acd_read_toc(cdp);
  599             acd_request_wait(cdp, ATAPI_PREVENT_ALLOW,
  600                              0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
  601             cdp->flags |= F_LOCKED;
  602             break;
  603         }
  604     switch (cmd) {
  605 /*
  606     case CDIOCRESUME:
  607         bzero(cdb);
  608         cdb->cmd = ATAPI_PAUSE;
  609         cdb->b8 = 0x01;
  610         return atapi_cmd_wait(cdp->ata, cdp->unit, cdb, 0, 0, timout, 0);
  611 */
  612     case CDIOCRESUME:
  613         return acd_request_wait(cdp, ATAPI_PAUSE, 
  614                                 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);
  615 
  616     case CDIOCPAUSE:
  617         return acd_request_wait(cdp, ATAPI_PAUSE, 
  618                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  619 
  620     case CDIOCSTART:
  621         return acd_request_wait(cdp, ATAPI_START_STOP,
  622                                 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
  623 
  624     case CDIOCSTOP:
  625         return acd_request_wait(cdp, ATAPI_START_STOP,
  626                                 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  627 
  628     case CDIOCALLOW:
  629         acd_select_slot(cdp);
  630         cdp->flags &= ~F_LOCKED;
  631         return acd_request_wait(cdp, ATAPI_PREVENT_ALLOW,
  632                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  633 
  634     case CDIOCPREVENT:
  635         acd_select_slot(cdp);
  636         cdp->flags |= F_LOCKED;
  637         return acd_request_wait(cdp, ATAPI_PREVENT_ALLOW,
  638                                 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
  639 
  640     case CDIOCRESET:
  641         error = suser(p);
  642         if (error)
  643             return (error);
  644         return acd_request_wait(cdp, ATAPI_TEST_UNIT_READY,
  645                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  646 
  647     case CDIOCEJECT:
  648         if ((cdp->flags & F_BOPEN) && cdp->refcnt)
  649             return EBUSY;
  650         return acd_eject(cdp, 0);
  651 
  652     case CDIOCCLOSE:
  653         if ((cdp->flags & F_BOPEN) && cdp->refcnt)
  654             return 0;
  655         return acd_eject(cdp, 1);
  656 
  657     case CDIOREADTOCHEADER:
  658         if (!cdp->toc.hdr.ending_track)
  659             return EIO;
  660         bcopy(&cdp->toc.hdr, addr, sizeof(cdp->toc.hdr));
  661         break;
  662 
  663     case CDIOREADTOCENTRYS:
  664         {
  665             struct ioc_read_toc_entry *te = (struct ioc_read_toc_entry *)addr;
  666             struct toc *toc = &cdp->toc;
  667             struct toc buf;
  668             u_long len;
  669             u_char starting_track = te->starting_track;
  670 
  671             if (!cdp->toc.hdr.ending_track)
  672                 return EIO;
  673 
  674             if (te->data_len < sizeof(toc->tab[0]) || 
  675                 (te->data_len % sizeof(toc->tab[0])) != 0 || 
  676                 (te->address_format != CD_MSF_FORMAT &&
  677                 te->address_format != CD_LBA_FORMAT))
  678                 return EINVAL;
  679 
  680             if (!starting_track)
  681                 starting_track = toc->hdr.starting_track;
  682             else if (starting_track == 170) 
  683                 starting_track = toc->hdr.ending_track + 1;
  684             else if (starting_track < toc->hdr.starting_track ||
  685                      starting_track > toc->hdr.ending_track + 1)
  686                 return EINVAL;
  687 
  688             len = ((toc->hdr.ending_track + 1 - starting_track) + 1) *
  689                   sizeof(toc->tab[0]);
  690             if (te->data_len < len)
  691                 len = te->data_len;
  692             if (len > sizeof(toc->tab))
  693                 return EINVAL;
  694 
  695             if (te->address_format == CD_MSF_FORMAT) {
  696                 struct cd_toc_entry *entry;
  697 
  698                 buf = cdp->toc;
  699                 toc = &buf;
  700                 entry = toc->tab + (toc->hdr.ending_track + 1 -
  701                         toc->hdr.starting_track) + 1;
  702                 while (--entry >= toc->tab)
  703                     lba2msf(ntohl(entry->addr.lba), &entry->addr.msf.minute,
  704                             &entry->addr.msf.second, &entry->addr.msf.frame);
  705             }
  706             return copyout(toc->tab + starting_track - toc->hdr.starting_track,
  707                            te->data, len);
  708         }
  709 
  710     case CDIOREADTOCENTRY:
  711         {
  712             struct ioc_read_toc_single_entry *te =
  713                 (struct ioc_read_toc_single_entry *)addr;
  714             struct toc *toc = &cdp->toc;
  715             struct toc buf;
  716             u_char track = te->track;
  717 
  718             if (!cdp->toc.hdr.ending_track)
  719                 return EIO;
  720 
  721             if (te->address_format != CD_MSF_FORMAT && 
  722                 te->address_format != CD_LBA_FORMAT)
  723                 return EINVAL;
  724 
  725             if (!track)
  726                 track = toc->hdr.starting_track;
  727             else if (track == 170)
  728                 track = toc->hdr.ending_track + 1;
  729             else if (track < toc->hdr.starting_track ||
  730                      track > toc->hdr.ending_track + 1)
  731                 return EINVAL;
  732 
  733             if (te->address_format == CD_MSF_FORMAT) {
  734                 struct cd_toc_entry *entry;
  735 
  736                 buf = cdp->toc;
  737                 toc = &buf;
  738                 entry = toc->tab + (track - toc->hdr.starting_track);
  739                 lba2msf(ntohl(entry->addr.lba), &entry->addr.msf.minute,
  740                         &entry->addr.msf.second, &entry->addr.msf.frame);
  741             }
  742             bcopy(toc->tab + track - toc->hdr.starting_track,
  743                   &te->entry, sizeof(struct cd_toc_entry));
  744         }
  745         break;
  746 
  747     case CDIOCREADSUBCHANNEL:
  748         {
  749             struct ioc_read_subchannel *args =
  750                 (struct ioc_read_subchannel *)addr;
  751             struct cd_sub_channel_info data;
  752             u_long len = args->data_len;
  753             int abslba, rellba;
  754 
  755             if (len > sizeof(data) ||
  756                 len < sizeof(struct cd_sub_channel_header))
  757                 return EINVAL;
  758 
  759             if (acd_request_wait(cdp, ATAPI_READ_SUBCHANNEL,
  760                                  0, 0x40, 1, 0, 0, 0, 
  761                                  sizeof(cdp->subchan)>>8, sizeof(cdp->subchan),
  762                                  0,
  763                                  (char *)&cdp->subchan, 
  764                                  sizeof(cdp->subchan)) != 0)
  765                 return EIO;
  766             if (cdp->flags & F_DEBUG)
  767                 atapi_dump(cdp->ata->ctrlr, cdp->lun, "subchan", &cdp->subchan, 
  768                            sizeof(cdp->subchan));
  769 
  770             abslba = cdp->subchan.abslba;
  771             rellba = cdp->subchan.rellba;
  772             if (args->address_format == CD_MSF_FORMAT) {
  773                 lba2msf(ntohl(abslba),
  774                     &data.what.position.absaddr.msf.minute,
  775                     &data.what.position.absaddr.msf.second,
  776                     &data.what.position.absaddr.msf.frame);
  777                 lba2msf(ntohl(rellba),
  778                     &data.what.position.reladdr.msf.minute,
  779                     &data.what.position.reladdr.msf.second,
  780                     &data.what.position.reladdr.msf.frame);
  781             } else {
  782                 data.what.position.absaddr.lba = abslba;
  783                 data.what.position.reladdr.lba = rellba;
  784             }
  785             data.header.audio_status = cdp->subchan.audio_status;
  786             data.what.position.control = cdp->subchan.control & 0xf;
  787             data.what.position.addr_type = cdp->subchan.control >> 4;
  788             data.what.position.track_number = cdp->subchan.track;
  789             data.what.position.index_number = cdp->subchan.indx;
  790             return copyout(&data, args->data, len);
  791         }
  792 
  793     case CDIOCPLAYMSF:
  794         {
  795             struct ioc_play_msf *args = (struct ioc_play_msf *)addr;
  796 
  797             return acd_request_wait(cdp, ATAPI_PLAY_MSF, 0, 0,
  798                                     args->start_m, args->start_s, args->start_f,
  799                                     args->end_m, args->end_s, args->end_f,
  800                                     0, 0, 0);
  801         }
  802 
  803     case CDIOCPLAYBLOCKS:
  804         {
  805             struct ioc_play_blocks *args = (struct ioc_play_blocks *)addr;
  806 
  807             return acd_request_wait(cdp, ATAPI_PLAY_BIG, 0,
  808                                     args->blk>>24 & 0xff, args->blk>>16 & 0xff,
  809                                     args->blk>>8 & 0xff, args->blk & 0xff,
  810                                     args->len>>24 & 0xff, args->len>>16 & 0xff,
  811                                     args->len>>8 & 0xff, args->len & 0xff,
  812                                     0, 0);
  813         }
  814 
  815     case CDIOCPLAYTRACKS:
  816         {
  817             struct ioc_play_track *args = (struct ioc_play_track *)addr;
  818             u_long start, len;
  819             int t1, t2;
  820 
  821             if (!cdp->toc.hdr.ending_track)
  822                 return EIO;
  823 
  824             if (args->end_track < cdp->toc.hdr.ending_track + 1)
  825                 ++args->end_track;
  826             if (args->end_track > cdp->toc.hdr.ending_track + 1)
  827                 args->end_track = cdp->toc.hdr.ending_track + 1;
  828             t1 = args->start_track - cdp->toc.hdr.starting_track;
  829             t2 = args->end_track - cdp->toc.hdr.starting_track;
  830             if (t1 < 0 || t2 < 0)
  831                 return EINVAL;
  832             start = ntohl(cdp->toc.tab[t1].addr.lba);
  833             len = ntohl(cdp->toc.tab[t2].addr.lba) - start;
  834 
  835             return acd_request_wait(cdp, ATAPI_PLAY_BIG, 0,
  836                                     start>>24 & 0xff, start>>16 & 0xff,
  837                                     start>>8 & 0xff, start & 0xff,
  838                                     len>>24 & 0xff, len>>16 & 0xff,
  839                                     len>>8 & 0xff, len & 0xff, 0, 0);
  840         }
  841 
  842     case CDIOCREADAUDIO:
  843         {
  844             struct ioc_read_audio* args = (struct ioc_read_audio*) addr;
  845             int lba, frames, result = 0;
  846             u_char *buffer, *ubuf = args->buffer;
  847 
  848             if (!cdp->toc.hdr.ending_track)
  849                 return EIO;
  850                 
  851             if ((frames = args->nframes) < 0)
  852                 return EINVAL;
  853 
  854             if (args->address_format == CD_LBA_FORMAT)
  855                 lba = args->address.lba;
  856             else if (args->address_format == CD_MSF_FORMAT)
  857                 lba = msf2lba(args->address.msf.minute,
  858                              args->address.msf.second,
  859                              args->address.msf.frame);
  860             else
  861                 return EINVAL;
  862 #ifndef CD_BUFFER_BLOCKS
  863 #define CD_BUFFER_BLOCKS 8
  864 #endif
  865             if (!(buffer = malloc(CD_BUFFER_BLOCKS * 2352, M_TEMP, M_NOWAIT)))
  866                 return ENOMEM;
  867 
  868             while (frames > 0) {
  869                 u_char blocks;
  870                 int size;
  871 
  872                 blocks = (frames>CD_BUFFER_BLOCKS) ? CD_BUFFER_BLOCKS : frames;
  873                 size = blocks * 2352;
  874 
  875                 result = acd_request_wait(cdp, ATAPI_READ_CD, 4,
  876                                           lba>>24, (lba>>16)&0xff,
  877                                           (lba>>8)&0xff, lba&0xff, 0, 0,
  878                                           blocks, 0xf0, buffer, size);
  879                 if (result != 0)
  880                     break;
  881 
  882                 result = copyout(buffer, ubuf, size);
  883                 if (result != 0)
  884                     break;
  885                     
  886                 ubuf += size;
  887                 frames -= blocks;
  888                 lba += blocks;
  889             }
  890 
  891             free(buffer, M_TEMP);
  892             return result;
  893         }
  894 
  895     case CDIOCGETVOL:
  896         {
  897             struct ioc_vol *arg = (struct ioc_vol *)addr;
  898 
  899             error = acd_request_wait(cdp, ATAPI_MODE_SENSE, 0, CDROM_AUDIO_PAGE,
  900                                      0, 0, 0, 0, 
  901                                      sizeof(cdp->au)>>8, sizeof(cdp->au), 0,
  902                                      (char *)&cdp->au, sizeof(cdp->au));
  903             if (error)
  904                 return error;
  905             if (cdp->flags & F_DEBUG)
  906                 atapi_dump(cdp->ata->ctrlr, cdp->lun, "au", &cdp->au,
  907                            sizeof(cdp->au));
  908             if (cdp->au.page_code != CDROM_AUDIO_PAGE)
  909                 return EIO;
  910             arg->vol[0] = cdp->au.port[0].volume;
  911             arg->vol[1] = cdp->au.port[1].volume;
  912             arg->vol[2] = cdp->au.port[2].volume;
  913             arg->vol[3] = cdp->au.port[3].volume;
  914         }
  915         break;
  916 
  917     case CDIOCSETVOL:
  918         {
  919             struct ioc_vol *arg = (struct ioc_vol *)addr;
  920 
  921             error = acd_request_wait(cdp, ATAPI_MODE_SENSE, 0, CDROM_AUDIO_PAGE,
  922                                      0, 0, 0, 0, 
  923                                      sizeof(cdp->au)>>8, sizeof(cdp->au), 0,
  924                                      (char *)&cdp->au, sizeof(cdp->au));
  925             if (error)
  926                 return error;
  927             if (cdp->flags & F_DEBUG)
  928                 atapi_dump(cdp->ata->ctrlr, cdp->lun, "au", &cdp->au, 
  929                            sizeof(cdp->au));
  930             if (cdp->au.page_code != CDROM_AUDIO_PAGE)
  931                 return EIO;
  932 
  933             error = acd_request_wait(cdp, ATAPI_MODE_SENSE, 0, 
  934                                      CDROM_AUDIO_PAGE_MASK, 0, 0, 0, 0, 
  935                                      sizeof(cdp->aumask)>>8,sizeof(cdp->aumask),
  936                                      0,
  937                                      (char *)&cdp->aumask, sizeof(cdp->aumask));
  938             if (error)
  939                 return error;
  940             if (cdp->flags & F_DEBUG)
  941                 atapi_dump(cdp->ata->ctrlr, cdp->lun, "mask", &cdp->aumask, 
  942                            sizeof(cdp->aumask));
  943 
  944             cdp->au.data_length = 0;
  945             cdp->au.port[0].channels = CHANNEL_0;
  946             cdp->au.port[1].channels = CHANNEL_1;
  947             cdp->au.port[0].volume = arg->vol[0] & cdp->aumask.port[0].volume;
  948             cdp->au.port[1].volume = arg->vol[1] & cdp->aumask.port[1].volume;
  949             cdp->au.port[2].volume = arg->vol[2] & cdp->aumask.port[2].volume;
  950             cdp->au.port[3].volume = arg->vol[3] & cdp->aumask.port[3].volume;
  951             return acd_request_wait(cdp, ATAPI_MODE_SELECT, 0x10,
  952                                     0, 0, 0, 0, 0, 
  953                                     sizeof(cdp->au)>>8, sizeof(cdp->au),
  954                                     0, (char *)&cdp->au, -sizeof(cdp->au));
  955         }
  956 
  957     case CDIOCSETPATCH:
  958         {
  959             struct ioc_patch *arg = (struct ioc_patch *)addr;
  960 
  961             return acd_setchan(cdp, arg->patch[0], arg->patch[1],
  962                                arg->patch[2], arg->patch[3]);
  963         }
  964 
  965     case CDIOCSETMONO:
  966         return acd_setchan(cdp, CHANNEL_0|CHANNEL_1, CHANNEL_0|CHANNEL_1, 0, 0);
  967 
  968     case CDIOCSETSTEREO:
  969         return acd_setchan(cdp, CHANNEL_0, CHANNEL_1, 0, 0);
  970 
  971     case CDIOCSETMUTE:
  972         return acd_setchan(cdp, 0, 0, 0, 0);
  973 
  974     case CDIOCSETLEFT:
  975         return acd_setchan(cdp, CHANNEL_0, CHANNEL_0, 0, 0);
  976 
  977     case CDIOCSETRIGHT:
  978         return acd_setchan(cdp, CHANNEL_1, CHANNEL_1, 0, 0);
  979 
  980     case CDRIOCNEXTWRITEABLEADDR:
  981         {
  982             struct acd_track_info track_info;
  983 
  984             if ((error = acd_read_track_info(cdp, 0xff, &track_info)))
  985                 break;
  986             if (!track_info.nwa_valid)
  987                 return EINVAL;
  988             cdp->next_writeable_lba = track_info.next_writeable_addr;
  989             *(int*)addr = track_info.next_writeable_addr;
  990         }
  991         break;
  992  
  993     case WORMIOCPREPDISK:
  994         {
  995             struct wormio_prepare_disk *w = (struct wormio_prepare_disk *)addr;
  996 
  997             if (w->dummy != 0 && w->dummy != 1)
  998                 error = EINVAL;
  999             else {
 1000                 error = acd_open_disk(cdp, w->dummy);
 1001                 if (error == 0) {
 1002                     cdp->flags |= F_DISK_PREPED;
 1003                     cdp->dummy = w->dummy;
 1004                     cdp->speed = w->speed;
 1005                 }
 1006             }
 1007         }
 1008         break;
 1009 
 1010     case WORMIOCPREPTRACK:
 1011         {
 1012             struct wormio_prepare_track *w =(struct wormio_prepare_track *)addr;
 1013 
 1014             if (w->audio != 0 && w->audio != 1)
 1015                 error = EINVAL;
 1016             else if (w->audio == 0 && w->preemp)
 1017                 error = EINVAL;
 1018             else if ((cdp->flags & F_DISK_PREPED) == 0) {
 1019                 error = EINVAL;
 1020                 printf("wcd%d: sequence error (PREP_TRACK)\n", cdp->lun);
 1021             } else {
 1022                 cdp->flags |= F_TRACK_PREP;
 1023                 cdp->preptrack = *w;
 1024             }
 1025         }
 1026         break;
 1027 
 1028     case WORMIOCFINISHTRACK:
 1029         if ((cdp->flags & F_TRACK_PREPED) != 0)
 1030             error = acd_close_track(cdp);
 1031         cdp->flags &= ~(F_TRACK_PREPED | F_TRACK_PREP);
 1032         break;
 1033 
 1034     case WORMIOCFIXATION:
 1035         {
 1036             struct wormio_fixation *w =
 1037             (struct wormio_fixation *)addr;
 1038 
 1039             if ((cdp->flags & F_WRITTEN) == 0)
 1040                 error = EINVAL;
 1041             else if (w->toc_type < 0 /* WORM_TOC_TYPE_AUDIO */ ||
 1042                 w->toc_type > 4 /* WORM_TOC_TYPE_CDI */ )
 1043                 error = EINVAL;
 1044             else if (w->onp != 0 && w->onp != 1)
 1045                 error = EINVAL;
 1046             else {
 1047                 /* no fixation needed if dummy write */
 1048                 if (cdp->dummy == 0)
 1049                     error = acd_close_disk(cdp);
 1050                 cdp->flags &=
 1051                     ~(F_WRITTEN|F_DISK_PREPED|F_TRACK_PREP|F_TRACK_PREPED);
 1052             }
 1053         }
 1054         break;
 1055 
 1056     case CDRIOCBLANK:
 1057         return acd_blank_disk(cdp);
 1058 
 1059     default:
 1060         return ENOTTY;
 1061     }
 1062     return error;
 1063 }
 1064 
 1065 static int 
 1066 acd_read_toc(struct acd *cdp)
 1067 {
 1068     int ntracks, len;
 1069     struct atapires result;
 1070 
 1071     bzero(&cdp->toc, sizeof(cdp->toc));
 1072     bzero(&cdp->info, sizeof(cdp->info));
 1073 
 1074     acd_select_slot(cdp);
 1075 
 1076     result = atapi_request_wait(cdp->ata, cdp->unit, ATAPI_TEST_UNIT_READY,
 1077                                 0, 0, 0, 0, 0, 0, 0, 0,
 1078                                 0, 0, 0, 0, 0, 0, 0, 0, 0);
 1079 
 1080     if (result.code == RES_ERR &&
 1081         (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION) {
 1082         cdp->flags |= F_MEDIA_CHANGED;
 1083         cdp->flags &= ~(F_WRITTEN|F_TRACK_PREP|F_TRACK_PREPED);
 1084         result = atapi_request_wait(cdp->ata, cdp->unit, ATAPI_TEST_UNIT_READY,
 1085                                     0, 0, 0, 0, 0, 0, 0, 0,
 1086                                     0, 0, 0, 0, 0, 0, 0, 0, 0);
 1087     }
 1088 
 1089     if (result.code) {
 1090         atapi_error(cdp->ata, cdp->unit, result);
 1091         return EIO;
 1092     }
 1093 
 1094     cdp->flags &= ~F_MEDIA_CHANGED;
 1095 
 1096     len = sizeof(struct ioc_toc_header) + sizeof(struct cd_toc_entry);
 1097     if (acd_request_wait(cdp, ATAPI_READ_TOC, 0, 0, 0, 0, 0, 0,
 1098                          len>>8, len & 0xff, 0, (char *)&cdp->toc, len) != 0) {
 1099         bzero(&cdp->toc, sizeof(cdp->toc));
 1100         return 0;
 1101     }
 1102     ntracks = cdp->toc.hdr.ending_track - cdp->toc.hdr.starting_track + 1;
 1103     if (ntracks <= 0 || ntracks > MAXTRK) {
 1104         bzero(&cdp->toc, sizeof(cdp->toc));
 1105         return 0;
 1106     }
 1107 
 1108     len = sizeof(struct ioc_toc_header) + ntracks * sizeof(struct cd_toc_entry);
 1109     if (acd_request_wait(cdp, ATAPI_READ_TOC, 0, 0, 0, 0, 0, 0,
 1110                          len>>8, len & 0xff, 0, (char *)&cdp->toc, len) & 0xff){
 1111         bzero(&cdp->toc, sizeof(cdp->toc));
 1112         return 0;
 1113     }
 1114 
 1115     cdp->toc.hdr.len = ntohs(cdp->toc.hdr.len);
 1116 
 1117     if (acd_request_wait(cdp, ATAPI_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 1118                          (char *)&cdp->info, sizeof(cdp->info)) != 0)
 1119         bzero(&cdp->info, sizeof(cdp->info));
 1120 
 1121     cdp->toc.tab[ntracks].control = cdp->toc.tab[ntracks - 1].control;
 1122     cdp->toc.tab[ntracks].addr_type = cdp->toc.tab[ntracks - 1].addr_type;
 1123     cdp->toc.tab[ntracks].track = 170;
 1124     cdp->toc.tab[ntracks].addr.lba = cdp->info.volsize;
 1125 
 1126     cdp->info.volsize = ntohl(cdp->info.volsize);
 1127     cdp->info.blksize = ntohl(cdp->info.blksize);
 1128 
 1129     if (cdp->info.volsize && cdp->toc.hdr.ending_track
 1130         && (cdp->flags & F_DEBUG)) {
 1131         printf("wcd%d: ", cdp->lun);
 1132         if (cdp->toc.tab[0].control & 4)
 1133             printf("%ldMB ", cdp->info.volsize / 512);
 1134         else
 1135             printf("%ld:%ld audio ", cdp->info.volsize / 75 / 60,
 1136                 cdp->info.volsize / 75 % 60);
 1137         printf("(%ld sectors (%ld bytes)), %d tracks\n", 
 1138             cdp->info.volsize, cdp->info.blksize,
 1139             cdp->toc.hdr.ending_track - cdp->toc.hdr.starting_track + 1);
 1140     }
 1141     return 0;
 1142 }
 1143 
 1144 /*
 1145  * Set up the audio channel masks.
 1146  */
 1147 static int 
 1148 acd_setchan(struct acd *cdp, u_char c0, u_char c1, u_char c2, u_char c3)
 1149 {
 1150     int error;
 1151 
 1152     error = acd_request_wait(cdp, ATAPI_MODE_SENSE, 0, CDROM_AUDIO_PAGE,
 1153                              0, 0, 0, 0, 
 1154                              sizeof(cdp->au)>>8, sizeof(cdp->au), 0,
 1155                              (char *)&cdp->au, sizeof(cdp->au));
 1156     if (error)
 1157         return error;
 1158     if (cdp->flags & F_DEBUG)
 1159         atapi_dump(cdp->ata->ctrlr, cdp->lun, "au", &cdp->au, sizeof(cdp->au));
 1160     if (cdp->au.page_code != CDROM_AUDIO_PAGE)
 1161         return EIO;
 1162 
 1163     cdp->au.data_length = 0;
 1164     cdp->au.port[0].channels = c0;
 1165     cdp->au.port[1].channels = c1;
 1166     cdp->au.port[2].channels = c2;
 1167     cdp->au.port[3].channels = c3;
 1168     return acd_request_wait(cdp, ATAPI_MODE_SELECT, 0x10,
 1169                             0, 0, 0, 0, 0, 
 1170                             sizeof(cdp->au)>>8, sizeof(cdp->au), 0,
 1171                             (char *)&cdp->au, -sizeof(cdp->au));
 1172 }
 1173 
 1174 static int 
 1175 acd_eject(struct acd *cdp, int close)
 1176 {
 1177     struct atapires result;
 1178 
 1179     acd_select_slot(cdp);
 1180 
 1181     result = atapi_request_wait(cdp->ata, cdp->unit, ATAPI_START_STOP, 1,
 1182                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 1183 
 1184     if (result.code == RES_ERR &&
 1185         ((result.error & AER_SKEY) == AER_SK_NOT_READY ||
 1186         (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)) {
 1187         int err;
 1188 
 1189         if (!close)
 1190             return 0;
 1191         err = acd_request_wait(cdp, ATAPI_START_STOP, 0, 0, 0, 3,
 1192                                0, 0, 0, 0, 0, 0, 0);
 1193         if (err)
 1194             return err;
 1195 
 1196         acd_read_toc(cdp);
 1197 
 1198         acd_request_wait(cdp, ATAPI_PREVENT_ALLOW, 0, 0, 0, 1,
 1199                          0, 0, 0, 0, 0, 0, 0);
 1200         cdp->flags |= F_LOCKED;
 1201         return 0;
 1202     }
 1203     if (result.code) {
 1204         atapi_error(cdp->ata, cdp->unit, result);
 1205         return EIO;
 1206     }
 1207     if (close)
 1208         return 0;
 1209 
 1210     tsleep((caddr_t) &lbolt, PRIBIO, "wcdej1", 0);
 1211     tsleep((caddr_t) &lbolt, PRIBIO, "wcdej2", 0);
 1212 
 1213     acd_request_wait(cdp, ATAPI_PREVENT_ALLOW, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 1214     cdp->flags &= ~F_LOCKED;
 1215 
 1216     cdp->flags |= F_MEDIA_CHANGED;
 1217     cdp->flags &= ~(F_WRITTEN|F_TRACK_PREP|F_TRACK_PREPED);
 1218     return acd_request_wait(cdp, ATAPI_START_STOP, 0, 0, 0, 2,
 1219                             0, 0, 0, 0, 0, 0, 0);
 1220 }
 1221 
 1222 static void
 1223 acd_select_slot(struct acd *cdp)
 1224 {
 1225     if (cdp->slot < 0 || cdp->changer_info->current_slot == cdp->slot)
 1226         return;
 1227 
 1228     /* Unlock (might not be needed but its cheaper than asking) */
 1229     acd_request_wait(cdp, ATAPI_PREVENT_ALLOW, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 1230 
 1231     /* Unload the current media from player */
 1232     acd_request_wait(cdp, ATAPI_LOAD_UNLOAD, 0, 0, 0, 2,
 1233                      0, 0, 0, cdp->changer_info->current_slot, 0, 0, 0);
 1234 
 1235     /* load the wanted slot */
 1236     acd_request_wait(cdp, ATAPI_LOAD_UNLOAD, 0, 0, 0, 3,
 1237                      0, 0, 0, cdp->slot, 0, 0, 0);
 1238 
 1239     cdp->changer_info->current_slot = cdp->slot;
 1240 
 1241     /* Lock the media if needed */
 1242     if (cdp->flags & F_LOCKED) {
 1243         acd_request_wait(cdp, ATAPI_PREVENT_ALLOW, 0, 0, 0, 1,
 1244                          0, 0, 0, 0, 0, 0, 0);
 1245     }
 1246 }
 1247 
 1248 static int
 1249 acd_open_disk(struct acd *cdp, int test)
 1250 {
 1251     cdp->next_writeable_lba = 0;
 1252     return 0;
 1253 }
 1254 
 1255 static int
 1256 acd_close_disk(struct acd *cdp)
 1257 {
 1258     return acd_request_wait(cdp, ATAPI_CLOSE_TRACK, 0x00,
 1259                             0x02, 0, 0, 0/*track*/, 0, 0, 0, 0, 0, 0);
 1260 }
 1261 
 1262 static int
 1263 acd_open_track(struct acd *cdp, struct wormio_prepare_track *ptp)
 1264 {
 1265     struct write_param param;
 1266     struct atapires result;
 1267 
 1268     result = atapi_request_wait(cdp->ata, cdp->unit, ATAPI_MODE_SENSE,
 1269                                 0, 0x05, 0, 0, 0, 0, 
 1270                                 sizeof(param)>>8, sizeof(param),
 1271                                 0, 0, 0, 0, 0, 0, 0,
 1272                                 (char *)&param, sizeof(param));
 1273 
 1274     if (cdp->flags & F_DEBUG)
 1275         atapi_dump(cdp->ata->ctrlr, cdp->lun, "0x05", &param, sizeof(param));
 1276 
 1277     if (result.code == RES_UNDERRUN)
 1278         result.code = 0;
 1279 
 1280     if (result.code) {
 1281         atapi_error(cdp->ata, cdp->unit, result);
 1282         return EIO;
 1283     }
 1284     param.page_code = 0x05;
 1285     param.page_length = 0x32;
 1286     param.test_write = cdp->dummy ? 1 : 0;
 1287     param.write_type = CDR_WTYPE_TRACK;
 1288 
 1289     switch (ptp->audio) {
 1290 /*    switch (data_type) { */
 1291 
 1292     case 0:
 1293 /*    case CDR_DATA: */
 1294         cdp->block_size = 2048;
 1295         param.track_mode = CDR_TMODE_DATA;
 1296         param.data_block_type = CDR_DB_ROM_MODE1;
 1297         param.session_format = CDR_SESS_CDROM;
 1298         break;
 1299 
 1300     default:
 1301 /*    case CDR_AUDIO: */
 1302         cdp->block_size = 2352;
 1303         if (ptp->preemp)
 1304             param.track_mode = CDR_TMODE_AUDIO;
 1305         else
 1306             param.track_mode = 0;
 1307         param.data_block_type = CDR_DB_RAW;
 1308         param.session_format = CDR_SESS_CDROM;
 1309         break;
 1310 
 1311 /*
 1312     case CDR_MODE2:
 1313         param.track_mode = CDR_TMODE_DATA;
 1314         param.data_block_type = CDR_DB_ROM_MODE2;
 1315         param.session_format = CDR_SESS_CDROM;
 1316         break;
 1317 
 1318     case CDR_XA1:
 1319         param.track_mode = CDR_TMODE_DATA;
 1320         param.data_block_type = CDR_DB_XA_MODE1;
 1321         param.session_format = CDR_SESS_CDROM_XA;
 1322         break;
 1323 
 1324     case CDR_XA2:
 1325         param.track_mode = CDR_TMODE_DATA;
 1326         param.data_block_type = CDR_DB_XA_MODE2_F1;
 1327         param.session_format = CDR_SESS_CDROM_XA;
 1328         break;
 1329 
 1330     case CDR_CDI:
 1331         param.track_mode = CDR_TMODE_DATA;
 1332         param.data_block_type = CDR_DB_XA_MODE2_F1;
 1333         param.session_format = CDR_SESS_CDI;
 1334         break;
 1335 */
 1336     }
 1337 
 1338     param.multi_session = CDR_MSES_NONE;
 1339     param.fp = 0;
 1340     param.packet_size = 0;
 1341 
 1342     if (cdp->flags & F_DEBUG)
 1343         atapi_dump(cdp->ata->ctrlr, cdp->lun, "0x05", &param, sizeof(param));
 1344 
 1345     result = atapi_request_wait(cdp->ata, cdp->unit, ATAPI_MODE_SELECT,
 1346                                 0x10, 0, 0, 0, 0, 0, 
 1347                                 sizeof(param)>>8, sizeof(param),
 1348                                 0, 0, 0, 0, 0, 0, 0,
 1349                                 (char *)&param, -sizeof(param));
 1350 
 1351     if (result.code == RES_UNDERRUN)
 1352         result.code = 0;
 1353 
 1354     if (result.code) {
 1355         atapi_error(cdp->ata, cdp->unit, result);
 1356         return EIO;
 1357     }
 1358     return 0;
 1359 }
 1360 
 1361 static int
 1362 acd_close_track(struct acd *cdp)
 1363 {
 1364     return acd_request_wait(cdp, ATAPI_SYNCHRONIZE_CACHE, 0,
 1365                             0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 1366 }
 1367 
 1368 static int
 1369 acd_read_track_info(struct acd *cdp, int lba, struct acd_track_info *info)
 1370 {
 1371     int error;
 1372 
 1373     error = acd_request_wait(cdp, ATAPI_READ_TRACK_INFO, 0x01,
 1374                              lba>>24, (lba>>16)&0xff,
 1375                              (lba>>8)&0xff, lba&0xff,
 1376                              0, 
 1377                              sizeof(*info)>>8, sizeof(*info), 0,
 1378                              (char *)info, sizeof(*info));
 1379     if (error)
 1380         return error;
 1381     info->track_start_addr = ntohl(info->track_start_addr);
 1382     info->next_writeable_addr = ntohl(info->next_writeable_addr);
 1383     info->free_blocks = ntohl(info->free_blocks);
 1384     info->fixed_packet_size = ntohl(info->fixed_packet_size);
 1385     info->track_length = ntohl(info->track_length);
 1386     return 0;
 1387 }
 1388 
 1389 static int
 1390 acd_blank_disk(struct acd *cdp)
 1391 {
 1392     int error;
 1393 
 1394     error = acd_request_wait(cdp, 0xa1, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 1395     cdp->flags |= F_MEDIA_CHANGED;
 1396     cdp->flags &= ~(F_WRITTEN|F_TRACK_PREP|F_TRACK_PREPED);
 1397     return error;
 1398 }
 1399 
 1400 static void
 1401 atapi_error(struct atapi *ata, int unit, struct atapires result)
 1402 {
 1403     if (result.code != RES_ERR) {
 1404         printf("atapi%d:%d: ERROR %d, status=%b, error=%b\n", 
 1405                ata->ctrlr, unit, result.code, result.status, 
 1406                ARS_BITS, result.error, AER_BITS);
 1407         return;
 1408     }
 1409     switch (result.error & AER_SKEY) {
 1410     case AER_SK_NOT_READY:
 1411         if (ata->debug)
 1412             printf("atapi%d:%d: not ready\n", ata->ctrlr, unit);
 1413         break;
 1414 
 1415     case AER_SK_BLANK_CHECK:
 1416         if (ata->debug)
 1417             printf("atapi%d:%d: blank check\n", ata->ctrlr, unit);
 1418         break;
 1419 
 1420     case AER_SK_MEDIUM_ERROR:
 1421         if (ata->debug)
 1422             printf("atapi%d:%d: medium error\n", ata->ctrlr, unit);
 1423         break;
 1424 
 1425     case AER_SK_HARDWARE_ERROR:
 1426         if (ata->debug)
 1427             printf("atapi%d:%d: hardware error\n", ata->ctrlr, unit);
 1428         break;
 1429 
 1430     case AER_SK_ILLEGAL_REQUEST:
 1431         if (ata->debug)
 1432             printf("atapi%d:%d: illegal request\n", ata->ctrlr, unit);
 1433         break;
 1434 
 1435     case AER_SK_UNIT_ATTENTION:
 1436         if (ata->debug)
 1437             printf("atapi%d:%d: unit attention\n", ata->ctrlr, unit);
 1438         break;
 1439 
 1440     case AER_SK_DATA_PROTECT:
 1441         if (ata->debug)
 1442             printf("atapi%d:%d: reading protected data\n", ata->ctrlr, unit);
 1443         break;
 1444 
 1445     case AER_SK_ABORTED_COMMAND:
 1446         if (ata->debug)
 1447             printf("atapi%d:%d: command aborted\n", ata->ctrlr, unit);
 1448         break;
 1449 
 1450     case AER_SK_MISCOMPARE:
 1451         if (ata->debug)
 1452             printf("atapi%d:%d: data don't match medium\n", ata->ctrlr, unit);
 1453         break;
 1454 
 1455     default:
 1456         if (ata->debug)
 1457             printf("atapi%d:%d: unknown error, status=%b, error=%b\n", 
 1458                    ata->ctrlr, unit, result.status, ARS_BITS, 
 1459                    result.error, AER_BITS);
 1460     }
 1461 }
 1462 
 1463 static void 
 1464 atapi_dump(int ctrlr, int lun, char *label, void *data, int len)
 1465 {
 1466         u_char *p = data;
 1467 
 1468         printf ("atapi%d%d: %s %x", ctrlr, lun, label, *p++);
 1469         while (--len > 0) printf ("-%x", *p++);
 1470         printf ("\n");
 1471 }
 1472 
 1473 static void 
 1474 acd_drvinit(void *unused)
 1475 {
 1476     cdevsw_add(&acd_cdevsw);
 1477 }
 1478 
 1479 SYSINIT(acddev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR, acd_drvinit, NULL)

Cache object: fda4c1b961c4c01f87f73ba15a6e9185


[ 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.