2 * Copyright (c) 1998, 1999 Søren Schmidt
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
28 * $FreeBSD: src/sys/i386/isa/wd_cd.c,v 1.29 2000/01/29 16:00:33 peter Exp $
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
35 #include <sys/malloc.h>
37 #include <sys/disklabel.h>
38 #include <sys/devicestat.h>
40 #include <sys/wormio.h>
41 #include <sys/fcntl.h>
44 #include <i386/isa/atapi.h>
45 #include <i386/isa/wd_cd.h>
47 static d_open_t acdopen;
48 static d_close_t acdclose;
49 static d_ioctl_t acdioctl;
50 static d_strategy_t acdstrategy;
54 static struct cdevsw acd_cdevsw = {
58 /* write */ physwrite,
62 /* strategy */ acdstrategy,
71 #define NUNIT 16 /* Max # of devices */
73 #define F_BOPEN 0x0001 /* The block device is opened */
74 #define F_MEDIA_CHANGED 0x0002 /* The media have changed since open */
75 #define F_DEBUG 0x0004 /* Print debug info */
76 #define F_LOCKED 0x0008 /* This unit is locked (or should be) */
77 #define F_TRACK_PREP 0x0010 /* Track should be prep'ed */
78 #define F_TRACK_PREPED 0x0020 /* Track has been prep'ed */
79 #define F_DISK_PREPED 0x0040 /* Disk has been prep'ed */
80 #define F_WRITTEN 0x0080 /* The medium has been written to */
82 static struct acd *acdtab[NUNIT];
83 static int acdnlun = 0; /* Number of configured drives */
85 int acdattach(struct atapi *, int, struct atapi_params *, int);
86 static struct acd *acd_init_lun(struct atapi *, int, struct atapi_params *, int,
88 static void acd_start(struct acd *);
89 static void acd_done(struct acd *, struct buf *, int, struct atapires);
90 static int acd_read_toc(struct acd *);
91 static int acd_request_wait(struct acd *, u_char, u_char, u_char, u_char, u_char, u_char, u_char, u_char, u_char, u_char, char *, int);
92 static void acd_describe(struct acd *);
93 static int acd_setchan(struct acd *, u_char, u_char, u_char, u_char);
94 static int acd_eject(struct acd *, int);
95 static void acd_select_slot(struct acd *);
96 static int acd_open_disk(struct acd *, int);
97 static int acd_open_track(struct acd *, struct wormio_prepare_track *);
98 static int acd_close_track(struct acd *);
99 static int acd_close_disk(struct acd *);
100 static int acd_read_track_info(struct acd *cdp, int lba, struct acd_track_info *info);
101 static int acd_blank_disk(struct acd *);
102 static void atapi_dump(int ctrlr, int lun, char *label, void *data, int len);
103 static void atapi_error(struct atapi *ata, int unit, struct atapires result);
106 acd_init_lun(struct atapi *ata, int unit, struct atapi_params *ap, int lun,
107 struct devstat *device_stats)
111 if (!(ptr = malloc(sizeof(struct acd), M_TEMP, M_NOWAIT)))
113 bzero(ptr, sizeof(struct acd));
114 bufq_init(&ptr->buf_queue);
119 ptr->flags = F_MEDIA_CHANGED;
120 ptr->flags &= ~(F_WRITTEN|F_TRACK_PREP|F_TRACK_PREPED);
121 ptr->block_size = 2048;
124 ptr->changer_info = NULL;
125 if (device_stats == NULL) {
126 if (!(ptr->device_stats = malloc(sizeof(struct devstat),
129 bzero(ptr->device_stats, sizeof(struct devstat));
132 ptr->device_stats = device_stats;
133 make_dev(&acd_cdevsw, dkmakeminor(lun, 0, 0),
134 UID_ROOT, GID_OPERATOR, 0640, "rwcd%da", lun);
135 make_dev(&acd_cdevsw, dkmakeminor(lun, 0, RAW_PART),
136 UID_ROOT, GID_OPERATOR, 0640, "rwcd%dc", lun);
137 make_dev(&acd_cdevsw, dkmakeminor(lun, 0, 0),
138 UID_ROOT, GID_OPERATOR, 0640, "wcd%da", lun);
139 make_dev(&acd_cdevsw, dkmakeminor(lun, 0, RAW_PART),
140 UID_ROOT, GID_OPERATOR, 0640, "wcd%dc", lun);
145 acdattach(struct atapi *ata, int unit, struct atapi_params *ap, int debug)
148 struct atapires result;
152 if (acdnlun >= NUNIT) {
153 printf("wcd: too many units\n");
156 if (!atapi_request_immediate) {
157 printf("wcd: configuration error, ATAPI code not present!\n");
160 if ((cdp = acd_init_lun(ata, unit, ap, acdnlun, NULL)) == NULL) {
161 printf("wcd: out of memory\n");
164 acdtab[acdnlun] = cdp;
167 cdp->flags |= F_DEBUG;
168 atapi_dump(cdp->ata->ctrlr, cdp->lun, "info", ap, sizeof(*ap));
171 /* Get drive capabilities, some drives needs this repeated */
172 for (count = 0 ; count < 5 ; count++) {
173 result = atapi_request_immediate(ata, unit,
175 0, ATAPI_CDROM_CAP_PAGE,
177 sizeof(cdp->cap)>>8, sizeof(cdp->cap),
179 (char *)&cdp->cap, sizeof(cdp->cap));
180 if (result.code == 0 || result.code == RES_UNDERRUN)
184 /* Some drives have shorter capabilities page. */
185 if (result.code == RES_UNDERRUN)
188 if (result.code == 0) {
189 cdp->cap.max_speed = ntohs(cdp->cap.max_speed);
190 cdp->cap.max_vol_levels = ntohs(cdp->cap.max_vol_levels);
191 cdp->cap.buf_size = ntohs(cdp->cap.buf_size);
192 cdp->cap.cur_speed = ntohs(cdp->cap.cur_speed);
194 if (cdp->flags & F_DEBUG)
195 atapi_dump(cdp->ata->ctrlr, cdp->lun, "cap", &cdp->cap,
198 /* If this is a changer device, allocate the neeeded lun's */
199 if (cdp->cap.mech == MST_MECH_CHANGER) {
201 struct acd *tmpcdp = cdp;
203 chp = malloc(sizeof(struct changer), M_TEMP, M_NOWAIT);
205 printf("wcd: out of memory\n");
208 bzero(chp, sizeof(struct changer));
209 result = atapi_request_immediate(ata, unit, ATAPI_MECH_STATUS,
211 sizeof(struct changer)>>8,
212 sizeof(struct changer),
214 (char *)chp, sizeof(struct changer));
215 if (cdp->flags & F_DEBUG) {
216 printf("result.code=%d curr=%02x slots=%d len=%d\n",
217 result.code, chp->current_slot, chp->slots,
218 htons(chp->table_length));
220 if (result.code == RES_UNDERRUN)
223 if (result.code == 0) {
224 chp->table_length = htons(chp->table_length);
225 for (i = 0; i < chp->slots && acdnlun < NUNIT; i++) {
227 tmpcdp = acd_init_lun(ata, unit, ap, acdnlun,
230 printf("wcd: out of memory\n");
235 tmpcdp->changer_info = chp;
236 printf("wcd%d: changer slot %d %s\n", acdnlun, i,
237 (chp->slot[i].present ? "disk present" : "no disk"));
238 acdtab[acdnlun++] = tmpcdp;
240 if (acdnlun >= NUNIT) {
241 printf("wcd: too many units\n");
245 sprintf(string, "wcd%d-", cdp->lun);
246 devstat_add_entry(cdp->device_stats, string, tmpcdp->lun, DEV_BSIZE,
247 DEVSTAT_NO_ORDERED_TAGS,
248 DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_IDE,
249 DEVSTAT_PRIORITY_CD);
253 devstat_add_entry(cdp->device_stats, "wcd", cdp->lun, DEV_BSIZE,
254 DEVSTAT_NO_ORDERED_TAGS,
255 DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_IDE,
256 DEVSTAT_PRIORITY_CD);
262 acd_describe(struct acd *cdp)
267 printf("wcd%d: drive speed ", cdp->lun);
268 if (cdp->cap.cur_speed != cdp->cap.max_speed)
269 printf("%d - ", cdp->cap.cur_speed * 1000 / 1024);
270 printf("%dKB/sec", cdp->cap.max_speed * 1000 / 1024);
271 if (cdp->cap.buf_size)
272 printf(", %dKB cache\n", cdp->cap.buf_size);
274 printf("wcd%d: supported read types:", cdp->lun);
276 if (cdp->cap.read_cdr) {
277 printf(" CD-R"); comma = 1;
279 if (cdp->cap.read_cdrw) {
280 printf("%s CD-RW", comma ? "," : ""); comma = 1;
282 if (cdp->cap.cd_da) {
283 printf("%s CD-DA", comma ? "," : ""); comma = 1;
285 if (cdp->cap.method2)
286 printf("%s packet track", comma ? "," : "");
287 if (cdp->cap.write_cdr || cdp->cap.write_cdrw) {
288 printf("\nwcd%d: supported write types:", cdp->lun);
290 if (cdp->cap.write_cdr) {
291 printf(" CD-R" ); comma = 1;
293 if (cdp->cap.write_cdrw) {
294 printf("%s CD-RW", comma ? "," : ""); comma = 1;
296 if (cdp->cap.test_write) {
297 printf("%s test write", comma ? "," : ""); comma = 1;
300 if (cdp->cap.audio_play) {
301 printf("\nwcd%d: Audio: ", cdp->lun);
302 if (cdp->cap.audio_play)
304 if (cdp->cap.max_vol_levels)
305 printf(", %d volume levels", cdp->cap.max_vol_levels);
307 printf("\nwcd%d: Mechanism: ", cdp->lun);
308 switch (cdp->cap.mech) {
310 mechanism = "caddy"; break;
312 mechanism = "tray"; break;
314 mechanism = "popup"; break;
315 case MST_MECH_CHANGER:
316 mechanism = "changer"; break;
317 case MST_MECH_CARTRIDGE:
318 mechanism = "cartridge"; break;
320 mechanism = 0; break;
323 printf("%s%s", cdp->cap.eject ? "ejectable " : "", mechanism);
324 else if (cdp->cap.eject)
327 if (cdp->cap.mech != MST_MECH_CHANGER) {
328 printf("\nwcd%d: Medium: ", cdp->lun);
329 switch (cdp->cap.medium_type & MST_TYPE_MASK_HIGH) {
331 printf("CD-ROM "); break;
333 printf("CD-R "); break;
335 printf("CD-RW "); break;
337 printf("door open"); break;
339 printf("no/blank disc inside"); break;
341 printf("medium format error"); break;
343 if ((cdp->cap.medium_type & MST_TYPE_MASK_HIGH) < MST_TYPE_MASK_HIGH) {
344 switch (cdp->cap.medium_type & MST_TYPE_MASK_LOW) {
346 printf("120mm data disc loaded"); break;
348 printf("120mm audio disc loaded"); break;
350 printf("120mm data/audio disc loaded"); break;
352 printf("120mm photo disc loaded"); break;
354 printf("80mm data disc loaded"); break;
356 printf("80mm audio disc loaded"); break;
358 printf("80mm data/audio disc loaded"); break;
360 printf("80mm photo disc loaded"); break;
362 switch (cdp->cap.medium_type & MST_TYPE_MASK_HIGH) {
364 printf("unknown medium"); break;
367 printf("blank medium"); break;
371 printf("unknown type=0x%x", cdp->cap.medium_type); break;
376 printf(cdp->cap.locked ? ", locked" : ", unlocked");
377 if (cdp->cap.prevent)
378 printf(", lock protected");
383 acdopen(dev_t dev, int flags, int fmt, struct proc *p)
385 int lun = dkunit(dev);
388 if (lun >= acdnlun || !atapi_request_immediate)
392 if (!(cdp->flags & F_BOPEN) && !cdp->refcnt) {
393 /* Prevent user eject */
394 acd_request_wait(cdp, ATAPI_PREVENT_ALLOW,
395 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
396 cdp->flags |= F_LOCKED;
399 cdp->flags |= F_BOPEN;
402 dev->si_bsize_phys = cdp->block_size;
403 if (!(flags & O_NONBLOCK) && acd_read_toc(cdp) && !(flags & FWRITE))
404 printf("acd%d: read_toc failed\n", lun);
409 acdclose(dev_t dev, int flags, int fmt, struct proc *p)
411 struct acd *cdp = acdtab[dkunit(dev)];
414 cdp->flags &= ~F_BOPEN;
418 /* Are we the last open ?? */
419 if (!(cdp->flags & F_BOPEN) && !cdp->refcnt) {
420 /* Yup, do we need to close any written tracks */
421 if ((flags & FWRITE) != 0) {
422 if ((cdp->flags & F_TRACK_PREPED) != 0) {
423 acd_close_track(cdp);
424 cdp->flags &= ~(F_TRACK_PREPED | F_TRACK_PREP);
427 /* Allow the user eject */
428 acd_request_wait(cdp, ATAPI_PREVENT_ALLOW,
429 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
431 cdp->flags &= ~F_LOCKED;
436 acdstrategy(struct buf *bp)
438 int lun = dkunit(bp->b_dev);
439 struct acd *cdp = acdtab[lun];
443 /* allow write only on CD-R/RW media */ /* all for now SOS */
444 if (!(bp->b_flags & B_READ) && !(writeable_media)) {
446 bp->b_flags |= B_ERROR;
452 if (bp->b_bcount == 0) {
458 bp->b_pblkno = bp->b_blkno;
459 bp->b_resid = bp->b_bcount;
462 bufqdisksort(&cdp->buf_queue, bp);
468 acd_start(struct acd *cdp)
470 struct buf *bp = bufq_first(&cdp->buf_queue);
478 bufq_remove(&cdp->buf_queue, bp);
480 /* Should reject all queued entries if media have changed. */
481 if (cdp->flags & F_MEDIA_CHANGED) {
483 bp->b_flags |= B_ERROR;
488 acd_select_slot(cdp);
490 if ((bp->b_flags & B_READ) == B_WRITE) {
491 if ((cdp->flags & F_TRACK_PREPED) == 0) {
492 if ((cdp->flags & F_TRACK_PREP) == 0) {
493 printf("wcd%d: sequence error\n", cdp->lun);
495 bp->b_flags |= B_ERROR;
499 if (acd_open_track(cdp, &cdp->preptrack) != 0) {
503 cdp->flags |= F_TRACK_PREPED;
508 if (bp->b_flags & B_READ)
510 lba = bp->b_offset / cdp->block_size;
512 lba = bp->b_blkno / (cdp->block_size / DEV_BSIZE);
515 lba = cdp->next_writeable_lba + (bp->b_offset / cdp->block_size);
516 blocks = (bp->b_bcount + (cdp->block_size - 1)) / cdp->block_size;
518 if ((bp->b_flags & B_READ) == B_WRITE) {
519 cmd = ATAPI_WRITE_BIG;
520 count = -bp->b_bcount;
522 cmd = ATAPI_READ_BIG;
523 count = bp->b_bcount;
526 devstat_start_transaction(cdp->device_stats);
528 atapi_request_callback(cdp->ata, cdp->unit, cmd, 0,
529 lba>>24, lba>>16, lba>>8, lba, 0,
530 blocks>>8, blocks, 0, 0, 0, 0, 0, 0, 0,
531 (u_char *)bp->b_data, count,
532 (atapi_callback_t *)acd_done, cdp, bp);
536 acd_done(struct acd *cdp, struct buf *bp, int resid, struct atapires result)
540 atapi_error(cdp->ata, cdp->unit, result);
542 bp->b_flags |= B_ERROR;
545 if ((bp->b_flags & B_READ) == B_WRITE)
546 cdp->flags |= F_WRITTEN;
548 devstat_end_transaction_buf(cdp->device_stats, bp);
554 acd_request_wait(struct acd *cdp, u_char cmd, u_char a1, u_char a2,
555 u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
556 u_char a9, char *addr, int count)
558 struct atapires result;
560 result = atapi_request_wait(cdp->ata, cdp->unit, cmd, a1, a2, a3, a4, a5,
561 a6, a7, a8, a9, 0, 0, 0, 0, 0, 0, addr, count);
563 atapi_error(cdp->ata, cdp->unit, result);
570 lba2msf(int lba, u_char *m, u_char *s, u_char *f)
574 *m = lba / (60 * 75);
581 msf2lba(u_char m, u_char s, u_char f)
583 return (m * 60 + s) * 75 + f - 150;
587 acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
589 int lun = dkunit(dev);
590 struct acd *cdp = acdtab[lun];
593 if (cdp->flags & F_MEDIA_CHANGED)
599 acd_request_wait(cdp, ATAPI_PREVENT_ALLOW,
600 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
601 cdp->flags |= F_LOCKED;
608 cdb->cmd = ATAPI_PAUSE;
610 return atapi_cmd_wait(cdp->ata, cdp->unit, cdb, 0, 0, timout, 0);
613 return acd_request_wait(cdp, ATAPI_PAUSE,
614 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);
617 return acd_request_wait(cdp, ATAPI_PAUSE,
618 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
621 return acd_request_wait(cdp, ATAPI_START_STOP,
622 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
625 return acd_request_wait(cdp, ATAPI_START_STOP,
626 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
629 acd_select_slot(cdp);
630 cdp->flags &= ~F_LOCKED;
631 return acd_request_wait(cdp, ATAPI_PREVENT_ALLOW,
632 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
635 acd_select_slot(cdp);
636 cdp->flags |= F_LOCKED;
637 return acd_request_wait(cdp, ATAPI_PREVENT_ALLOW,
638 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
644 return acd_request_wait(cdp, ATAPI_TEST_UNIT_READY,
645 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
648 if ((cdp->flags & F_BOPEN) && cdp->refcnt)
650 return acd_eject(cdp, 0);
653 if ((cdp->flags & F_BOPEN) && cdp->refcnt)
655 return acd_eject(cdp, 1);
657 case CDIOREADTOCHEADER:
658 if (!cdp->toc.hdr.ending_track)
660 bcopy(&cdp->toc.hdr, addr, sizeof(cdp->toc.hdr));
663 case CDIOREADTOCENTRYS:
665 struct ioc_read_toc_entry *te = (struct ioc_read_toc_entry *)addr;
666 struct toc *toc = &cdp->toc;
669 u_char starting_track = te->starting_track;
671 if (!cdp->toc.hdr.ending_track)
674 if (te->data_len < sizeof(toc->tab[0]) ||
675 (te->data_len % sizeof(toc->tab[0])) != 0 ||
676 (te->address_format != CD_MSF_FORMAT &&
677 te->address_format != CD_LBA_FORMAT))
681 starting_track = toc->hdr.starting_track;
682 else if (starting_track == 170)
683 starting_track = toc->hdr.ending_track + 1;
684 else if (starting_track < toc->hdr.starting_track ||
685 starting_track > toc->hdr.ending_track + 1)
688 len = ((toc->hdr.ending_track + 1 - starting_track) + 1) *
690 if (te->data_len < len)
692 if (len > sizeof(toc->tab))
695 if (te->address_format == CD_MSF_FORMAT) {
696 struct cd_toc_entry *entry;
700 entry = toc->tab + (toc->hdr.ending_track + 1 -
701 toc->hdr.starting_track) + 1;
702 while (--entry >= toc->tab)
703 lba2msf(ntohl(entry->addr.lba), &entry->addr.msf.minute,
704 &entry->addr.msf.second, &entry->addr.msf.frame);
706 return copyout(toc->tab + starting_track - toc->hdr.starting_track,
710 case CDIOREADTOCENTRY:
712 struct ioc_read_toc_single_entry *te =
713 (struct ioc_read_toc_single_entry *)addr;
714 struct toc *toc = &cdp->toc;
716 u_char track = te->track;
718 if (!cdp->toc.hdr.ending_track)
721 if (te->address_format != CD_MSF_FORMAT &&
722 te->address_format != CD_LBA_FORMAT)
726 track = toc->hdr.starting_track;
727 else if (track == 170)
728 track = toc->hdr.ending_track + 1;
729 else if (track < toc->hdr.starting_track ||
730 track > toc->hdr.ending_track + 1)
733 if (te->address_format == CD_MSF_FORMAT) {
734 struct cd_toc_entry *entry;
738 entry = toc->tab + (track - toc->hdr.starting_track);
739 lba2msf(ntohl(entry->addr.lba), &entry->addr.msf.minute,
740 &entry->addr.msf.second, &entry->addr.msf.frame);
742 bcopy(toc->tab + track - toc->hdr.starting_track,
743 &te->entry, sizeof(struct cd_toc_entry));
747 case CDIOCREADSUBCHANNEL:
749 struct ioc_read_subchannel *args =
750 (struct ioc_read_subchannel *)addr;
751 struct cd_sub_channel_info data;
752 u_long len = args->data_len;
755 if (len > sizeof(data) ||
756 len < sizeof(struct cd_sub_channel_header))
759 if (acd_request_wait(cdp, ATAPI_READ_SUBCHANNEL,
761 sizeof(cdp->subchan)>>8, sizeof(cdp->subchan),
763 (char *)&cdp->subchan,
764 sizeof(cdp->subchan)) != 0)
766 if (cdp->flags & F_DEBUG)
767 atapi_dump(cdp->ata->ctrlr, cdp->lun, "subchan", &cdp->subchan,
768 sizeof(cdp->subchan));
770 abslba = cdp->subchan.abslba;
771 rellba = cdp->subchan.rellba;
772 if (args->address_format == CD_MSF_FORMAT) {
773 lba2msf(ntohl(abslba),
774 &data.what.position.absaddr.msf.minute,
775 &data.what.position.absaddr.msf.second,
776 &data.what.position.absaddr.msf.frame);
777 lba2msf(ntohl(rellba),
778 &data.what.position.reladdr.msf.minute,
779 &data.what.position.reladdr.msf.second,
780 &data.what.position.reladdr.msf.frame);
782 data.what.position.absaddr.lba = abslba;
783 data.what.position.reladdr.lba = rellba;
785 data.header.audio_status = cdp->subchan.audio_status;
786 data.what.position.control = cdp->subchan.control & 0xf;
787 data.what.position.addr_type = cdp->subchan.control >> 4;
788 data.what.position.track_number = cdp->subchan.track;
789 data.what.position.index_number = cdp->subchan.indx;
790 return copyout(&data, args->data, len);
795 struct ioc_play_msf *args = (struct ioc_play_msf *)addr;
797 return acd_request_wait(cdp, ATAPI_PLAY_MSF, 0, 0,
798 args->start_m, args->start_s, args->start_f,
799 args->end_m, args->end_s, args->end_f,
803 case CDIOCPLAYBLOCKS:
805 struct ioc_play_blocks *args = (struct ioc_play_blocks *)addr;
807 return acd_request_wait(cdp, ATAPI_PLAY_BIG, 0,
808 args->blk>>24 & 0xff, args->blk>>16 & 0xff,
809 args->blk>>8 & 0xff, args->blk & 0xff,
810 args->len>>24 & 0xff, args->len>>16 & 0xff,
811 args->len>>8 & 0xff, args->len & 0xff,
815 case CDIOCPLAYTRACKS:
817 struct ioc_play_track *args = (struct ioc_play_track *)addr;
821 if (!cdp->toc.hdr.ending_track)
824 if (args->end_track < cdp->toc.hdr.ending_track + 1)
826 if (args->end_track > cdp->toc.hdr.ending_track + 1)
827 args->end_track = cdp->toc.hdr.ending_track + 1;
828 t1 = args->start_track - cdp->toc.hdr.starting_track;
829 t2 = args->end_track - cdp->toc.hdr.starting_track;
830 if (t1 < 0 || t2 < 0)
832 start = ntohl(cdp->toc.tab[t1].addr.lba);
833 len = ntohl(cdp->toc.tab[t2].addr.lba) - start;
835 return acd_request_wait(cdp, ATAPI_PLAY_BIG, 0,
836 start>>24 & 0xff, start>>16 & 0xff,
837 start>>8 & 0xff, start & 0xff,
838 len>>24 & 0xff, len>>16 & 0xff,
839 len>>8 & 0xff, len & 0xff, 0, 0);
844 struct ioc_read_audio* args = (struct ioc_read_audio*) addr;
845 int lba, frames, result = 0;
846 u_char *buffer, *ubuf = args->buffer;
848 if (!cdp->toc.hdr.ending_track)
851 if ((frames = args->nframes) < 0)
854 if (args->address_format == CD_LBA_FORMAT)
855 lba = args->address.lba;
856 else if (args->address_format == CD_MSF_FORMAT)
857 lba = msf2lba(args->address.msf.minute,
858 args->address.msf.second,
859 args->address.msf.frame);
862 #ifndef CD_BUFFER_BLOCKS
863 #define CD_BUFFER_BLOCKS 8
865 if (!(buffer = malloc(CD_BUFFER_BLOCKS * 2352, M_TEMP, M_NOWAIT)))
872 blocks = (frames>CD_BUFFER_BLOCKS) ? CD_BUFFER_BLOCKS : frames;
873 size = blocks * 2352;
875 result = acd_request_wait(cdp, ATAPI_READ_CD, 4,
876 lba>>24, (lba>>16)&0xff,
877 (lba>>8)&0xff, lba&0xff, 0, 0,
878 blocks, 0xf0, buffer, size);
882 result = copyout(buffer, ubuf, size);
891 free(buffer, M_TEMP);
897 struct ioc_vol *arg = (struct ioc_vol *)addr;
899 error = acd_request_wait(cdp, ATAPI_MODE_SENSE, 0, CDROM_AUDIO_PAGE,
901 sizeof(cdp->au)>>8, sizeof(cdp->au), 0,
902 (char *)&cdp->au, sizeof(cdp->au));
905 if (cdp->flags & F_DEBUG)
906 atapi_dump(cdp->ata->ctrlr, cdp->lun, "au", &cdp->au,
908 if (cdp->au.page_code != CDROM_AUDIO_PAGE)
910 arg->vol[0] = cdp->au.port[0].volume;
911 arg->vol[1] = cdp->au.port[1].volume;
912 arg->vol[2] = cdp->au.port[2].volume;
913 arg->vol[3] = cdp->au.port[3].volume;
919 struct ioc_vol *arg = (struct ioc_vol *)addr;
921 error = acd_request_wait(cdp, ATAPI_MODE_SENSE, 0, CDROM_AUDIO_PAGE,
923 sizeof(cdp->au)>>8, sizeof(cdp->au), 0,
924 (char *)&cdp->au, sizeof(cdp->au));
927 if (cdp->flags & F_DEBUG)
928 atapi_dump(cdp->ata->ctrlr, cdp->lun, "au", &cdp->au,
930 if (cdp->au.page_code != CDROM_AUDIO_PAGE)
933 error = acd_request_wait(cdp, ATAPI_MODE_SENSE, 0,
934 CDROM_AUDIO_PAGE_MASK, 0, 0, 0, 0,
935 sizeof(cdp->aumask)>>8,sizeof(cdp->aumask),
937 (char *)&cdp->aumask, sizeof(cdp->aumask));
940 if (cdp->flags & F_DEBUG)
941 atapi_dump(cdp->ata->ctrlr, cdp->lun, "mask", &cdp->aumask,
942 sizeof(cdp->aumask));
944 cdp->au.data_length = 0;
945 cdp->au.port[0].channels = CHANNEL_0;
946 cdp->au.port[1].channels = CHANNEL_1;
947 cdp->au.port[0].volume = arg->vol[0] & cdp->aumask.port[0].volume;
948 cdp->au.port[1].volume = arg->vol[1] & cdp->aumask.port[1].volume;
949 cdp->au.port[2].volume = arg->vol[2] & cdp->aumask.port[2].volume;
950 cdp->au.port[3].volume = arg->vol[3] & cdp->aumask.port[3].volume;
951 return acd_request_wait(cdp, ATAPI_MODE_SELECT, 0x10,
953 sizeof(cdp->au)>>8, sizeof(cdp->au),
954 0, (char *)&cdp->au, -sizeof(cdp->au));
959 struct ioc_patch *arg = (struct ioc_patch *)addr;
961 return acd_setchan(cdp, arg->patch[0], arg->patch[1],
962 arg->patch[2], arg->patch[3]);
966 return acd_setchan(cdp, CHANNEL_0|CHANNEL_1, CHANNEL_0|CHANNEL_1, 0, 0);
969 return acd_setchan(cdp, CHANNEL_0, CHANNEL_1, 0, 0);
972 return acd_setchan(cdp, 0, 0, 0, 0);
975 return acd_setchan(cdp, CHANNEL_0, CHANNEL_0, 0, 0);
978 return acd_setchan(cdp, CHANNEL_1, CHANNEL_1, 0, 0);
980 case CDRIOCNEXTWRITEABLEADDR:
982 struct acd_track_info track_info;
984 if ((error = acd_read_track_info(cdp, 0xff, &track_info)))
986 if (!track_info.nwa_valid)
988 cdp->next_writeable_lba = track_info.next_writeable_addr;
989 *(int*)addr = track_info.next_writeable_addr;
993 case WORMIOCPREPDISK:
995 struct wormio_prepare_disk *w = (struct wormio_prepare_disk *)addr;
997 if (w->dummy != 0 && w->dummy != 1)
1000 error = acd_open_disk(cdp, w->dummy);
1002 cdp->flags |= F_DISK_PREPED;
1003 cdp->dummy = w->dummy;
1004 cdp->speed = w->speed;
1010 case WORMIOCPREPTRACK:
1012 struct wormio_prepare_track *w =(struct wormio_prepare_track *)addr;
1014 if (w->audio != 0 && w->audio != 1)
1016 else if (w->audio == 0 && w->preemp)
1018 else if ((cdp->flags & F_DISK_PREPED) == 0) {
1020 printf("wcd%d: sequence error (PREP_TRACK)\n", cdp->lun);
1022 cdp->flags |= F_TRACK_PREP;
1023 cdp->preptrack = *w;
1028 case WORMIOCFINISHTRACK:
1029 if ((cdp->flags & F_TRACK_PREPED) != 0)
1030 error = acd_close_track(cdp);
1031 cdp->flags &= ~(F_TRACK_PREPED | F_TRACK_PREP);
1034 case WORMIOCFIXATION:
1036 struct wormio_fixation *w =
1037 (struct wormio_fixation *)addr;
1039 if ((cdp->flags & F_WRITTEN) == 0)
1041 else if (w->toc_type < 0 /* WORM_TOC_TYPE_AUDIO */ ||
1042 w->toc_type > 4 /* WORM_TOC_TYPE_CDI */ )
1044 else if (w->onp != 0 && w->onp != 1)
1047 /* no fixation needed if dummy write */
1048 if (cdp->dummy == 0)
1049 error = acd_close_disk(cdp);
1051 ~(F_WRITTEN|F_DISK_PREPED|F_TRACK_PREP|F_TRACK_PREPED);
1057 return acd_blank_disk(cdp);
1066 acd_read_toc(struct acd *cdp)
1069 struct atapires result;
1071 bzero(&cdp->toc, sizeof(cdp->toc));
1072 bzero(&cdp->info, sizeof(cdp->info));
1074 acd_select_slot(cdp);
1076 result = atapi_request_wait(cdp->ata, cdp->unit, ATAPI_TEST_UNIT_READY,
1077 0, 0, 0, 0, 0, 0, 0, 0,
1078 0, 0, 0, 0, 0, 0, 0, 0, 0);
1080 if (result.code == RES_ERR &&
1081 (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION) {
1082 cdp->flags |= F_MEDIA_CHANGED;
1083 cdp->flags &= ~(F_WRITTEN|F_TRACK_PREP|F_TRACK_PREPED);
1084 result = atapi_request_wait(cdp->ata, cdp->unit, ATAPI_TEST_UNIT_READY,
1085 0, 0, 0, 0, 0, 0, 0, 0,
1086 0, 0, 0, 0, 0, 0, 0, 0, 0);
1090 atapi_error(cdp->ata, cdp->unit, result);
1094 cdp->flags &= ~F_MEDIA_CHANGED;
1096 len = sizeof(struct ioc_toc_header) + sizeof(struct cd_toc_entry);
1097 if (acd_request_wait(cdp, ATAPI_READ_TOC, 0, 0, 0, 0, 0, 0,
1098 len>>8, len & 0xff, 0, (char *)&cdp->toc, len) != 0) {
1099 bzero(&cdp->toc, sizeof(cdp->toc));
1102 ntracks = cdp->toc.hdr.ending_track - cdp->toc.hdr.starting_track + 1;
1103 if (ntracks <= 0 || ntracks > MAXTRK) {
1104 bzero(&cdp->toc, sizeof(cdp->toc));
1108 len = sizeof(struct ioc_toc_header) + ntracks * sizeof(struct cd_toc_entry);
1109 if (acd_request_wait(cdp, ATAPI_READ_TOC, 0, 0, 0, 0, 0, 0,
1110 len>>8, len & 0xff, 0, (char *)&cdp->toc, len) & 0xff){
1111 bzero(&cdp->toc, sizeof(cdp->toc));
1115 cdp->toc.hdr.len = ntohs(cdp->toc.hdr.len);
1117 if (acd_request_wait(cdp, ATAPI_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1118 (char *)&cdp->info, sizeof(cdp->info)) != 0)
1119 bzero(&cdp->info, sizeof(cdp->info));
1121 cdp->toc.tab[ntracks].control = cdp->toc.tab[ntracks - 1].control;
1122 cdp->toc.tab[ntracks].addr_type = cdp->toc.tab[ntracks - 1].addr_type;
1123 cdp->toc.tab[ntracks].track = 170;
1124 cdp->toc.tab[ntracks].addr.lba = cdp->info.volsize;
1126 cdp->info.volsize = ntohl(cdp->info.volsize);
1127 cdp->info.blksize = ntohl(cdp->info.blksize);
1129 if (cdp->info.volsize && cdp->toc.hdr.ending_track
1130 && (cdp->flags & F_DEBUG)) {
1131 printf("wcd%d: ", cdp->lun);
1132 if (cdp->toc.tab[0].control & 4)
1133 printf("%ldMB ", cdp->info.volsize / 512);
1135 printf("%ld:%ld audio ", cdp->info.volsize / 75 / 60,
1136 cdp->info.volsize / 75 % 60);
1137 printf("(%ld sectors (%ld bytes)), %d tracks\n",
1138 cdp->info.volsize, cdp->info.blksize,
1139 cdp->toc.hdr.ending_track - cdp->toc.hdr.starting_track + 1);
1145 * Set up the audio channel masks.
1148 acd_setchan(struct acd *cdp, u_char c0, u_char c1, u_char c2, u_char c3)
1152 error = acd_request_wait(cdp, ATAPI_MODE_SENSE, 0, CDROM_AUDIO_PAGE,
1154 sizeof(cdp->au)>>8, sizeof(cdp->au), 0,
1155 (char *)&cdp->au, sizeof(cdp->au));
1158 if (cdp->flags & F_DEBUG)
1159 atapi_dump(cdp->ata->ctrlr, cdp->lun, "au", &cdp->au, sizeof(cdp->au));
1160 if (cdp->au.page_code != CDROM_AUDIO_PAGE)
1163 cdp->au.data_length = 0;
1164 cdp->au.port[0].channels = c0;
1165 cdp->au.port[1].channels = c1;
1166 cdp->au.port[2].channels = c2;
1167 cdp->au.port[3].channels = c3;
1168 return acd_request_wait(cdp, ATAPI_MODE_SELECT, 0x10,
1170 sizeof(cdp->au)>>8, sizeof(cdp->au), 0,
1171 (char *)&cdp->au, -sizeof(cdp->au));
1175 acd_eject(struct acd *cdp, int close)
1177 struct atapires result;
1179 acd_select_slot(cdp);
1181 result = atapi_request_wait(cdp->ata, cdp->unit, ATAPI_START_STOP, 1,
1182 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1184 if (result.code == RES_ERR &&
1185 ((result.error & AER_SKEY) == AER_SK_NOT_READY ||
1186 (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)) {
1191 err = acd_request_wait(cdp, ATAPI_START_STOP, 0, 0, 0, 3,
1192 0, 0, 0, 0, 0, 0, 0);
1198 acd_request_wait(cdp, ATAPI_PREVENT_ALLOW, 0, 0, 0, 1,
1199 0, 0, 0, 0, 0, 0, 0);
1200 cdp->flags |= F_LOCKED;
1204 atapi_error(cdp->ata, cdp->unit, result);
1210 tsleep((caddr_t) &lbolt, PRIBIO, "wcdej1", 0);
1211 tsleep((caddr_t) &lbolt, PRIBIO, "wcdej2", 0);
1213 acd_request_wait(cdp, ATAPI_PREVENT_ALLOW, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1214 cdp->flags &= ~F_LOCKED;
1216 cdp->flags |= F_MEDIA_CHANGED;
1217 cdp->flags &= ~(F_WRITTEN|F_TRACK_PREP|F_TRACK_PREPED);
1218 return acd_request_wait(cdp, ATAPI_START_STOP, 0, 0, 0, 2,
1219 0, 0, 0, 0, 0, 0, 0);
1223 acd_select_slot(struct acd *cdp)
1225 if (cdp->slot < 0 || cdp->changer_info->current_slot == cdp->slot)
1228 /* Unlock (might not be needed but its cheaper than asking) */
1229 acd_request_wait(cdp, ATAPI_PREVENT_ALLOW, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1231 /* Unload the current media from player */
1232 acd_request_wait(cdp, ATAPI_LOAD_UNLOAD, 0, 0, 0, 2,
1233 0, 0, 0, cdp->changer_info->current_slot, 0, 0, 0);
1235 /* load the wanted slot */
1236 acd_request_wait(cdp, ATAPI_LOAD_UNLOAD, 0, 0, 0, 3,
1237 0, 0, 0, cdp->slot, 0, 0, 0);
1239 cdp->changer_info->current_slot = cdp->slot;
1241 /* Lock the media if needed */
1242 if (cdp->flags & F_LOCKED) {
1243 acd_request_wait(cdp, ATAPI_PREVENT_ALLOW, 0, 0, 0, 1,
1244 0, 0, 0, 0, 0, 0, 0);
1249 acd_open_disk(struct acd *cdp, int test)
1251 cdp->next_writeable_lba = 0;
1256 acd_close_disk(struct acd *cdp)
1258 return acd_request_wait(cdp, ATAPI_CLOSE_TRACK, 0x00,
1259 0x02, 0, 0, 0/*track*/, 0, 0, 0, 0, 0, 0);
1263 acd_open_track(struct acd *cdp, struct wormio_prepare_track *ptp)
1265 struct write_param param;
1266 struct atapires result;
1268 result = atapi_request_wait(cdp->ata, cdp->unit, ATAPI_MODE_SENSE,
1269 0, 0x05, 0, 0, 0, 0,
1270 sizeof(param)>>8, sizeof(param),
1271 0, 0, 0, 0, 0, 0, 0,
1272 (char *)¶m, sizeof(param));
1274 if (cdp->flags & F_DEBUG)
1275 atapi_dump(cdp->ata->ctrlr, cdp->lun, "0x05", ¶m, sizeof(param));
1277 if (result.code == RES_UNDERRUN)
1281 atapi_error(cdp->ata, cdp->unit, result);
1284 param.page_code = 0x05;
1285 param.page_length = 0x32;
1286 param.test_write = cdp->dummy ? 1 : 0;
1287 param.write_type = CDR_WTYPE_TRACK;
1289 switch (ptp->audio) {
1290 /* switch (data_type) { */
1293 /* case CDR_DATA: */
1294 cdp->block_size = 2048;
1295 param.track_mode = CDR_TMODE_DATA;
1296 param.data_block_type = CDR_DB_ROM_MODE1;
1297 param.session_format = CDR_SESS_CDROM;
1301 /* case CDR_AUDIO: */
1302 cdp->block_size = 2352;
1304 param.track_mode = CDR_TMODE_AUDIO;
1306 param.track_mode = 0;
1307 param.data_block_type = CDR_DB_RAW;
1308 param.session_format = CDR_SESS_CDROM;
1313 param.track_mode = CDR_TMODE_DATA;
1314 param.data_block_type = CDR_DB_ROM_MODE2;
1315 param.session_format = CDR_SESS_CDROM;
1319 param.track_mode = CDR_TMODE_DATA;
1320 param.data_block_type = CDR_DB_XA_MODE1;
1321 param.session_format = CDR_SESS_CDROM_XA;
1325 param.track_mode = CDR_TMODE_DATA;
1326 param.data_block_type = CDR_DB_XA_MODE2_F1;
1327 param.session_format = CDR_SESS_CDROM_XA;
1331 param.track_mode = CDR_TMODE_DATA;
1332 param.data_block_type = CDR_DB_XA_MODE2_F1;
1333 param.session_format = CDR_SESS_CDI;
1338 param.multi_session = CDR_MSES_NONE;
1340 param.packet_size = 0;
1342 if (cdp->flags & F_DEBUG)
1343 atapi_dump(cdp->ata->ctrlr, cdp->lun, "0x05", ¶m, sizeof(param));
1345 result = atapi_request_wait(cdp->ata, cdp->unit, ATAPI_MODE_SELECT,
1346 0x10, 0, 0, 0, 0, 0,
1347 sizeof(param)>>8, sizeof(param),
1348 0, 0, 0, 0, 0, 0, 0,
1349 (char *)¶m, -sizeof(param));
1351 if (result.code == RES_UNDERRUN)
1355 atapi_error(cdp->ata, cdp->unit, result);
1362 acd_close_track(struct acd *cdp)
1364 return acd_request_wait(cdp, ATAPI_SYNCHRONIZE_CACHE, 0,
1365 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1369 acd_read_track_info(struct acd *cdp, int lba, struct acd_track_info *info)
1373 error = acd_request_wait(cdp, ATAPI_READ_TRACK_INFO, 0x01,
1374 lba>>24, (lba>>16)&0xff,
1375 (lba>>8)&0xff, lba&0xff,
1377 sizeof(*info)>>8, sizeof(*info), 0,
1378 (char *)info, sizeof(*info));
1381 info->track_start_addr = ntohl(info->track_start_addr);
1382 info->next_writeable_addr = ntohl(info->next_writeable_addr);
1383 info->free_blocks = ntohl(info->free_blocks);
1384 info->fixed_packet_size = ntohl(info->fixed_packet_size);
1385 info->track_length = ntohl(info->track_length);
1390 acd_blank_disk(struct acd *cdp)
1394 error = acd_request_wait(cdp, 0xa1, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1395 cdp->flags |= F_MEDIA_CHANGED;
1396 cdp->flags &= ~(F_WRITTEN|F_TRACK_PREP|F_TRACK_PREPED);
1401 atapi_error(struct atapi *ata, int unit, struct atapires result)
1403 if (result.code != RES_ERR) {
1404 printf("atapi%d:%d: ERROR %d, status=%b, error=%b\n",
1405 ata->ctrlr, unit, result.code, result.status,
1406 ARS_BITS, result.error, AER_BITS);
1409 switch (result.error & AER_SKEY) {
1410 case AER_SK_NOT_READY:
1412 printf("atapi%d:%d: not ready\n", ata->ctrlr, unit);
1415 case AER_SK_BLANK_CHECK:
1417 printf("atapi%d:%d: blank check\n", ata->ctrlr, unit);
1420 case AER_SK_MEDIUM_ERROR:
1422 printf("atapi%d:%d: medium error\n", ata->ctrlr, unit);
1425 case AER_SK_HARDWARE_ERROR:
1427 printf("atapi%d:%d: hardware error\n", ata->ctrlr, unit);
1430 case AER_SK_ILLEGAL_REQUEST:
1432 printf("atapi%d:%d: illegal request\n", ata->ctrlr, unit);
1435 case AER_SK_UNIT_ATTENTION:
1437 printf("atapi%d:%d: unit attention\n", ata->ctrlr, unit);
1440 case AER_SK_DATA_PROTECT:
1442 printf("atapi%d:%d: reading protected data\n", ata->ctrlr, unit);
1445 case AER_SK_ABORTED_COMMAND:
1447 printf("atapi%d:%d: command aborted\n", ata->ctrlr, unit);
1450 case AER_SK_MISCOMPARE:
1452 printf("atapi%d:%d: data don't match medium\n", ata->ctrlr, unit);
1457 printf("atapi%d:%d: unknown error, status=%b, error=%b\n",
1458 ata->ctrlr, unit, result.status, ARS_BITS,
1459 result.error, AER_BITS);
1464 atapi_dump(int ctrlr, int lun, char *label, void *data, int len)
1468 printf ("atapi%d%d: %s %x", ctrlr, lun, label, *p++);
1469 while (--len > 0) printf ("-%x", *p++);
1474 acd_drvinit(void *unused)
1476 cdevsw_add(&acd_cdevsw);
1479 SYSINIT(acddev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR, acd_drvinit, NULL)