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/wcd.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  * IDE CD-ROM driver for FreeBSD.
    3  * Supports ATAPI-compatible drives.
    4  *
    5  * Copyright (C) 1995 Cronyx Ltd.
    6  * Author Serge Vakulenko, <vak@cronyx.ru>
    7  *
    8  * This software is distributed with NO WARRANTIES, not even the implied
    9  * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   10  *
   11  * Authors grant any other persons or organisations permission to use
   12  * or modify this software as long as this message is kept with the software,
   13  * all derivative works or modified versions.
   14  *
   15  * Version 1.9, Mon Oct  9 20:27:42 MSK 1995
   16  */
   17 
   18 #include "wdc.h"
   19 #include "wcd.h"
   20 #include "opt_atapi.h"
   21 
   22 #if NWCD > 0 && NWDC > 0 && defined (ATAPI)
   23 
   24 #include <sys/param.h>
   25 #include <sys/systm.h>
   26 #include <sys/kernel.h>
   27 #include <sys/proc.h>
   28 #include <sys/malloc.h>
   29 #include <sys/buf.h>
   30 #include <sys/ioctl.h>
   31 #include <sys/disklabel.h>
   32 #include <sys/cdio.h>
   33 #include <sys/conf.h>
   34 #ifdef DEVFS
   35 #include <sys/devfsext.h>
   36 #endif /*DEVFS*/
   37 
   38 #include <machine/cpufunc.h>
   39 
   40 #include <i386/isa/atapi.h>
   41 
   42 static  d_open_t        wcdropen;
   43 static  d_open_t        wcdbopen;
   44 static  d_close_t       wcdrclose;
   45 static  d_close_t       wcdbclose;
   46 static  d_ioctl_t       wcdioctl;
   47 static  d_strategy_t    wcdstrategy;
   48 
   49 #define CDEV_MAJOR 69
   50 #define BDEV_MAJOR 19
   51 extern  struct cdevsw wcd_cdevsw;
   52 static struct bdevsw wcd_bdevsw = 
   53         { wcdbopen,     wcdbclose,      wcdstrategy,    wcdioctl,       /*19*/
   54           nodump,       nopsize,        0,      "wcd",  &wcd_cdevsw,    -1 };
   55 
   56 static struct cdevsw wcd_cdevsw = 
   57         { wcdropen,     wcdrclose,      rawread,        nowrite,        /*69*/
   58           wcdioctl,     nostop,         nullreset,      nodevtotty,/* atapi */
   59           seltrue,      nommap,         wcdstrategy,    "wcd",
   60           &wcd_bdevsw,  -1 };
   61 
   62 #ifndef ATAPI_STATIC
   63 static
   64 #endif
   65 int  wcdattach(struct atapi*, int, struct atapi_params*, int);
   66 
   67 #define NUNIT   (NWDC*2)                /* Max. number of devices */
   68 #define UNIT(d) ((minor(d) >> 3) & 3)   /* Unit part of minor device number */
   69 #define SECSIZE 2048                    /* CD-ROM sector size in bytes */
   70 
   71 #define F_BOPEN         0x0001          /* The block device is opened */
   72 #define F_MEDIA_CHANGED 0x0002          /* The media have changed since open */
   73 #define F_DEBUG         0x0004          /* Print debug info */
   74 
   75 /*
   76  * Disc table of contents.
   77  */
   78 #define MAXTRK 99
   79 struct toc {
   80         struct ioc_toc_header hdr;
   81         struct cd_toc_entry tab[MAXTRK+1];      /* One extra for the leadout */
   82 };
   83 
   84 /*
   85  * Volume size info.
   86  */
   87 struct volinfo {
   88         u_long volsize;         /* Volume size in blocks */
   89         u_long blksize;         /* Block size in bytes */
   90 } info;
   91 
   92 /*
   93  * Current subchannel status.
   94  */
   95 struct subchan {
   96         u_char void0;
   97         u_char audio_status;
   98         u_short data_length;
   99         u_char data_format;
  100         u_char control;
  101         u_char track;
  102         u_char indx;
  103         u_long abslba;
  104         u_long rellba;
  105 };
  106 
  107 /*
  108  * Audio Control Parameters Page
  109  */
  110 struct audiopage {
  111         /* Mode data header */
  112         u_short data_length;
  113         u_char  medium_type;
  114         u_char  reserved1[5];
  115 
  116         /* Audio control page */
  117         u_char  page_code;
  118 #define AUDIO_PAGE      0x0e
  119 #define AUDIO_PAGE_MASK 0x4e            /* changeable values */
  120         u_char  param_len;
  121         u_char  flags;
  122 #define CD_PA_SOTC      0x02            /* mandatory */
  123 #define CD_PA_IMMED     0x04            /* always 1 */
  124         u_char  reserved3[3];
  125         u_short lb_per_sec;
  126         struct port_control {
  127                 u_char  channels : 4;
  128 #define CHANNEL_0       1               /* mandatory */
  129 #define CHANNEL_1       2               /* mandatory */
  130 #define CHANNEL_2       4               /* optional */
  131 #define CHANNEL_3       8               /* optional */
  132                 u_char  volume;
  133         } port[4];
  134 };
  135 
  136 /*
  137  * CD-ROM Capabilities and Mechanical Status Page
  138  */
  139 struct cappage {
  140         /* Mode data header */
  141         u_short data_length;
  142         u_char  medium_type;
  143 #define MDT_UNKNOWN     0x00
  144 #define MDT_DATA_120    0x01
  145 #define MDT_AUDIO_120   0x02
  146 #define MDT_COMB_120    0x03
  147 #define MDT_PHOTO_120   0x04
  148 #define MDT_DATA_80     0x05
  149 #define MDT_AUDIO_80    0x06
  150 #define MDT_COMB_80     0x07
  151 #define MDT_PHOTO_80    0x08
  152 #define MDT_NO_DISC     0x70
  153 #define MDT_DOOR_OPEN   0x71
  154 #define MDT_FMT_ERROR   0x72
  155         u_char  reserved1[5];
  156 
  157         /* Capabilities page */
  158         u_char  page_code;
  159 #define CAP_PAGE        0x2a
  160         u_char  param_len;
  161         u_char  reserved2[2];
  162 
  163         u_char  audio_play : 1;         /* audio play supported */
  164         u_char  composite : 1;          /* composite audio/video supported */
  165         u_char  dport1 : 1;             /* digital audio on port 1 */
  166         u_char  dport2 : 1;             /* digital audio on port 2 */
  167         u_char  mode2_form1 : 1;        /* mode 2 form 1 (XA) read */
  168         u_char  mode2_form2 : 1;        /* mode 2 form 2 format */
  169         u_char  multisession : 1;       /* multi-session photo-CD */
  170         u_char  : 1;
  171         u_char  cd_da : 1;              /* audio-CD read supported */
  172         u_char  cd_da_stream : 1;       /* CD-DA streaming */
  173         u_char  rw : 1;                 /* combined R-W subchannels */
  174         u_char  rw_corr : 1;            /* R-W subchannel data corrected */
  175         u_char  c2 : 1;                 /* C2 error pointers supported */
  176         u_char  isrc : 1;               /* can return the ISRC info */
  177         u_char  upc : 1;                /* can return the catalog number UPC */
  178         u_char  : 1;
  179         u_char  lock : 1;               /* could be locked */
  180         u_char  locked : 1;             /* current lock state */
  181         u_char  prevent : 1;            /* prevent jumper installed */
  182         u_char  eject : 1;              /* can eject */
  183         u_char  : 1;
  184         u_char  mech : 3;               /* loading mechanism type */
  185 #define MECH_CADDY      0
  186 #define MECH_TRAY       1
  187 #define MECH_POPUP      2
  188 #define MECH_CHANGER    4
  189 #define MECH_CARTRIDGE  5
  190         u_char  sep_vol : 1;            /* independent volume of channels */
  191         u_char  sep_mute : 1;           /* independent mute of channels */
  192         u_char  : 6;
  193 
  194         u_short max_speed;              /* max raw data rate in bytes/1000 */
  195         u_short max_vol_levels;         /* number of discrete volume levels */
  196         u_short buf_size;               /* internal buffer size in bytes/1024 */
  197         u_short cur_speed;              /* current data rate in bytes/1000  */
  198 
  199         /* Digital drive output format description (optional?) */
  200         u_char  reserved3;
  201         u_char  bckf : 1;               /* data valid on failing edge of BCK */
  202         u_char  rch : 1;                /* high LRCK indicates left channel */
  203         u_char  lsbf : 1;               /* set if LSB first */
  204         u_char  dlen: 2;
  205 #define DLEN_32         0               /* 32 BCKs */
  206 #define DLEN_16         1               /* 16 BCKs */
  207 #define DLEN_24         2               /* 24 BCKs */
  208 #define DLEN_24_I2S     3               /* 24 BCKs (I2S) */
  209         u_char  : 3;
  210         u_char  reserved4[2];
  211 };
  212 
  213 struct wcd {
  214         struct atapi *ata;              /* Controller structure */
  215         int unit;                       /* IDE bus drive unit */
  216         int lun;                        /* Logical device unit */
  217         int flags;                      /* Device state flags */
  218         int refcnt;                     /* The number of raw opens */
  219         struct buf_queue_head buf_queue;               /* Queue of i/o requests */
  220         struct atapi_params *param;     /* Drive parameters table */
  221         struct toc toc;                 /* Table of disc contents */
  222         struct volinfo info;            /* Volume size info */
  223         struct audiopage au;            /* Audio page info */
  224         struct cappage cap;             /* Capabilities page info */
  225         struct audiopage aumask;        /* Audio page mask */
  226         struct subchan subchan;         /* Subchannel info */
  227         char description[80];           /* Device description */
  228         int starting_lba ;
  229 #ifdef  DEVFS
  230         void    *ra_devfs_token;
  231         void    *rc_devfs_token;
  232         void    *a_devfs_token;
  233         void    *c_devfs_token;
  234 #endif
  235 };
  236 
  237 struct wcd *wcdtab[NUNIT];      /* Drive info by unit number */
  238 static int wcdnlun = 0;         /* Number of configured drives */
  239 
  240 static void wcd_start (struct wcd *t);
  241 static void wcd_done (struct wcd *t, struct buf *bp, int resid,
  242         struct atapires result);
  243 static void wcd_error (struct wcd *t, struct atapires result);
  244 static int wcd_read_toc (struct wcd *t);
  245 static int wcd_request_wait (struct wcd *t, u_char cmd, u_char a1, u_char a2,
  246         u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
  247         u_char a9, char *addr, int count);
  248 static void wcd_describe (struct wcd *t);
  249 static int wcd_open(dev_t dev, int rawflag);
  250 static int wcd_setchan (struct wcd *t,
  251         u_char c0, u_char c1, u_char c2, u_char c3);
  252 static int wcd_eject (struct wcd *t, int closeit);
  253 
  254 /*
  255  * Dump the array in hexadecimal format for debugging purposes.
  256  */
  257 static void wcd_dump (int lun, char *label, void *data, int len)
  258 {
  259         u_char *p = data;
  260 
  261         printf ("wcd%d: %s %x", lun, label, *p++);
  262         while (--len > 0)
  263                 printf ("-%x", *p++);
  264         printf ("\n");
  265 }
  266 
  267 #ifndef ATAPI_STATIC
  268 static
  269 #endif
  270 int 
  271 wcdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug)
  272 {
  273         struct wcd *t;
  274         struct atapires result;
  275         int lun;
  276 
  277         if (wcdnlun >= NUNIT) {
  278                 printf ("wcd: too many units\n");
  279                 return (0);
  280         }
  281         if (!atapi_request_immediate) {
  282                 printf("wcd: configuration error, ATAPI core code not present!\n");
  283                 printf("wcd: check `options ATAPI_STATIC' in your kernel config file!\n");
  284                 return (0);
  285         }
  286         t = malloc (sizeof (struct wcd), M_TEMP, M_NOWAIT);
  287         if (! t) {
  288                 printf ("wcd: out of memory\n");
  289                 return (0);
  290         }
  291         wcdtab[wcdnlun] = t;
  292         bzero (t, sizeof (struct wcd));
  293         bufq_init(&t->buf_queue);
  294         t->ata = ata;
  295         t->unit = unit;
  296         lun = t->lun = wcdnlun++;
  297         t->param = ap;
  298         t->flags = F_MEDIA_CHANGED;
  299         t->starting_lba = 0;
  300         t->refcnt = 0;
  301         if (debug) {
  302                 t->flags |= F_DEBUG;
  303                 /* Print params. */
  304                 wcd_dump (t->lun, "info", ap, sizeof *ap);
  305         }
  306 
  307         /* Get drive capabilities. */
  308         result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
  309                 0, CAP_PAGE, 0, 0, 0, 0, sizeof (t->cap) >> 8, sizeof (t->cap),
  310                 0, 0, 0, 0, 0, 0, 0, (char*) &t->cap, sizeof (t->cap));
  311 
  312         /* Do it twice to avoid the stale media changed state. */
  313         if (result.code == RES_ERR &&
  314             (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)
  315                 result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
  316                         0, CAP_PAGE, 0, 0, 0, 0, sizeof (t->cap) >> 8,
  317                         sizeof (t->cap), 0, 0, 0, 0, 0, 0, 0,
  318                         (char*) &t->cap, sizeof (t->cap));
  319 
  320         /* Some drives have shorter capabilities page. */
  321         if (result.code == RES_UNDERRUN)
  322                 result.code = 0;
  323 
  324         if (result.code == 0) {
  325                 wcd_describe (t);
  326                 if (t->flags & F_DEBUG)
  327                         wcd_dump (t->lun, "cap", &t->cap, sizeof t->cap);
  328         }
  329 
  330 
  331 #ifdef DEVFS
  332         t->ra_devfs_token = 
  333                 devfs_add_devswf(&wcd_cdevsw, dkmakeminor(lun, 0, 0),
  334                                  DV_CHR, UID_ROOT, GID_OPERATOR, 0640,
  335                                  "rwcd%da", lun);
  336         t->rc_devfs_token = 
  337                 devfs_add_devswf(&wcd_cdevsw, dkmakeminor(lun, 0, RAW_PART),
  338                                  DV_CHR, UID_ROOT, GID_OPERATOR, 0640,
  339                                  "rwcd%dc", lun);
  340         t->a_devfs_token = 
  341                 devfs_add_devswf(&wcd_bdevsw, dkmakeminor(lun, 0, 0),
  342                                  DV_BLK, UID_ROOT, GID_OPERATOR, 0640,
  343                                  "wcd%da", lun);
  344         t->c_devfs_token = 
  345                 devfs_add_devswf(&wcd_bdevsw, dkmakeminor(lun, 0, RAW_PART),
  346                                  DV_BLK, UID_ROOT, GID_OPERATOR, 0640,
  347                                  "wcd%dc", lun);
  348 #endif
  349         return (1);
  350 }
  351 
  352 void wcd_describe (struct wcd *t)
  353 {
  354         char *m;
  355 
  356         t->cap.max_speed      = ntohs (t->cap.max_speed);
  357         t->cap.max_vol_levels = ntohs (t->cap.max_vol_levels);
  358         t->cap.buf_size       = ntohs (t->cap.buf_size);
  359         t->cap.cur_speed      = ntohs (t->cap.cur_speed);
  360 
  361         printf ("wcd%d: ", t->lun);
  362         if (t->cap.cur_speed != t->cap.max_speed)
  363                 printf ("%d/", t->cap.cur_speed * 1000 / 1024);
  364         printf ("%dKB/sec", t->cap.max_speed * 1000 / 1024);
  365         if (t->cap.buf_size)
  366                 printf (", %dKB cache", t->cap.buf_size);
  367 
  368         if (t->cap.audio_play)
  369                 printf (", audio play");
  370         if (t->cap.max_vol_levels)
  371                 printf (", %d volume levels", t->cap.max_vol_levels);
  372 
  373         switch (t->cap.mech) {
  374         default:             m = 0;           break;
  375         case MECH_CADDY:     m = "caddy";     break;
  376         case MECH_TRAY:      m = "tray";      break;
  377         case MECH_POPUP:     m = "popup";     break;
  378         case MECH_CHANGER:   m = "changer";   break;
  379         case MECH_CARTRIDGE: m = "cartridge"; break;
  380         }
  381         if (m)
  382                 printf (", %s%s", t->cap.eject ? "ejectable " : "", m);
  383         else if (t->cap.eject)
  384                 printf (", eject");
  385         printf ("\n");
  386 
  387         printf ("wcd%d: ", t->lun);
  388         switch (t->cap.medium_type) {
  389         case MDT_UNKNOWN:   printf ("medium type unknown");          break;
  390         case MDT_DATA_120:  printf ("120mm data disc loaded");       break;
  391         case MDT_AUDIO_120: printf ("120mm audio disc loaded");      break;
  392         case MDT_COMB_120:  printf ("120mm data/audio disc loaded"); break;
  393         case MDT_PHOTO_120: printf ("120mm photo disc loaded");      break;
  394         case MDT_DATA_80:   printf ("80mm data disc loaded");        break;
  395         case MDT_AUDIO_80:  printf ("80mm audio disc loaded");       break;
  396         case MDT_COMB_80:   printf ("80mm data/audio disc loaded");  break;
  397         case MDT_PHOTO_80:  printf ("80mm photo disc loaded");       break;
  398         case MDT_NO_DISC:   printf ("no disc inside");               break;
  399         case MDT_DOOR_OPEN: printf ("door open");                    break;
  400         case MDT_FMT_ERROR: printf ("medium format error");          break;
  401         default:    printf ("medium type=0x%x", t->cap.medium_type); break;
  402         }
  403         if (t->cap.lock)
  404                 printf (t->cap.locked ? ", locked" : ", unlocked");
  405         if (t->cap.prevent)
  406                 printf (", lock protected");
  407         printf ("\n");
  408 }
  409 
  410 static int 
  411 wcd_open (dev_t dev, int rawflag)
  412 {
  413         int lun = UNIT(dev);
  414         int track = dkslice(dev); /* XXX */
  415         struct wcd *t;
  416 
  417         /* Check that the device number is legal
  418          * and the ATAPI driver is loaded. */
  419         if (lun >= wcdnlun || ! atapi_request_immediate)
  420                 return (ENXIO);
  421         t = wcdtab[lun];
  422 
  423         /* On the first open, read the table of contents. */
  424         if (! (t->flags & F_BOPEN) && ! t->refcnt) {
  425                 /* Read table of contents. */
  426                 if (wcd_read_toc (t) < 0)
  427                         return (EIO);
  428 
  429                 /* Lock the media. */
  430                 wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
  431                         0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
  432         }
  433         if (rawflag)
  434                 ++t->refcnt;
  435         else
  436                 t->flags |= F_BOPEN;
  437         t->starting_lba = ntohl(t->toc.tab[track].addr.lba) ;
  438         if (track != 0) { 
  439                 printf("Warning, opening track %d at %d\n",
  440                         track, t->starting_lba);
  441         }
  442         return (0);
  443 }
  444 
  445 int wcdbopen (dev_t dev, int flags, int fmt, struct proc *p)
  446 {
  447         return wcd_open (dev, 0);
  448 }
  449 
  450 int wcdropen (dev_t dev, int flags, int fmt, struct proc *p)
  451 {
  452         return wcd_open (dev, 1);
  453 }
  454 
  455 /*
  456  * Close the device.  Only called if we are the LAST
  457  * occurence of an open device.
  458  */
  459 int wcdbclose (dev_t dev, int flags, int fmt, struct proc *p)
  460 {
  461         int lun = UNIT(dev);
  462         struct wcd *t = wcdtab[lun];
  463 
  464         /* If we were the last open of the entire device, release it. */
  465         if (! t->refcnt)
  466                 wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
  467                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  468         t->flags &= ~F_BOPEN;
  469         return (0);
  470 }
  471 
  472 int wcdrclose (dev_t dev, int flags, int fmt, struct proc *p)
  473 {
  474         int lun = UNIT(dev);
  475         struct wcd *t = wcdtab[lun];
  476 
  477         /* If we were the last open of the entire device, release it. */
  478         if (! (t->flags & F_BOPEN) && t->refcnt == 1)
  479                 wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
  480                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  481         --t->refcnt;
  482         return (0);
  483 }
  484 
  485 /*
  486  * Actually translate the requested transfer into one the physical driver can
  487  * understand. The transfer is described by a buf and will include only one
  488  * physical transfer.
  489  */
  490 void wcdstrategy (struct buf *bp)
  491 {
  492         int lun = UNIT(bp->b_dev);
  493         struct wcd *t = wcdtab[lun];
  494         int x;
  495 
  496         /* Can't ever write to a CD. */
  497         if (! (bp->b_flags & B_READ)) {
  498                 bp->b_error = EROFS;
  499                 bp->b_flags |= B_ERROR;
  500                 biodone (bp);
  501                 return;
  502         }
  503 
  504         /* If it's a null transfer, return immediatly. */
  505         if (bp->b_bcount == 0) {
  506                 bp->b_resid = 0;
  507                 biodone (bp);
  508                 return;
  509         }
  510 
  511         /* Process transfer request. */
  512         bp->b_pblkno = bp->b_blkno;
  513         bp->b_resid = bp->b_bcount;
  514 
  515         x = splbio();
  516 
  517         /* Place it in the queue of disk activities for this disk. */
  518         bufqdisksort (&t->buf_queue, bp);
  519 
  520         /* Tell the device to get going on the transfer if it's
  521          * not doing anything, otherwise just wait for completion. */
  522         wcd_start (t);
  523         splx(x);
  524 }
  525 
  526 /*
  527  * Look to see if there is a buf waiting for the device
  528  * and that the device is not already busy. If both are true,
  529  * It dequeues the buf and creates an ATAPI command to perform the
  530  * transfer in the buf.
  531  * The bufs are queued by the strategy routine (wcdstrategy).
  532  * Must be called at the correct (splbio) level.
  533  */
  534 static void wcd_start (struct wcd *t)
  535 {
  536         struct buf *bp = bufq_first(&t->buf_queue);
  537         u_long blkno, nblk;
  538 
  539         /* See if there is a buf to do and we are not already doing one. */
  540         if (! bp)
  541                 return;
  542 
  543         /* Unqueue the request. */
  544         bufq_remove(&t->buf_queue, bp);
  545 
  546         /* Should reject all queued entries if media have changed. */
  547         if (t->flags & F_MEDIA_CHANGED) {
  548                 bp->b_error = EIO;
  549                 bp->b_flags |= B_ERROR;
  550                 biodone (bp);
  551                 return;
  552         }
  553 
  554         /* We have a buf, now we should make a command
  555          * First, translate the block to absolute and put it in terms of the
  556          * logical blocksize of the device.
  557          * What if something asks for 512 bytes not on a 2k boundary? */
  558         blkno = t->starting_lba + bp->b_blkno / (SECSIZE / 512);
  559         nblk = (bp->b_bcount + (SECSIZE - 1)) / SECSIZE;
  560 
  561         atapi_request_callback (t->ata, t->unit, ATAPI_READ_BIG, 0,
  562                 blkno>>24, blkno>>16, blkno>>8, blkno, 0, nblk>>8, nblk, 0, 0,
  563                 0, 0, 0, 0, 0, (u_char*) bp->b_un.b_addr, bp->b_bcount,
  564                 wcd_done, t, bp);
  565 }
  566 
  567 static void wcd_done (struct wcd *t, struct buf *bp, int resid,
  568         struct atapires result)
  569 {
  570         if (result.code) {
  571                 wcd_error (t, result);
  572                 bp->b_error = EIO;
  573                 bp->b_flags |= B_ERROR;
  574         } else
  575                 bp->b_resid = resid;
  576         biodone (bp);
  577         wcd_start (t);
  578 }
  579 
  580 static void wcd_error (struct wcd *t, struct atapires result)
  581 {
  582         if (result.code != RES_ERR)
  583                 return;
  584         switch (result.error & AER_SKEY) {
  585         case AER_SK_NOT_READY:
  586                 if (result.error & ~AER_SKEY) {
  587                         /* Audio disc. */
  588                         printf ("wcd%d: cannot read audio disc\n", t->lun);
  589                         return;
  590                 }
  591                 /* Tray open. */
  592                 if (! (t->flags & F_MEDIA_CHANGED))
  593                         printf ("wcd%d: tray open\n", t->lun);
  594                 t->flags |= F_MEDIA_CHANGED;
  595                 return;
  596 
  597         case AER_SK_UNIT_ATTENTION:
  598                 /* Media changed. */
  599                 if (! (t->flags & F_MEDIA_CHANGED))
  600                         printf ("wcd%d: media changed\n", t->lun);
  601                 t->flags |= F_MEDIA_CHANGED;
  602                 return;
  603 
  604         case AER_SK_ILLEGAL_REQUEST:
  605                 /* Unknown command or invalid command arguments. */
  606                 if (t->flags & F_DEBUG)
  607                         printf ("wcd%d: invalid command\n", t->lun);
  608                 return;
  609         }
  610         printf ("wcd%d: i/o error, status=%b, error=%b\n", t->lun,
  611                 result.status, ARS_BITS, result.error, AER_BITS);
  612 }
  613 
  614 static int wcd_request_wait (struct wcd *t, u_char cmd, u_char a1, u_char a2,
  615         u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
  616         u_char a9, char *addr, int count)
  617 {
  618         struct atapires result;
  619 
  620         result = atapi_request_wait (t->ata, t->unit, cmd,
  621                 a1, a2, a3, a4, a5, a6, a7, a8, a9, 0, 0, 0, 0, 0, 0,
  622                 addr, count);
  623         if (result.code) {
  624                 wcd_error (t, result);
  625                 return (EIO);
  626         }
  627         return (0);
  628 }
  629 
  630 static __inline void lba2msf (int lba, u_char *m, u_char *s, u_char *f)
  631 {
  632         lba += 150;             /* offset of first logical frame */
  633         lba &= 0xffffff;        /* negative lbas use only 24 bits */
  634         *m = lba / (60 * 75);
  635         lba %= (60 * 75);
  636         *s = lba / 75;
  637         *f = lba % 75;
  638 }
  639 
  640 /*
  641  * Perform special action on behalf of the user.
  642  * Knows about the internals of this device
  643  */
  644 int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
  645 {
  646         int lun = UNIT(dev);
  647         struct wcd *t = wcdtab[lun];
  648         int error = 0;
  649 
  650         if (t->flags & F_MEDIA_CHANGED)
  651                 switch (cmd) {
  652                 case CDIOCSETDEBUG:
  653                 case CDIOCCLRDEBUG:
  654                 case CDIOCRESET:
  655                         /* These ops are media change transparent. */
  656                         break;
  657                 default:
  658                         /* Read table of contents. */
  659                         wcd_read_toc (t);
  660 
  661                         /* Lock the media. */
  662                         wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
  663                                 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
  664                         break;
  665                 }
  666         switch (cmd) {
  667         default:
  668                 return (ENOTTY);
  669 
  670         case CDIOCSETDEBUG:
  671                 if (p->p_cred->pc_ucred->cr_uid)
  672                         return (EPERM);
  673                 t->flags |= F_DEBUG;
  674                 atapi_debug (t->ata, 1);
  675                 return 0;
  676 
  677         case CDIOCCLRDEBUG:
  678                 if (p->p_cred->pc_ucred->cr_uid)
  679                         return (EPERM);
  680                 t->flags &= ~F_DEBUG;
  681                 atapi_debug (t->ata, 0);
  682                 return 0;
  683 
  684         case CDIOCRESUME:
  685                 return wcd_request_wait (t, ATAPI_PAUSE,
  686                         0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);
  687 
  688         case CDIOCPAUSE:
  689                 return wcd_request_wait (t, ATAPI_PAUSE,
  690                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  691 
  692         case CDIOCSTART:
  693                 return wcd_request_wait (t, ATAPI_START_STOP,
  694                         1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
  695 
  696         case CDIOCSTOP:
  697                 return wcd_request_wait (t, ATAPI_START_STOP,
  698                         1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  699 
  700         case CDIOCALLOW:
  701                 return wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
  702                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  703 
  704         case CDIOCPREVENT:
  705                 return wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
  706                         0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
  707 
  708         case CDIOCRESET:
  709                 if (p->p_cred->pc_ucred->cr_uid)
  710                         return (EPERM);
  711                 return wcd_request_wait (t, ATAPI_TEST_UNIT_READY,
  712                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  713 
  714         case CDIOCEJECT:
  715                 /* Don't allow eject if the device is opened
  716                  * by somebody (not us) in block mode. */
  717                 if ((t->flags & F_BOPEN) && t->refcnt)
  718                         return (EBUSY);
  719                 return wcd_eject (t, 0);
  720 
  721         case CDIOCCLOSE:
  722                 if ((t->flags & F_BOPEN) && t->refcnt)
  723                         return (0);
  724                 return wcd_eject (t, 1);
  725 
  726         case CDIOREADTOCHEADER:
  727                 if (! t->toc.hdr.ending_track)
  728                         return (EIO);
  729                 bcopy (&t->toc.hdr, addr, sizeof t->toc.hdr);
  730                 break;
  731 
  732         case CDIOREADTOCENTRYS: {
  733                 struct ioc_read_toc_entry *te =
  734                         (struct ioc_read_toc_entry*) addr;
  735                 struct toc *toc = &t->toc;
  736                 struct toc buf;
  737                 u_long len;
  738                 u_char starting_track = te->starting_track;
  739 
  740                 if (! t->toc.hdr.ending_track)
  741                         return (EIO);
  742 
  743                 if (   te->data_len < sizeof(toc->tab[0])
  744                     || (te->data_len % sizeof(toc->tab[0])) != 0
  745                     || te->address_format != CD_MSF_FORMAT
  746                     && te->address_format != CD_LBA_FORMAT
  747                    )
  748                         return EINVAL;
  749 
  750                 if (starting_track == 0)
  751                         starting_track = toc->hdr.starting_track;
  752                 else if (starting_track == 170) /* Handle leadout request */
  753                         starting_track = toc->hdr.ending_track + 1;
  754                 else if (starting_track < toc->hdr.starting_track ||
  755                          starting_track > toc->hdr.ending_track + 1)
  756                         return (EINVAL);
  757 
  758                 len = ((toc->hdr.ending_track + 1 - starting_track) + 1) *
  759                         sizeof(toc->tab[0]);
  760                 if (te->data_len < len)
  761                         len = te->data_len;
  762                 if (len > sizeof(toc->tab))
  763                         return EINVAL;
  764 
  765                 /* Convert to MSF format, if needed. */
  766                 if (te->address_format == CD_MSF_FORMAT) {
  767                         struct cd_toc_entry *e;
  768 
  769                         buf = t->toc;
  770                         toc = &buf;
  771                         e = toc->tab + (toc->hdr.ending_track + 1 -
  772                                         toc->hdr.starting_track) + 1;
  773                         while (--e >= toc->tab)
  774                                 lba2msf (ntohl(e->addr.lba), &e->addr.msf.minute,
  775                                     &e->addr.msf.second, &e->addr.msf.frame);
  776                 }
  777                 return copyout (toc->tab + starting_track -
  778                                 toc->hdr.starting_track, te->data, len);
  779         }
  780         case CDIOCREADSUBCHANNEL: {
  781                 struct ioc_read_subchannel *args =
  782                         (struct ioc_read_subchannel*) addr;
  783                 struct cd_sub_channel_info data;
  784                 u_long len = args->data_len;
  785                 int abslba, rellba;
  786 
  787                 if (len > sizeof(data) ||
  788                     len < sizeof(struct cd_sub_channel_header))
  789                         return (EINVAL);
  790 
  791                 if (wcd_request_wait (t, ATAPI_READ_SUBCHANNEL, 0, 0x40, 1, 0,
  792                     0, 0, sizeof (t->subchan) >> 8, sizeof (t->subchan),
  793                     0, (char*)&t->subchan, sizeof (t->subchan)) != 0)
  794                         return (EIO);
  795                 if (t->flags & F_DEBUG)
  796                         wcd_dump (t->lun, "subchan", &t->subchan, sizeof t->subchan);
  797 
  798                 abslba = t->subchan.abslba;
  799                 rellba = t->subchan.rellba;
  800                 if (args->address_format == CD_MSF_FORMAT) {
  801                         lba2msf (ntohl(abslba),
  802                                 &data.what.position.absaddr.msf.minute,
  803                                 &data.what.position.absaddr.msf.second,
  804                                 &data.what.position.absaddr.msf.frame);
  805                         lba2msf (ntohl(rellba),
  806                                 &data.what.position.reladdr.msf.minute,
  807                                 &data.what.position.reladdr.msf.second,
  808                                 &data.what.position.reladdr.msf.frame);
  809                 } else {
  810                         data.what.position.absaddr.lba = abslba;
  811                         data.what.position.reladdr.lba = rellba;
  812                 }
  813                 data.header.audio_status = t->subchan.audio_status;
  814                 data.what.position.control = t->subchan.control & 0xf;
  815                 data.what.position.addr_type = t->subchan.control >> 4;
  816                 data.what.position.track_number = t->subchan.track;
  817                 data.what.position.index_number = t->subchan.indx;
  818 
  819                 return copyout (&data, args->data, len);
  820         }
  821         case CDIOCPLAYMSF: {
  822                 struct ioc_play_msf *args = (struct ioc_play_msf*) addr;
  823 
  824                 return wcd_request_wait (t, ATAPI_PLAY_MSF, 0, 0,
  825                         args->start_m, args->start_s, args->start_f,
  826                         args->end_m, args->end_s, args->end_f, 0, 0, 0);
  827         }
  828         case CDIOCPLAYBLOCKS: {
  829                 struct ioc_play_blocks *args = (struct ioc_play_blocks*) addr;
  830 
  831                 return wcd_request_wait (t, ATAPI_PLAY_BIG, 0,
  832                         args->blk >> 24 & 0xff, args->blk >> 16 & 0xff,
  833                         args->blk >> 8 & 0xff, args->blk & 0xff,
  834                         args->len >> 24 & 0xff, args->len >> 16 & 0xff,
  835                         args->len >> 8 & 0xff, args->len & 0xff, 0, 0);
  836         }
  837         case CDIOCPLAYTRACKS: {
  838                 struct ioc_play_track *args = (struct ioc_play_track*) addr;
  839                 u_long start, len;
  840                 int t1, t2;
  841 
  842                 if (! t->toc.hdr.ending_track)
  843                         return (EIO);
  844 
  845                 /* Ignore index fields,
  846                  * play from start_track to end_track inclusive. */
  847                 if (args->end_track < t->toc.hdr.ending_track+1)
  848                         ++args->end_track;
  849                 if (args->end_track > t->toc.hdr.ending_track+1)
  850                         args->end_track = t->toc.hdr.ending_track+1;
  851                 t1 = args->start_track - t->toc.hdr.starting_track;
  852                 t2 = args->end_track - t->toc.hdr.starting_track;
  853                 if (t1 < 0 || t2 < 0)
  854                         return (EINVAL);
  855                 start = ntohl(t->toc.tab[t1].addr.lba);
  856                 len = ntohl(t->toc.tab[t2].addr.lba) - start;
  857 
  858                 return wcd_request_wait (t, ATAPI_PLAY_BIG, 0,
  859                         start >> 24 & 0xff, start >> 16 & 0xff,
  860                         start >> 8 & 0xff, start & 0xff,
  861                         len >> 24 & 0xff, len >> 16 & 0xff,
  862                         len >> 8 & 0xff, len & 0xff, 0, 0);
  863         }
  864         case CDIOCGETVOL: {
  865                 struct ioc_vol *arg = (struct ioc_vol*) addr;
  866 
  867                 error = wcd_request_wait (t, ATAPI_MODE_SENSE, 0, AUDIO_PAGE,
  868                         0, 0, 0, 0, sizeof (t->au) >> 8, sizeof (t->au), 0,
  869                         (char*) &t->au, sizeof (t->au));
  870                 if (error)
  871                         return (error);
  872                 if (t->flags & F_DEBUG)
  873                         wcd_dump (t->lun, "au", &t->au, sizeof t->au);
  874                 if (t->au.page_code != AUDIO_PAGE)
  875                         return (EIO);
  876                 arg->vol[0] = t->au.port[0].volume;
  877                 arg->vol[1] = t->au.port[1].volume;
  878                 arg->vol[2] = t->au.port[2].volume;
  879                 arg->vol[3] = t->au.port[3].volume;
  880                 break;
  881         }
  882         case CDIOCSETVOL: {
  883                 struct ioc_vol *arg = (struct ioc_vol*) addr;
  884 
  885                 error = wcd_request_wait (t, ATAPI_MODE_SENSE, 0, AUDIO_PAGE,
  886                         0, 0, 0, 0, sizeof (t->au) >> 8, sizeof (t->au), 0,
  887                         (char*) &t->au, sizeof (t->au));
  888                 if (error)
  889                         return (error);
  890                 if (t->flags & F_DEBUG)
  891                         wcd_dump (t->lun, "au", &t->au, sizeof t->au);
  892                 if (t->au.page_code != AUDIO_PAGE)
  893                         return (EIO);
  894 
  895                 error = wcd_request_wait (t, ATAPI_MODE_SENSE, 0,
  896                         AUDIO_PAGE_MASK, 0, 0, 0, 0, sizeof (t->aumask) >> 8,
  897                         sizeof (t->aumask), 0, (char*) &t->aumask,
  898                         sizeof (t->aumask));
  899                 if (error)
  900                         return (error);
  901                 if (t->flags & F_DEBUG)
  902                         wcd_dump (t->lun, "mask", &t->aumask, sizeof t->aumask);
  903 
  904                 /* Sony-55E requires the data length field to be zeroed. */
  905                 t->au.data_length = 0;
  906 
  907                 t->au.port[0].channels = CHANNEL_0;
  908                 t->au.port[1].channels = CHANNEL_1;
  909                 t->au.port[0].volume = arg->vol[0] & t->aumask.port[0].volume;
  910                 t->au.port[1].volume = arg->vol[1] & t->aumask.port[1].volume;
  911                 t->au.port[2].volume = arg->vol[2] & t->aumask.port[2].volume;
  912                 t->au.port[3].volume = arg->vol[3] & t->aumask.port[3].volume;
  913                 return wcd_request_wait (t, ATAPI_MODE_SELECT_BIG, 0x10,
  914                         0, 0, 0, 0, 0, sizeof (t->au) >> 8, sizeof (t->au),
  915                         0, (char*) &t->au, - sizeof (t->au));
  916         }
  917         case CDIOCSETPATCH: {
  918                 struct ioc_patch *arg = (struct ioc_patch*) addr;
  919 
  920                 return wcd_setchan (t, arg->patch[0], arg->patch[1],
  921                         arg->patch[2], arg->patch[3]);
  922         }
  923         case CDIOCSETMONO:
  924                 return wcd_setchan (t, CHANNEL_0 | CHANNEL_1,
  925                         CHANNEL_0 | CHANNEL_1, 0, 0);
  926 
  927         case CDIOCSETSTERIO:
  928                 return wcd_setchan (t, CHANNEL_0, CHANNEL_1, 0, 0);
  929 
  930         case CDIOCSETMUTE:
  931                 return wcd_setchan (t, 0, 0, 0, 0);
  932 
  933         case CDIOCSETLEFT:
  934                 return wcd_setchan (t, CHANNEL_0, CHANNEL_0, 0, 0);
  935 
  936         case CDIOCSETRIGHT:
  937                 return wcd_setchan (t, CHANNEL_1, CHANNEL_1, 0, 0);
  938         }
  939         return (error);
  940 }
  941 
  942 /*
  943  * Read the entire TOC for the disc into our internal buffer.
  944  */
  945 static int wcd_read_toc (struct wcd *t)
  946 {
  947         int ntracks, len;
  948         struct atapires result;
  949 
  950         bzero (&t->toc, sizeof (t->toc));
  951         bzero (&t->info, sizeof (t->info));
  952 
  953         /* Check for the media.
  954          * Do it twice to avoid the stale media changed state. */
  955         result = atapi_request_wait (t->ata, t->unit, ATAPI_TEST_UNIT_READY,
  956                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  957 
  958         if (result.code == RES_ERR &&
  959             (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION) {
  960                 t->flags |= F_MEDIA_CHANGED;
  961                 result = atapi_request_wait (t->ata, t->unit,
  962                         ATAPI_TEST_UNIT_READY, 0, 0, 0, 0, 0, 0, 0, 0,
  963                         0, 0, 0, 0, 0, 0, 0, 0, 0);
  964         }
  965         if (result.code) {
  966                 wcd_error (t, result);
  967                 return (EIO);
  968         }
  969         t->flags &= ~F_MEDIA_CHANGED;
  970 
  971         /* First read just the header, so we know how long the TOC is. */
  972         len = sizeof(struct ioc_toc_header) + sizeof(struct cd_toc_entry);
  973         if (wcd_request_wait (t, ATAPI_READ_TOC, 0, 0, 0, 0, 0, 0,
  974             len >> 8, len & 0xff, 0, (char*)&t->toc, len) != 0) {
  975 err:            bzero (&t->toc, sizeof (t->toc));
  976                 return (0);
  977         }
  978 
  979         ntracks = t->toc.hdr.ending_track - t->toc.hdr.starting_track + 1;
  980         if (ntracks <= 0 || ntracks > MAXTRK)
  981                 goto err;
  982 
  983         /* Now read the whole schmeer. */
  984         len = sizeof(struct ioc_toc_header) +
  985                 ntracks * sizeof(struct cd_toc_entry);
  986         if (wcd_request_wait (t, ATAPI_READ_TOC, 0, 0, 0, 0, 0, 0,
  987             len >> 8, len & 0xff, 0, (char*)&t->toc, len) & 0xff)
  988                 goto err;
  989 
  990         NTOHS(t->toc.hdr.len);
  991 
  992         /* Read disc capacity. */
  993         if (wcd_request_wait (t, ATAPI_READ_CAPACITY, 0, 0, 0, 0, 0, 0,
  994             0, sizeof(t->info), 0, (char*)&t->info, sizeof(t->info)) != 0)
  995                 bzero (&t->info, sizeof (t->info));
  996 
  997         /* make fake leadout entry */
  998         t->toc.tab[ntracks].control = t->toc.tab[ntracks-1].control;
  999         t->toc.tab[ntracks].addr_type = t->toc.tab[ntracks-1].addr_type;
 1000         t->toc.tab[ntracks].track = 170; /* magic */
 1001         t->toc.tab[ntracks].addr.lba = t->info.volsize;
 1002 
 1003         NTOHL(t->info.volsize);
 1004         NTOHL(t->info.blksize);
 1005 
 1006         /* Print the disc description string on every disc change.
 1007          * It would help to track the history of disc changes. */
 1008         if (t->info.volsize && t->toc.hdr.ending_track &&
 1009             (t->flags & F_MEDIA_CHANGED) && (t->flags & F_DEBUG)) {
 1010                 printf ("wcd%d: ", t->lun);
 1011                 if (t->toc.tab[0].control & 4)
 1012                         printf ("%ldMB ", t->info.volsize / 512);
 1013                 else
 1014                         printf ("%ld:%ld audio ", t->info.volsize/75/60,
 1015                                 t->info.volsize/75%60);
 1016                 printf ("(%ld sectors), %d tracks\n", t->info.volsize,
 1017                         t->toc.hdr.ending_track - t->toc.hdr.starting_track + 1);
 1018         }
 1019         return (0);
 1020 }
 1021 
 1022 /*
 1023  * Set up the audio channel masks.
 1024  */
 1025 static int wcd_setchan (struct wcd *t,
 1026         u_char c0, u_char c1, u_char c2, u_char c3)
 1027 {
 1028         int error;
 1029 
 1030         error = wcd_request_wait (t, ATAPI_MODE_SENSE, 0, AUDIO_PAGE,
 1031                 0, 0, 0, 0, sizeof (t->au) >> 8, sizeof (t->au), 0,
 1032                 (char*) &t->au, sizeof (t->au));
 1033         if (error)
 1034                 return (error);
 1035         if (t->flags & F_DEBUG)
 1036                 wcd_dump (t->lun, "au", &t->au, sizeof t->au);
 1037         if (t->au.page_code != AUDIO_PAGE)
 1038                 return (EIO);
 1039 
 1040         /* Sony-55E requires the data length field to be zeroed. */
 1041         t->au.data_length = 0;
 1042 
 1043         t->au.port[0].channels = c0;
 1044         t->au.port[1].channels = c1;
 1045         t->au.port[2].channels = c2;
 1046         t->au.port[3].channels = c3;
 1047         return wcd_request_wait (t, ATAPI_MODE_SELECT_BIG, 0x10,
 1048                 0, 0, 0, 0, 0, sizeof (t->au) >> 8, sizeof (t->au),
 1049                 0, (char*) &t->au, - sizeof (t->au));
 1050 }
 1051 
 1052 static int wcd_eject (struct wcd *t, int closeit)
 1053 {
 1054         struct atapires result;
 1055 
 1056         /* Try to stop the disc. */
 1057         result = atapi_request_wait (t->ata, t->unit, ATAPI_START_STOP,
 1058                 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 1059 
 1060         if (result.code == RES_ERR &&
 1061             ((result.error & AER_SKEY) == AER_SK_NOT_READY ||
 1062             (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)) {
 1063                 int err;
 1064 
 1065                 if (!closeit)
 1066                         return (0);
 1067                 /*
 1068                  * The disc was unloaded.
 1069                  * Load it (close tray).
 1070                  * Read the table of contents.
 1071                  */
 1072                 err = wcd_request_wait (t, ATAPI_START_STOP,
 1073                         0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0);
 1074                 if (err)
 1075                         return (err);
 1076 
 1077                 /* Read table of contents. */
 1078                 wcd_read_toc (t);
 1079 
 1080                 /* Lock the media. */
 1081                 wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
 1082                         0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
 1083 
 1084                 return (0);
 1085         }
 1086 
 1087         if (result.code) {
 1088                 wcd_error (t, result);
 1089                 return (EIO);
 1090         }
 1091 
 1092         if (closeit)
 1093                 return (0);
 1094 
 1095         /* Give it some time to stop spinning. */
 1096         tsleep ((caddr_t)&lbolt, PRIBIO, "wcdej1", 0);
 1097         tsleep ((caddr_t)&lbolt, PRIBIO, "wcdej2", 0);
 1098 
 1099         /* Unlock. */
 1100         wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
 1101                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 1102 
 1103         /* Eject. */
 1104         t->flags |= F_MEDIA_CHANGED;
 1105         return wcd_request_wait (t, ATAPI_START_STOP,
 1106                 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0);
 1107 }
 1108 
 1109 #ifdef WCD_MODULE
 1110 /*
 1111  * Loadable ATAPI CD-ROM driver stubs.
 1112  */
 1113 #include <sys/exec.h>
 1114 #include <sys/sysent.h>
 1115 #include <sys/lkm.h>
 1116 
 1117 /*
 1118  * Construct lkm_dev structures (see lkm.h).
 1119  * Our bdevsw/cdevsw slot numbers are 19/69.
 1120  */
 1121 
 1122 
 1123 MOD_DEV(wcd, LM_DT_BLOCK, BDEV_MAJOR, &wcd_bdevsw);
 1124 MOD_DEV(rwcd, LM_DT_CHAR, CDEV_MAJOR, &wcd_cdevsw);
 1125 
 1126 /*
 1127  * Function called when loading the driver.
 1128  */
 1129 int wcd_load (struct lkm_table *lkmtp, int cmd)
 1130 {
 1131         struct atapi *ata;
 1132         int n, u;
 1133 
 1134         if (! atapi_start)
 1135                 /* No ATAPI driver available. */
 1136                 return EPROTONOSUPPORT;
 1137         n = 0;
 1138         for (ata=atapi_tab; ata<atapi_tab+2; ++ata)
 1139                 if (ata->port)
 1140                         for (u=0; u<2; ++u)
 1141                                 /* Probing controller ata->ctrlr, unit u. */
 1142                                 if (ata->params[u] && ! ata->attached[u] &&
 1143                                     wcdattach (ata, u, ata->params[u],
 1144                                     ata->debug) >= 0)
 1145                                 {
 1146                                         /* Drive found. */
 1147                                         ata->attached[u] = 1;
 1148                                         ++n;
 1149                                 }
 1150         if (! n)
 1151                 /* No IDE CD-ROMs found. */
 1152                 return ENXIO;
 1153         return 0;
 1154 }
 1155 
 1156 /*
 1157  * Function called when unloading the driver.
 1158  */
 1159 int wcd_unload (struct lkm_table *lkmtp, int cmd)
 1160 {
 1161         struct wcd **t;
 1162 
 1163         for (t=wcdtab; t<wcdtab+wcdnlun; ++t)
 1164                 if (((*t)->flags & F_BOPEN) || (*t)->refcnt)
 1165                         /* The device is opened, cannot unload the driver. */
 1166                         return EBUSY;
 1167         for (t=wcdtab; t<wcdtab+wcdnlun; ++t) {
 1168                 (*t)->ata->attached[(*t)->unit] = 0;
 1169                 free (*t, M_TEMP);
 1170         }
 1171         wcdnlun = 0;
 1172         bzero (wcdtab, sizeof(wcdtab));
 1173         return 0;
 1174 }
 1175 
 1176 /*
 1177  * Dispatcher function for the module (load/unload/stat).
 1178  */
 1179 int wcd_mod (struct lkm_table *lkmtp, int cmd, int ver)
 1180 {
 1181         int err = 0;
 1182 
 1183         if (ver != LKM_VERSION)
 1184                 return EINVAL;
 1185 
 1186         if (cmd == LKM_E_LOAD)
 1187                 err = wcd_load (lkmtp, cmd);
 1188         else if (cmd == LKM_E_UNLOAD)
 1189                 err = wcd_unload (lkmtp, cmd);
 1190         if (err)
 1191                 return err;
 1192 
 1193         /* Register the cdevsw entry. */
 1194         lkmtp->private.lkm_dev = &rwcd_module;
 1195         err = lkmdispatch (lkmtp, cmd);
 1196         if (err)
 1197                 return err;
 1198 
 1199         /* Register the bdevsw entry. */
 1200         lkmtp->private.lkm_dev = &wcd_module;
 1201         return lkmdispatch (lkmtp, cmd);
 1202 }
 1203 #endif /* WCD_MODULE */
 1204 
 1205 static wcd_devsw_installed = 0;
 1206 
 1207 static void     wcd_drvinit(void *unused)
 1208 {
 1209         dev_t dev;
 1210 
 1211         if( ! wcd_devsw_installed ) {
 1212                 dev = makedev(CDEV_MAJOR, 0);
 1213                 cdevsw_add(&dev,&wcd_cdevsw, NULL);
 1214                 dev = makedev(BDEV_MAJOR, 0);
 1215                 bdevsw_add(&dev,&wcd_bdevsw, NULL);
 1216                 wcd_devsw_installed = 1;
 1217         }
 1218 }
 1219 
 1220 SYSINIT(wcddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,wcd_drvinit,NULL)
 1221 
 1222 
 1223 #endif /* NWCD && NWDC && ATAPI */

Cache object: 6df796e94fb94dc80daf8d72a9a6ff97


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