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