1 /* $NetBSD: mcd.c,v 1.108 2009/05/12 08:44:19 cegger Exp $ */
4 * Copyright (c) 1993, 1994, 1995 Charles M. Hannum. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Charles M. Hannum.
17 * 4. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
20 * Copyright 1993 by Holger Veit (data part)
21 * Copyright 1993 by Brian Moore (audio part)
22 * All rights reserved.
24 * Redistribution and use in source and binary forms, with or without
25 * modification, are permitted provided that the following conditions
27 * 1. Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
29 * 2. Redistributions in binary form must reproduce the above copyright
30 * notice, this list of conditions and the following disclaimer in the
31 * documentation and/or other materials provided with the distribution.
32 * 3. All advertising materials mentioning features or use of this software
33 * must display the following acknowledgement:
34 * This software was developed by Holger Veit and Brian Moore
35 * for use with "386BSD" and similar operating systems.
36 * "Similar operating systems" includes mainly non-profit oriented
37 * systems for research and education, including but not restricted to
38 * "NetBSD", "FreeBSD", "Mach" (by CMU).
39 * 4. Neither the name of the developer(s) nor the name "386BSD"
40 * may be used to endorse or promote products derived from this
41 * software without specific prior written permission.
43 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER(S) ``AS IS'' AND ANY
44 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
46 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER(S) BE
47 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
48 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
49 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
50 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
51 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
52 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
53 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 /*static char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore";*/
58 #include <sys/cdefs.h>
59 __KERNEL_RCSID(0, "$NetBSD: mcd.c,v 1.108 2009/05/12 08:44:19 cegger Exp $");
61 #include <sys/param.h>
62 #include <sys/systm.h>
63 #include <sys/callout.h>
64 #include <sys/kernel.h>
72 #include <sys/ioctl.h>
74 #include <sys/errno.h>
75 #include <sys/disklabel.h>
76 #include <sys/device.h>
78 #include <sys/mutex.h>
83 #include <dev/isa/isavar.h>
84 #include <dev/isa/mcdreg.h>
87 #define MCD_TRACE(fmt,...)
89 #define MCD_TRACE(fmt,...) {if (sc->debug) {printf("%s: st=%02x: ", device_xname(&sc->sc_dev), sc->status); printf(fmt,__VA_ARGS__);}}
92 #define MCDPART(dev) DISKPART(dev)
93 #define MCDUNIT(dev) DISKUNIT(dev)
96 #define MCD_MAXTOCS 104 /* from the Linux driver */
98 /* control promiscuous match */
99 #include "opt_mcd_promisc.h"
116 #define MCD_S_BEGIN 1
117 #define MCD_S_WAITMODE 2
118 #define MCD_S_WAITREAD 3
123 struct device sc_dev
;
128 callout_t sc_pintr_ch
;
130 bus_space_tag_t sc_iot
;
131 bus_space_handle_t sc_ioh
;
137 #define MCDF_WLABEL 0x04 /* label is writable */
138 #define MCDF_LABELLING 0x08 /* writing label */
139 #define MCDF_LOADED 0x10 /* parameters loaded */
144 struct mcd_volinfo volinfo
;
145 union mcd_qchninfo toc
[MCD_MAXTOCS
];
146 struct mcd_command lastpb
;
149 #define MCD_MD_UNKNOWN -1
151 #define MCD_UPC_UNKNOWN -1
152 struct bufq_state
*buf_queue
;
159 static int bcd2bin(bcd_t
);
160 static bcd_t
bin2bcd(int);
161 static void hsg2msf(int, bcd_t
*);
162 static daddr_t
msf2hsg(bcd_t
*, int);
164 int mcd_playtracks(struct mcd_softc
*, struct ioc_play_track
*);
165 int mcd_playmsf(struct mcd_softc
*, struct ioc_play_msf
*);
166 int mcd_playblocks(struct mcd_softc
*, struct ioc_play_blocks
*);
167 int mcd_stop(struct mcd_softc
*);
168 int mcd_eject(struct mcd_softc
*);
169 int mcd_read_subchannel(struct mcd_softc
*, struct ioc_read_subchannel
*,
170 struct cd_sub_channel_info
*);
171 int mcd_pause(struct mcd_softc
*);
172 int mcd_resume(struct mcd_softc
*);
173 int mcd_toc_header(struct mcd_softc
*, struct ioc_toc_header
*);
174 int mcd_toc_entries(struct mcd_softc
*, struct ioc_read_toc_entry
*,
175 struct cd_toc_entry
*, int *);
177 int mcd_getreply(struct mcd_softc
*);
178 int mcd_getstat(struct mcd_softc
*);
179 int mcd_getresult(struct mcd_softc
*, struct mcd_result
*);
180 void mcd_setflags(struct mcd_softc
*);
181 int mcd_get(struct mcd_softc
*, char *, int);
182 int mcd_send(struct mcd_softc
*, struct mcd_mbox
*, int);
184 void mcd_soft_reset(struct mcd_softc
*);
185 int mcd_hard_reset(struct mcd_softc
*);
186 int mcd_setmode(struct mcd_softc
*, int);
187 int mcd_setupc(struct mcd_softc
*, int);
188 int mcd_read_toc(struct mcd_softc
*);
189 int mcd_getqchan(struct mcd_softc
*, union mcd_qchninfo
*, int);
190 int mcd_setlock(struct mcd_softc
*, int);
192 int mcd_find(bus_space_tag_t
, bus_space_handle_t
, struct mcd_softc
*);
193 int mcdprobe(device_t
, cfdata_t
, void *);
194 void mcdattach(device_t
, device_t
, void *);
196 CFATTACH_DECL(mcd
, sizeof(struct mcd_softc
),
197 mcdprobe
, mcdattach
, NULL
, NULL
);
199 extern struct cfdriver mcd_cd
;
201 dev_type_open(mcdopen
);
202 dev_type_close(mcdclose
);
203 dev_type_read(mcdread
);
204 dev_type_write(mcdwrite
);
205 dev_type_ioctl(mcdioctl
);
206 dev_type_strategy(mcdstrategy
);
207 dev_type_dump(mcddump
);
208 dev_type_size(mcdsize
);
210 const struct bdevsw mcd_bdevsw
= {
211 mcdopen
, mcdclose
, mcdstrategy
, mcdioctl
, mcddump
, mcdsize
, D_DISK
214 const struct cdevsw mcd_cdevsw
= {
215 mcdopen
, mcdclose
, mcdread
, mcdwrite
, mcdioctl
,
216 nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_DISK
219 void mcdgetdefaultlabel(struct mcd_softc
*, struct disklabel
*);
220 void mcdgetdisklabel(struct mcd_softc
*);
221 int mcd_get_parms(struct mcd_softc
*);
222 void mcdstart(struct mcd_softc
*);
223 void mcd_pseudointr(void *);
225 struct dkdriver mcddkdriver
= { mcdstrategy
, NULL
, };
227 #define MCD_RETRIES 3
228 #define MCD_RDRETRIES 3
231 #define RDELAY_WAITMODE 300
232 #define RDELAY_WAITREAD 800
234 #define DELAY_GRANULARITY 25 /* 25us */
235 #define DELAY_GETREPLY 100000 /* 100000 * 25us */
238 mcdattach(device_t parent
, device_t self
, void *aux
)
240 struct mcd_softc
*sc
= (void *)self
;
241 struct isa_attach_args
*ia
= aux
;
242 bus_space_tag_t iot
= ia
->ia_iot
;
243 bus_space_handle_t ioh
;
247 if (bus_space_map(iot
, ia
->ia_io
[0].ir_addr
, MCD_NPORT
, 0, &ioh
)) {
248 printf(": can't map i/o space\n");
252 mutex_init(&sc
->sc_lock
, MUTEX_DEFAULT
, IPL_NONE
);
260 if (!mcd_find(iot
, ioh
, sc
)) {
261 printf(": mcd_find failed\n");
265 bufq_alloc(&sc
->buf_queue
, "disksort", BUFQ_SORT_RAWBLOCK
);
266 callout_init(&sc
->sc_pintr_ch
, 0);
269 * Initialize and attach the disk structure.
271 disk_init(&sc
->sc_dk
, device_xname(&sc
->sc_dev
), &mcddkdriver
);
272 disk_attach(&sc
->sc_dk
);
274 printf(": model %s\n", sc
->type
!= 0 ? sc
->type
: "unknown");
276 (void) mcd_setlock(sc
, MCD_LK_UNLOCK
);
278 mbx
.cmd
.opcode
= MCD_CMDCONFIGDRIVE
;
279 mbx
.cmd
.length
= sizeof(mbx
.cmd
.data
.config
) - 1;
280 mbx
.cmd
.data
.config
.subcommand
= MCD_CF_IRQENABLE
;
281 mbx
.cmd
.data
.config
.data1
= 0x01;
283 (void) mcd_send(sc
, &mbx
, 0);
287 sc
->sc_ih
= isa_intr_establish(ia
->ia_ic
, ia
->ia_irq
[0].ir_irq
,
288 IST_EDGE
, IPL_BIO
, mcdintr
, sc
);
292 mcdopen(dev_t dev
, int flag
, int fmt
, struct lwp
*l
)
295 struct mcd_softc
*sc
;
297 sc
= device_lookup_private(&mcd_cd
, MCDUNIT(dev
));
301 mutex_enter(&sc
->sc_lock
);
303 if (sc
->sc_dk
.dk_openmask
!= 0) {
305 * If any partition is open, but the disk has been invalidated,
306 * disallow further opens.
308 if ((sc
->flags
& MCDF_LOADED
) == 0) {
314 * Lock the drawer. This will also notice any pending disk
315 * change or door open indicator and clear the MCDF_LOADED bit
318 (void) mcd_setlock(sc
, MCD_LK_LOCK
);
320 if ((sc
->flags
& MCDF_LOADED
) == 0) {
321 /* Partially reset the state. */
322 sc
->lastmode
= MCD_MD_UNKNOWN
;
323 sc
->lastupc
= MCD_UPC_UNKNOWN
;
325 sc
->flags
|= MCDF_LOADED
;
327 /* Set the mode, causing the disk to spin up. */
328 if ((error
= mcd_setmode(sc
, MCD_MD_COOKED
)) != 0)
331 /* Load the physical device parameters. */
332 if (mcd_get_parms(sc
) != 0) {
337 /* Read the table of contents. */
338 if ((error
= mcd_read_toc(sc
)) != 0)
341 /* Fabricate a disk label. */
348 MCD_TRACE("open: partition=%d disksize=%ld blksize=%d\n", part
,
349 sc
->disksize
, sc
->blksize
);
351 /* Check that the partition exists. */
352 if (part
!= RAW_PART
&&
353 (part
>= sc
->sc_dk
.dk_label
->d_npartitions
||
354 sc
->sc_dk
.dk_label
->d_partitions
[part
].p_fstype
== FS_UNUSED
)) {
359 /* Insure only one open at a time. */
362 sc
->sc_dk
.dk_copenmask
|= (1 << part
);
365 sc
->sc_dk
.dk_bopenmask
|= (1 << part
);
368 sc
->sc_dk
.dk_openmask
= sc
->sc_dk
.dk_copenmask
| sc
->sc_dk
.dk_bopenmask
;
370 mutex_exit(&sc
->sc_lock
);
374 sc
->flags
&= ~MCDF_LOADED
;
377 if (sc
->sc_dk
.dk_openmask
== 0) {
379 (void) mcd_setmode(sc
, MCD_MD_SLEEP
);
381 (void) mcd_setlock(sc
, MCD_LK_UNLOCK
);
385 mutex_exit(&sc
->sc_lock
);
390 mcdclose(dev_t dev
, int flag
, int fmt
, struct lwp
*l
)
392 struct mcd_softc
*sc
= device_lookup_private(&mcd_cd
, MCDUNIT(dev
));
393 int part
= MCDPART(dev
);
395 MCD_TRACE("close: partition=%d\n", part
);
397 mutex_enter(&sc
->sc_lock
);
401 sc
->sc_dk
.dk_copenmask
&= ~(1 << part
);
404 sc
->sc_dk
.dk_bopenmask
&= ~(1 << part
);
407 sc
->sc_dk
.dk_openmask
= sc
->sc_dk
.dk_copenmask
| sc
->sc_dk
.dk_bopenmask
;
409 if (sc
->sc_dk
.dk_openmask
== 0) {
410 /* XXXX Must wait for I/O to complete! */
413 (void) mcd_setmode(sc
, MCD_MD_SLEEP
);
415 (void) mcd_setlock(sc
, MCD_LK_UNLOCK
);
418 mutex_exit(&sc
->sc_lock
);
423 mcdstrategy(struct buf
*bp
)
425 struct mcd_softc
*sc
;
426 struct disklabel
*lp
;
430 sc
= device_lookup_private(&mcd_cd
, MCDUNIT(bp
->b_dev
));
431 lp
= sc
->sc_dk
.dk_label
;
434 MCD_TRACE("strategy: buf=0x%p blkno=%d bcount=%d\n", bp
,
435 (int) bp
->b_blkno
, bp
->b_bcount
);
436 if (bp
->b_blkno
< 0 ||
437 (bp
->b_bcount
% sc
->blksize
) != 0) {
438 printf("%s: strategy: blkno = %" PRId64
" bcount = %d\n",
439 device_xname(&sc
->sc_dev
), bp
->b_blkno
, bp
->b_bcount
);
440 bp
->b_error
= EINVAL
;
444 /* If device invalidated (e.g. media change, door open), error. */
445 if ((sc
->flags
& MCDF_LOADED
) == 0) {
446 MCD_TRACE("strategy: drive not valid%s", "\n");
451 /* No data to read. */
452 if (bp
->b_bcount
== 0)
456 * Do bounds checking, adjust transfer. if error, process.
457 * If end of partition, just return.
459 if (MCDPART(bp
->b_dev
) != RAW_PART
&&
460 bounds_check_with_label(&sc
->sc_dk
, bp
,
461 (sc
->flags
& (MCDF_WLABEL
|MCDF_LABELLING
)) != 0) <= 0)
465 * Now convert the block number to absolute and put it in
466 * terms of the device's logical block size.
468 blkno
= bp
->b_blkno
/ (lp
->d_secsize
/ DEV_BSIZE
);
469 if (MCDPART(bp
->b_dev
) != RAW_PART
)
470 blkno
+= lp
->d_partitions
[MCDPART(bp
->b_dev
)].p_offset
;
472 bp
->b_rawblkno
= blkno
;
476 bufq_put(sc
->buf_queue
, bp
);
483 bp
->b_resid
= bp
->b_bcount
;
488 mcdstart(struct mcd_softc
*sc
)
496 if ((bp
= bufq_get(sc
->buf_queue
)) == NULL
) {
503 /* Block found to process. */
504 MCD_TRACE("start: found block bp=0x%p\n", bp
);
508 if ((sc
->flags
& MCDF_LOADED
) == 0) {
509 MCD_TRACE("start: drive not valid%s", "\n");
517 /* Instrumentation. */
519 disk_busy(&sc
->sc_dk
);
522 sc
->mbx
.retry
= MCD_RDRETRIES
;
524 sc
->mbx
.blkno
= bp
->b_rawblkno
;
525 sc
->mbx
.nblk
= bp
->b_bcount
/ sc
->blksize
;
526 sc
->mbx
.sz
= sc
->blksize
;
528 sc
->mbx
.state
= MCD_S_BEGIN
;
529 sc
->mbx
.mode
= MCD_MD_COOKED
;
537 mcdread(dev_t dev
, struct uio
*uio
, int flags
)
540 return (physio(mcdstrategy
, NULL
, dev
, B_READ
, minphys
, uio
));
544 mcdwrite(dev_t dev
, struct uio
*uio
, int flags
)
547 return (physio(mcdstrategy
, NULL
, dev
, B_WRITE
, minphys
, uio
));
551 mcdioctl(dev_t dev
, u_long cmd
, void *addr
, int flag
, struct lwp
*l
)
553 struct mcd_softc
*sc
= device_lookup_private(&mcd_cd
, MCDUNIT(dev
));
556 #ifdef __HAVE_OLD_DISKLABEL
557 struct disklabel newlabel
;
560 MCD_TRACE("ioctl: cmd=0x%lx\n", cmd
);
562 if ((sc
->flags
& MCDF_LOADED
) == 0)
568 *(struct disklabel
*)addr
= *(sc
->sc_dk
.dk_label
);
570 #ifdef __HAVE_OLD_DISKLABEL
572 newlabel
= *(sc
->sc_dk
.dk_label
);
573 if (newlabel
.d_npartitions
> OLDMAXPARTITIONS
)
575 memcpy(addr
, &newlabel
, sizeof (struct olddisklabel
));
580 ((struct partinfo
*)addr
)->disklab
= sc
->sc_dk
.dk_label
;
581 ((struct partinfo
*)addr
)->part
=
582 &sc
->sc_dk
.dk_label
->d_partitions
[part
];
587 #ifdef __HAVE_OLD_DISKLABEL
592 struct disklabel
*lp
;
594 if ((flag
& FWRITE
) == 0)
597 #ifdef __HAVE_OLD_DISKLABEL
598 if (cmd
== ODIOCSDINFO
|| cmd
== ODIOCWDINFO
) {
599 memset(&newlabel
, 0, sizeof newlabel
);
600 memcpy(&newlabel
, addr
, sizeof (struct olddisklabel
));
606 mutex_enter(&sc
->sc_lock
);
607 sc
->flags
|= MCDF_LABELLING
;
609 error
= setdisklabel(sc
->sc_dk
.dk_label
,
610 lp
, /*sc->sc_dk.dk_openmask : */0,
611 sc
->sc_dk
.dk_cpulabel
);
615 sc
->flags
&= ~MCDF_LABELLING
;
616 mutex_exit(&sc
->sc_lock
);
624 mcdgetdefaultlabel(sc
, addr
);
627 #ifdef __HAVE_OLD_DISKLABEL
629 mcdgetdefaultlabel(sc
, &newlabel
);
630 if (newlabel
.d_npartitions
> OLDMAXPARTITIONS
)
632 memcpy(addr
, &newlabel
, sizeof (struct olddisklabel
));
636 case CDIOCPLAYTRACKS
:
637 return mcd_playtracks(sc
, addr
);
639 return mcd_playmsf(sc
, addr
);
640 case CDIOCPLAYBLOCKS
:
641 return mcd_playblocks(sc
, addr
);
642 case CDIOCREADSUBCHANNEL
: {
643 struct cd_sub_channel_info info
;
644 error
= mcd_read_subchannel(sc
, addr
, &info
);
646 struct ioc_read_subchannel
*ch
= addr
;
647 error
= copyout(&info
, ch
->data
, ch
->data_len
);
651 case CDIOCREADSUBCHANNEL_BUF
:
652 return mcd_read_subchannel(sc
, addr
,
653 &((struct ioc_read_subchannel_buf
*)addr
)->info
);
654 case CDIOREADTOCHEADER
:
655 return mcd_toc_header(sc
, addr
);
656 case CDIOREADTOCENTRYS
: {
657 struct cd_toc_entry entries
[MCD_MAXTOCS
];
658 struct ioc_read_toc_entry
*te
= addr
;
660 if (te
->data_len
> sizeof entries
)
662 error
= mcd_toc_entries(sc
, te
, entries
, &count
);
664 /* Copy the data back. */
665 error
= copyout(entries
, te
->data
, min(te
->data_len
,
666 count
* sizeof(struct cd_toc_entry
)));
669 case CDIOREADTOCENTRIES_BUF
: {
670 struct ioc_read_toc_entry_buf
*te
= addr
;
672 if (te
->req
.data_len
> sizeof te
->entry
)
674 return mcd_toc_entries(sc
, &te
->req
, te
->entry
, &count
);
686 return mcd_resume(sc
);
688 return mcd_pause(sc
);
694 if (*(int *)addr
== 0) {
696 * Don't force eject: check that we are the only
697 * partition open. If so, unlock it.
699 if ((sc
->sc_dk
.dk_openmask
& ~(1 << part
)) == 0 &&
700 sc
->sc_dk
.dk_bopenmask
+ sc
->sc_dk
.dk_copenmask
==
701 sc
->sc_dk
.dk_openmask
) {
702 error
= mcd_setlock(sc
, MCD_LK_UNLOCK
);
710 case CDIOCEJECT
: /* FALLTHROUGH */
712 return mcd_eject(sc
);
714 return mcd_setlock(sc
, MCD_LK_UNLOCK
);
716 return mcd_setlock(sc
, MCD_LK_LOCK
);
718 return mcd_setlock(sc
,
719 (*(int *)addr
) ? MCD_LK_LOCK
: MCD_LK_UNLOCK
);
727 return mcd_hard_reset(sc
);
734 panic("mcdioctl: impossible");
739 mcdgetdefaultlabel(struct mcd_softc
*sc
, struct disklabel
*lp
)
742 memset(lp
, 0, sizeof(struct disklabel
));
744 lp
->d_secsize
= sc
->blksize
;
746 lp
->d_nsectors
= 100;
747 lp
->d_ncylinders
= (sc
->disksize
/ 100) + 1;
748 lp
->d_secpercyl
= lp
->d_ntracks
* lp
->d_nsectors
;
750 strncpy(lp
->d_typename
, "Mitsumi CD-ROM", 16);
751 lp
->d_type
= 0; /* XXX */
752 strncpy(lp
->d_packname
, "fictitious", 16);
753 lp
->d_secperunit
= sc
->disksize
;
755 lp
->d_interleave
= 1;
756 lp
->d_flags
= D_REMOVABLE
;
758 lp
->d_partitions
[0].p_offset
= 0;
759 lp
->d_partitions
[0].p_size
=
760 lp
->d_secperunit
* (lp
->d_secsize
/ DEV_BSIZE
);
761 lp
->d_partitions
[0].p_fstype
= FS_ISO9660
;
762 lp
->d_partitions
[RAW_PART
].p_offset
= 0;
763 lp
->d_partitions
[RAW_PART
].p_size
=
764 lp
->d_secperunit
* (lp
->d_secsize
/ DEV_BSIZE
);
765 lp
->d_partitions
[RAW_PART
].p_fstype
= FS_ISO9660
;
766 lp
->d_npartitions
= RAW_PART
+ 1;
768 lp
->d_magic
= DISKMAGIC
;
769 lp
->d_magic2
= DISKMAGIC
;
770 lp
->d_checksum
= dkcksum(lp
);
774 * This could have been taken from scsi/cd.c, but it is not clear
775 * whether the scsi cd driver is linked in.
778 mcdgetdisklabel(struct mcd_softc
*sc
)
780 struct disklabel
*lp
= sc
->sc_dk
.dk_label
;
782 memset(sc
->sc_dk
.dk_cpulabel
, 0, sizeof(struct cpu_disklabel
));
784 mcdgetdefaultlabel(sc
, lp
);
788 mcd_get_parms(struct mcd_softc
*sc
)
794 /* Send volume info command. */
795 mbx
.cmd
.opcode
= MCD_CMDGETVOLINFO
;
797 mbx
.res
.length
= sizeof(mbx
.res
.data
.volinfo
);
798 if ((error
= mcd_send(sc
, &mbx
, 1)) != 0)
801 if (mbx
.res
.data
.volinfo
.trk_low
== 0x00 &&
802 mbx
.res
.data
.volinfo
.trk_high
== 0x00)
806 sc
->volinfo
= mbx
.res
.data
.volinfo
;
807 sc
->blksize
= MCD_BLKSIZE_COOKED
;
808 size
= msf2hsg(sc
->volinfo
.vol_msf
, 0);
809 sc
->disksize
= size
* (MCD_BLKSIZE_COOKED
/ DEV_BSIZE
);
817 /* CD-ROMs are read-only. */
822 mcddump(dev_t dev
, daddr_t blkno
, void *va
,
826 /* Not implemented. */
831 * Find the board and fill in the softc.
834 mcd_find(bus_space_tag_t iot
, bus_space_handle_t ioh
, struct mcd_softc
*sc
)
843 bus_space_write_1(iot
, ioh
, MCD_RESET
, 0);
845 /* Get any pending status and throw away. */
847 bus_space_read_1(iot
, ioh
, MCD_STATUS
);
850 /* Send get status command. */
851 mbx
.cmd
.opcode
= MCD_CMDGETSTAT
;
854 if (mcd_send(sc
, &mbx
, 0) != 0)
857 /* Get info about the drive. */
858 mbx
.cmd
.opcode
= MCD_CMDCONTINFO
;
860 mbx
.res
.length
= sizeof(mbx
.res
.data
.continfo
);
861 if (mcd_send(sc
, &mbx
, 0) != 0)
865 * The following is code which is not guaranteed to work for all
866 * drives, because the meaning of the expected 'M' is not clear
867 * (M_itsumi is an obvious assumption, but I don't trust that).
868 * Also, the original hack had a bogus condition that always
871 * Note: Which models support interrupts? >=LU005S?
873 sc
->readcmd
= MCD_CMDREADSINGLESPEED
;
874 switch (mbx
.res
.data
.continfo
.code
) {
876 if (mbx
.res
.data
.continfo
.version
<= 2)
878 else if (mbx
.res
.data
.continfo
.version
<= 5)
888 sc
->readcmd
= MCD_CMDREADDOUBLESPEED
;
892 * mcd_send() says the response looked OK but the
893 * drive type is unknown. If mcd_promisc, match anyway.
895 if (mcd_promisc
!= 0)
899 printf("%s: unrecognized drive version %c%02x; will try to use it anyway\n",
900 device_xname(&sc
->sc_dev
),
901 mbx
.res
.data
.continfo
.code
, mbx
.res
.data
.continfo
.version
);
912 mcdprobe(device_t parent
, cfdata_t match
, void *aux
)
914 struct isa_attach_args
*ia
= aux
;
916 bus_space_tag_t iot
= ia
->ia_iot
;
917 bus_space_handle_t ioh
;
925 if (ISA_DIRECT_CONFIG(ia
))
928 /* Disallow wildcarded i/o address. */
929 if (ia
->ia_io
[0].ir_addr
== ISA_UNKNOWN_PORT
)
931 if (ia
->ia_irq
[0].ir_irq
== ISA_UNKNOWN_IRQ
)
935 if (bus_space_map(iot
, ia
->ia_io
[0].ir_addr
, MCD_NPORT
, 0, &ioh
))
941 rv
= mcd_find(iot
, ioh
, &sc
);
943 bus_space_unmap(iot
, ioh
, MCD_NPORT
);
947 ia
->ia_io
[0].ir_size
= MCD_NPORT
;
959 mcd_getreply(struct mcd_softc
*sc
)
961 bus_space_tag_t iot
= sc
->sc_iot
;
962 bus_space_handle_t ioh
= sc
->sc_ioh
;
965 /* Wait until xfer port senses data ready. */
966 for (i
= DELAY_GETREPLY
; i
; i
--) {
967 if ((bus_space_read_1(iot
, ioh
, MCD_XFER
) &
968 MCD_XF_STATUSUNAVAIL
) == 0)
970 delay(DELAY_GRANULARITY
);
976 return bus_space_read_1(iot
, ioh
, MCD_STATUS
);
980 mcd_getstat(struct mcd_softc
*sc
)
984 mbx
.cmd
.opcode
= MCD_CMDGETSTAT
;
987 return mcd_send(sc
, &mbx
, 1);
991 mcd_getresult(struct mcd_softc
*sc
, struct mcd_result
*res
)
996 printf("%s: mcd_getresult: %d", device_xname(&sc
->sc_dev
),
999 if ((x
= mcd_getreply(sc
)) < 0) {
1001 printf(" timeout\n");
1002 else if (!sc
->probe
)
1003 printf("%s: timeout in getresult\n", device_xname(&sc
->sc_dev
));
1007 printf(" %02x", (u_int
)x
);
1011 if ((sc
->status
& MCD_ST_CMDCHECK
) != 0)
1014 for (i
= 0; i
< res
->length
; i
++) {
1015 if ((x
= mcd_getreply(sc
)) < 0) {
1017 printf(" timeout\n");
1019 printf("%s: timeout in getresult\n", device_xname(&sc
->sc_dev
));
1023 printf(" %02x", (u_int
)x
);
1024 res
->data
.raw
.data
[i
] = x
;
1028 printf(" succeeded\n");
1032 while ((bus_space_read_1(sc
->sc_iot
, sc
->sc_ioh
, MCD_XFER
) &
1033 MCD_XF_STATUSUNAVAIL
) == 0) {
1034 x
= bus_space_read_1(sc
->sc_iot
, sc
->sc_ioh
, MCD_STATUS
);
1035 printf("%s: got extra byte %02x during getstatus\n",
1036 device_xname(&sc
->sc_dev
), (u_int
)x
);
1045 mcd_setflags(struct mcd_softc
*sc
)
1049 if ((sc
->flags
& MCDF_LOADED
) != 0 &&
1050 (sc
->status
& (MCD_ST_DSKCHNG
| MCD_ST_DSKIN
| MCD_ST_DOOROPEN
)) !=
1052 if ((sc
->status
& MCD_ST_DOOROPEN
) != 0)
1053 printf("%s: door open\n", device_xname(&sc
->sc_dev
));
1054 else if ((sc
->status
& MCD_ST_DSKIN
) == 0)
1055 printf("%s: no disk present\n", device_xname(&sc
->sc_dev
));
1056 else if ((sc
->status
& MCD_ST_DSKCHNG
) != 0)
1057 printf("%s: media change\n", device_xname(&sc
->sc_dev
));
1058 sc
->flags
&= ~MCDF_LOADED
;
1061 if ((sc
->status
& MCD_ST_AUDIOBSY
) != 0)
1062 sc
->audio_status
= CD_AS_PLAY_IN_PROGRESS
;
1063 else if (sc
->audio_status
== CD_AS_PLAY_IN_PROGRESS
||
1064 sc
->audio_status
== CD_AS_AUDIO_INVALID
)
1065 sc
->audio_status
= CD_AS_PLAY_COMPLETED
;
1069 mcd_send(struct mcd_softc
*sc
, struct mcd_mbox
*mbx
, int diskin
)
1071 int retry
, i
, error
;
1072 bus_space_tag_t iot
= sc
->sc_iot
;
1073 bus_space_handle_t ioh
= sc
->sc_ioh
;
1076 printf("%s: mcd_send: %d %02x", device_xname(&sc
->sc_dev
),
1077 mbx
->cmd
.length
, (u_int
)mbx
->cmd
.opcode
);
1078 for (i
= 0; i
< mbx
->cmd
.length
; i
++)
1079 printf(" %02x", (u_int
)mbx
->cmd
.data
.raw
.data
[i
]);
1083 for (retry
= MCD_RETRIES
; retry
; retry
--) {
1084 bus_space_write_1(iot
, ioh
, MCD_COMMAND
, mbx
->cmd
.opcode
);
1085 for (i
= 0; i
< mbx
->cmd
.length
; i
++)
1086 bus_space_write_1(iot
, ioh
, MCD_COMMAND
, mbx
->cmd
.data
.raw
.data
[i
]);
1087 if ((error
= mcd_getresult(sc
, &mbx
->res
)) == 0)
1089 if (error
== EINVAL
)
1094 if (diskin
&& (sc
->flags
& MCDF_LOADED
) == 0)
1104 return (b
>> 4) * 10 + (b
& 15);
1111 return ((b
/ 10) << 4) | (b
% 10);
1115 hsg2msf(int hsg
, bcd_t
*msf
)
1119 F_msf(msf
) = bin2bcd(hsg
% 75);
1121 S_msf(msf
) = bin2bcd(hsg
% 60);
1123 M_msf(msf
) = bin2bcd(hsg
);
1127 msf2hsg(bcd_t
*msf
, int relative
)
1131 blkno
= bcd2bin(M_msf(msf
)) * 75 * 60 +
1132 bcd2bin(S_msf(msf
)) * 75 +
1133 bcd2bin(F_msf(msf
));
1140 mcd_pseudointr(void *v
)
1142 struct mcd_softc
*sc
= v
;
1151 * State machine to process read requests.
1152 * Initialize with MCD_S_BEGIN: calculate sizes, and set mode
1153 * MCD_S_WAITMODE: waits for status reply from set mode, set read command
1154 * MCD_S_WAITREAD: wait for read ready, read data.
1159 struct mcd_softc
*sc
= arg
;
1160 struct mcd_mbx
*mbx
= &sc
->mbx
;
1161 struct buf
*bp
= mbx
->bp
;
1162 bus_space_tag_t iot
= sc
->sc_iot
;
1163 bus_space_handle_t ioh
= sc
->sc_ioh
;
1169 switch (mbx
->state
) {
1175 if (mbx
->mode
== sc
->lastmode
)
1178 sc
->lastmode
= MCD_MD_UNKNOWN
;
1179 bus_space_write_1(iot
, ioh
, MCD_COMMAND
, MCD_CMDSETMODE
);
1180 bus_space_write_1(iot
, ioh
, MCD_COMMAND
, mbx
->mode
);
1182 mbx
->count
= RDELAY_WAITMODE
;
1183 mbx
->state
= MCD_S_WAITMODE
;
1185 case MCD_S_WAITMODE
:
1186 callout_stop(&sc
->sc_pintr_ch
);
1187 for (i
= 20; i
; i
--) {
1188 x
= bus_space_read_1(iot
, ioh
, MCD_XFER
);
1189 if ((x
& MCD_XF_STATUSUNAVAIL
) == 0)
1195 sc
->status
= bus_space_read_1(iot
, ioh
, MCD_STATUS
);
1197 if ((sc
->flags
& MCDF_LOADED
) == 0)
1199 MCD_TRACE("doread: got WAITMODE delay=%d\n",
1200 RDELAY_WAITMODE
- mbx
->count
);
1202 sc
->lastmode
= mbx
->mode
;
1205 MCD_TRACE("doread: read blkno=%d for bp=0x%p\n",
1206 (int) mbx
->blkno
, bp
);
1208 /* Build parameter block. */
1209 hsg2msf(mbx
->blkno
, msf
);
1211 /* Send the read command. */
1212 bus_space_write_1(iot
, ioh
, MCD_COMMAND
, sc
->readcmd
);
1213 bus_space_write_1(iot
, ioh
, MCD_COMMAND
, msf
[0]);
1214 bus_space_write_1(iot
, ioh
, MCD_COMMAND
, msf
[1]);
1215 bus_space_write_1(iot
, ioh
, MCD_COMMAND
, msf
[2]);
1216 bus_space_write_1(iot
, ioh
, MCD_COMMAND
, 0);
1217 bus_space_write_1(iot
, ioh
, MCD_COMMAND
, 0);
1218 bus_space_write_1(iot
, ioh
, MCD_COMMAND
, mbx
->nblk
);
1220 mbx
->count
= RDELAY_WAITREAD
;
1221 mbx
->state
= MCD_S_WAITREAD
;
1223 case MCD_S_WAITREAD
:
1224 callout_stop(&sc
->sc_pintr_ch
);
1227 for (i
= 20; i
; i
--) {
1228 x
= bus_space_read_1(iot
, ioh
, MCD_XFER
);
1229 if ((x
& MCD_XF_DATAUNAVAIL
) == 0)
1231 if ((x
& MCD_XF_STATUSUNAVAIL
) == 0)
1237 sc
->status
= bus_space_read_1(iot
, ioh
, MCD_STATUS
);
1239 if ((sc
->flags
& MCDF_LOADED
) == 0)
1242 printf("%s: got status byte %02x during read\n",
1243 device_xname(&sc
->sc_dev
), (u_int
)sc
->status
);
1248 MCD_TRACE("doread: got data delay=%d\n",
1249 RDELAY_WAITREAD
- mbx
->count
);
1251 /* Data is ready. */
1252 bus_space_write_1(iot
, ioh
, MCD_CTL2
, 0x04); /* XXX */
1253 bus_space_read_multi_1(iot
, ioh
, MCD_RDATA
,
1254 (char *)bp
->b_data
+ mbx
->skip
, mbx
->sz
);
1255 bus_space_write_1(iot
, ioh
, MCD_CTL2
, 0x0c); /* XXX */
1257 mbx
->skip
+= mbx
->sz
;
1258 if (--mbx
->nblk
> 0)
1261 mbx
->state
= MCD_S_IDLE
;
1263 /* Return buffer. */
1265 disk_unbusy(&sc
->sc_dk
, bp
->b_bcount
, (bp
->b_flags
& B_READ
));
1272 if (mbx
->count
-- < 0) {
1273 printf("%s: timeout in state %d",
1274 device_xname(&sc
->sc_dev
), mbx
->state
);
1279 printf("%s: sleep in state %d\n", device_xname(&sc
->sc_dev
),
1282 callout_reset(&sc
->sc_pintr_ch
, hz
/ 100,
1283 mcd_pseudointr
, sc
);
1288 if (mbx
->retry
-- > 0) {
1289 printf("; retrying\n");
1292 printf("; giving up\n");
1295 /* Invalidate the buffer. */
1297 bp
->b_resid
= bp
->b_bcount
- mbx
->skip
;
1298 disk_unbusy(&sc
->sc_dk
, (bp
->b_bcount
- bp
->b_resid
),
1299 (bp
->b_flags
& B_READ
));
1306 printf("%s: unit timeout; resetting\n", device_xname(&sc
->sc_dev
));
1307 bus_space_write_1(iot
, ioh
, MCD_RESET
, MCD_CMDRESET
);
1309 (void) mcd_getstat(sc
, 1);
1310 (void) mcd_getstat(sc
, 1);
1311 /*sc->status &= ~MCD_ST_DSKCHNG; */
1312 sc
->debug
= 1; /* preventive set debug mode */
1317 mcd_soft_reset(struct mcd_softc
*sc
)
1322 sc
->lastmode
= MCD_MD_UNKNOWN
;
1323 sc
->lastupc
= MCD_UPC_UNKNOWN
;
1324 sc
->audio_status
= CD_AS_AUDIO_INVALID
;
1325 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
, MCD_CTL2
, 0x0c); /* XXX */
1329 mcd_hard_reset(struct mcd_softc
*sc
)
1331 struct mcd_mbox mbx
;
1335 mbx
.cmd
.opcode
= MCD_CMDRESET
;
1338 return mcd_send(sc
, &mbx
, 0);
1342 mcd_setmode(struct mcd_softc
*sc
, int mode
)
1344 struct mcd_mbox mbx
;
1347 if (sc
->lastmode
== mode
)
1350 printf("%s: setting mode to %d\n", device_xname(&sc
->sc_dev
), mode
);
1351 sc
->lastmode
= MCD_MD_UNKNOWN
;
1353 mbx
.cmd
.opcode
= MCD_CMDSETMODE
;
1354 mbx
.cmd
.length
= sizeof(mbx
.cmd
.data
.datamode
);
1355 mbx
.cmd
.data
.datamode
.mode
= mode
;
1357 if ((error
= mcd_send(sc
, &mbx
, 1)) != 0)
1360 sc
->lastmode
= mode
;
1365 mcd_setupc(struct mcd_softc
*sc
, int upc
)
1367 struct mcd_mbox mbx
;
1370 if (sc
->lastupc
== upc
)
1373 printf("%s: setting upc to %d\n", device_xname(&sc
->sc_dev
), upc
);
1374 sc
->lastupc
= MCD_UPC_UNKNOWN
;
1376 mbx
.cmd
.opcode
= MCD_CMDCONFIGDRIVE
;
1377 mbx
.cmd
.length
= sizeof(mbx
.cmd
.data
.config
) - 1;
1378 mbx
.cmd
.data
.config
.subcommand
= MCD_CF_READUPC
;
1379 mbx
.cmd
.data
.config
.data1
= upc
;
1381 if ((error
= mcd_send(sc
, &mbx
, 1)) != 0)
1389 mcd_toc_header(struct mcd_softc
*sc
, struct ioc_toc_header
*th
)
1393 printf("%s: mcd_toc_header: reading toc header\n",
1394 device_xname(&sc
->sc_dev
));
1396 th
->len
= msf2hsg(sc
->volinfo
.vol_msf
, 0);
1397 th
->starting_track
= bcd2bin(sc
->volinfo
.trk_low
);
1398 th
->ending_track
= bcd2bin(sc
->volinfo
.trk_high
);
1404 mcd_read_toc(struct mcd_softc
*sc
)
1406 struct ioc_toc_header th
;
1407 union mcd_qchninfo q
;
1408 int error
, trk
, idx
, retry
;
1410 if ((error
= mcd_toc_header(sc
, &th
)) != 0)
1413 if ((error
= mcd_stop(sc
)) != 0)
1417 printf("%s: read_toc: reading qchannel info\n",
1418 device_xname(&sc
->sc_dev
));
1420 for (trk
= th
.starting_track
; trk
<= th
.ending_track
; trk
++)
1421 sc
->toc
[trk
].toc
.idx_no
= 0x00;
1422 trk
= th
.ending_track
- th
.starting_track
+ 1;
1423 for (retry
= 300; retry
&& trk
> 0; retry
--) {
1424 if (mcd_getqchan(sc
, &q
, CD_TRACK_INFO
) != 0)
1426 if (q
.toc
.trk_no
!= 0x00 || q
.toc
.idx_no
== 0x00)
1428 idx
= bcd2bin(q
.toc
.idx_no
);
1429 if (idx
< MCD_MAXTOCS
&&
1430 sc
->toc
[idx
].toc
.idx_no
== 0x00) {
1436 /* Inform the drive that we're finished so it turns off the light. */
1437 if ((error
= mcd_setmode(sc
, MCD_MD_COOKED
)) != 0)
1443 /* Add a fake last+1 for mcd_playtracks(). */
1444 idx
= th
.ending_track
+ 1;
1445 sc
->toc
[idx
].toc
.control
= sc
->toc
[idx
-1].toc
.control
;
1446 sc
->toc
[idx
].toc
.addr_type
= sc
->toc
[idx
-1].toc
.addr_type
;
1447 sc
->toc
[idx
].toc
.trk_no
= 0x00;
1448 sc
->toc
[idx
].toc
.idx_no
= 0xaa;
1449 sc
->toc
[idx
].toc
.absolute_pos
[0] = sc
->volinfo
.vol_msf
[0];
1450 sc
->toc
[idx
].toc
.absolute_pos
[1] = sc
->volinfo
.vol_msf
[1];
1451 sc
->toc
[idx
].toc
.absolute_pos
[2] = sc
->volinfo
.vol_msf
[2];
1457 mcd_toc_entries(struct mcd_softc
*sc
, struct ioc_read_toc_entry
*te
, struct cd_toc_entry
*entries
, int *count
)
1459 int len
= te
->data_len
;
1460 struct ioc_toc_header header
;
1465 if (len
< sizeof(struct cd_toc_entry
))
1467 if (te
->address_format
!= CD_MSF_FORMAT
&&
1468 te
->address_format
!= CD_LBA_FORMAT
)
1471 /* Copy the TOC header. */
1472 if ((error
= mcd_toc_header(sc
, &header
)) != 0)
1475 /* Verify starting track. */
1476 trk
= te
->starting_track
;
1478 trk
= header
.starting_track
;
1479 else if (trk
== 0xaa)
1480 trk
= header
.ending_track
+ 1;
1481 else if (trk
< header
.starting_track
||
1482 trk
> header
.ending_track
+ 1)
1485 /* Copy the TOC data. */
1486 for (n
= 0; trk
<= header
.ending_track
+ 1; n
++, trk
++) {
1487 if (n
* sizeof entries
[0] > len
)
1489 if (sc
->toc
[trk
].toc
.idx_no
== 0x00)
1491 entries
[n
].control
= sc
->toc
[trk
].toc
.control
;
1492 entries
[n
].addr_type
= sc
->toc
[trk
].toc
.addr_type
;
1493 entries
[n
].track
= bcd2bin(sc
->toc
[trk
].toc
.idx_no
);
1494 switch (te
->address_format
) {
1496 entries
[n
].addr
.addr
[0] = 0;
1497 entries
[n
].addr
.addr
[1] = bcd2bin(sc
->toc
[trk
].toc
.absolute_pos
[0]);
1498 entries
[n
].addr
.addr
[2] = bcd2bin(sc
->toc
[trk
].toc
.absolute_pos
[1]);
1499 entries
[n
].addr
.addr
[3] = bcd2bin(sc
->toc
[trk
].toc
.absolute_pos
[2]);
1502 lba
= msf2hsg(sc
->toc
[trk
].toc
.absolute_pos
, 0);
1503 entries
[n
].addr
.addr
[0] = lba
>> 24;
1504 entries
[n
].addr
.addr
[1] = lba
>> 16;
1505 entries
[n
].addr
.addr
[2] = lba
>> 8;
1506 entries
[n
].addr
.addr
[3] = lba
;
1516 mcd_stop(struct mcd_softc
*sc
)
1518 struct mcd_mbox mbx
;
1522 printf("%s: mcd_stop: stopping play\n", device_xname(&sc
->sc_dev
));
1524 mbx
.cmd
.opcode
= MCD_CMDSTOPAUDIO
;
1527 if ((error
= mcd_send(sc
, &mbx
, 1)) != 0)
1530 sc
->audio_status
= CD_AS_PLAY_COMPLETED
;
1535 mcd_getqchan(struct mcd_softc
*sc
, union mcd_qchninfo
*q
, int qchn
)
1537 struct mcd_mbox mbx
;
1540 if (qchn
== CD_TRACK_INFO
) {
1541 if ((error
= mcd_setmode(sc
, MCD_MD_TOC
)) != 0)
1544 if ((error
= mcd_setmode(sc
, MCD_MD_COOKED
)) != 0)
1547 if (qchn
== CD_MEDIA_CATALOG
) {
1548 if ((error
= mcd_setupc(sc
, MCD_UPC_ENABLE
)) != 0)
1551 if ((error
= mcd_setupc(sc
, MCD_UPC_DISABLE
)) != 0)
1555 mbx
.cmd
.opcode
= MCD_CMDGETQCHN
;
1557 mbx
.res
.length
= sizeof(mbx
.res
.data
.qchninfo
);
1558 if ((error
= mcd_send(sc
, &mbx
, 1)) != 0)
1561 *q
= mbx
.res
.data
.qchninfo
;
1566 mcd_read_subchannel(struct mcd_softc
*sc
, struct ioc_read_subchannel
*ch
, struct cd_sub_channel_info
*info
)
1568 int len
= ch
->data_len
;
1569 union mcd_qchninfo q
;
1574 printf("%s: subchan: af=%d df=%d\n", device_xname(&sc
->sc_dev
),
1575 ch
->address_format
, ch
->data_format
);
1577 if (len
> sizeof(*info
) || len
< sizeof(info
->header
))
1579 if (ch
->address_format
!= CD_MSF_FORMAT
&&
1580 ch
->address_format
!= CD_LBA_FORMAT
)
1582 if (ch
->data_format
!= CD_CURRENT_POSITION
&&
1583 ch
->data_format
!= CD_MEDIA_CATALOG
)
1586 if ((error
= mcd_getqchan(sc
, &q
, ch
->data_format
)) != 0)
1589 info
->header
.audio_status
= sc
->audio_status
;
1590 info
->what
.media_catalog
.data_format
= ch
->data_format
;
1592 switch (ch
->data_format
) {
1593 case CD_MEDIA_CATALOG
:
1594 info
->what
.media_catalog
.mc_valid
= 1;
1596 info
->what
.media_catalog
.mc_number
=
1600 case CD_CURRENT_POSITION
:
1601 info
->what
.position
.track_number
= bcd2bin(q
.current
.trk_no
);
1602 info
->what
.position
.index_number
= bcd2bin(q
.current
.idx_no
);
1603 switch (ch
->address_format
) {
1605 info
->what
.position
.reladdr
.addr
[0] = 0;
1606 info
->what
.position
.reladdr
.addr
[1] = bcd2bin(q
.current
.relative_pos
[0]);
1607 info
->what
.position
.reladdr
.addr
[2] = bcd2bin(q
.current
.relative_pos
[1]);
1608 info
->what
.position
.reladdr
.addr
[3] = bcd2bin(q
.current
.relative_pos
[2]);
1609 info
->what
.position
.absaddr
.addr
[0] = 0;
1610 info
->what
.position
.absaddr
.addr
[1] = bcd2bin(q
.current
.absolute_pos
[0]);
1611 info
->what
.position
.absaddr
.addr
[2] = bcd2bin(q
.current
.absolute_pos
[1]);
1612 info
->what
.position
.absaddr
.addr
[3] = bcd2bin(q
.current
.absolute_pos
[2]);
1615 lba
= msf2hsg(q
.current
.relative_pos
, 1);
1617 * Pre-gap has index number of 0, and decreasing MSF
1618 * address. Must be converted to negative LBA, per
1621 if (info
->what
.position
.index_number
== 0x00)
1623 info
->what
.position
.reladdr
.addr
[0] = lba
>> 24;
1624 info
->what
.position
.reladdr
.addr
[1] = lba
>> 16;
1625 info
->what
.position
.reladdr
.addr
[2] = lba
>> 8;
1626 info
->what
.position
.reladdr
.addr
[3] = lba
;
1627 lba
= msf2hsg(q
.current
.absolute_pos
, 0);
1628 info
->what
.position
.absaddr
.addr
[0] = lba
>> 24;
1629 info
->what
.position
.absaddr
.addr
[1] = lba
>> 16;
1630 info
->what
.position
.absaddr
.addr
[2] = lba
>> 8;
1631 info
->what
.position
.absaddr
.addr
[3] = lba
;
1641 mcd_playtracks(struct mcd_softc
*sc
, struct ioc_play_track
*p
)
1643 struct mcd_mbox mbx
;
1644 int a
= p
->start_track
;
1645 int z
= p
->end_track
;
1649 printf("%s: playtracks: from %d:%d to %d:%d\n",
1650 device_xname(&sc
->sc_dev
),
1651 a
, p
->start_index
, z
, p
->end_index
);
1653 if (a
< bcd2bin(sc
->volinfo
.trk_low
) ||
1654 a
> bcd2bin(sc
->volinfo
.trk_high
) ||
1656 z
< bcd2bin(sc
->volinfo
.trk_low
) ||
1657 z
> bcd2bin(sc
->volinfo
.trk_high
))
1660 if ((error
= mcd_setmode(sc
, MCD_MD_COOKED
)) != 0)
1663 mbx
.cmd
.opcode
= MCD_CMDREADSINGLESPEED
;
1664 mbx
.cmd
.length
= sizeof(mbx
.cmd
.data
.play
);
1665 mbx
.cmd
.data
.play
.start_msf
[0] = sc
->toc
[a
].toc
.absolute_pos
[0];
1666 mbx
.cmd
.data
.play
.start_msf
[1] = sc
->toc
[a
].toc
.absolute_pos
[1];
1667 mbx
.cmd
.data
.play
.start_msf
[2] = sc
->toc
[a
].toc
.absolute_pos
[2];
1668 mbx
.cmd
.data
.play
.end_msf
[0] = sc
->toc
[z
+1].toc
.absolute_pos
[0];
1669 mbx
.cmd
.data
.play
.end_msf
[1] = sc
->toc
[z
+1].toc
.absolute_pos
[1];
1670 mbx
.cmd
.data
.play
.end_msf
[2] = sc
->toc
[z
+1].toc
.absolute_pos
[2];
1671 sc
->lastpb
= mbx
.cmd
;
1673 return mcd_send(sc
, &mbx
, 1);
1677 mcd_playmsf(struct mcd_softc
*sc
, struct ioc_play_msf
*p
)
1679 struct mcd_mbox mbx
;
1683 printf("%s: playmsf: from %d:%d.%d to %d:%d.%d\n",
1684 device_xname(&sc
->sc_dev
),
1685 p
->start_m
, p
->start_s
, p
->start_f
,
1686 p
->end_m
, p
->end_s
, p
->end_f
);
1688 if ((p
->start_m
* 60 * 75 + p
->start_s
* 75 + p
->start_f
) >=
1689 (p
->end_m
* 60 * 75 + p
->end_s
* 75 + p
->end_f
))
1692 if ((error
= mcd_setmode(sc
, MCD_MD_COOKED
)) != 0)
1695 mbx
.cmd
.opcode
= MCD_CMDREADSINGLESPEED
;
1696 mbx
.cmd
.length
= sizeof(mbx
.cmd
.data
.play
);
1697 mbx
.cmd
.data
.play
.start_msf
[0] = bin2bcd(p
->start_m
);
1698 mbx
.cmd
.data
.play
.start_msf
[1] = bin2bcd(p
->start_s
);
1699 mbx
.cmd
.data
.play
.start_msf
[2] = bin2bcd(p
->start_f
);
1700 mbx
.cmd
.data
.play
.end_msf
[0] = bin2bcd(p
->end_m
);
1701 mbx
.cmd
.data
.play
.end_msf
[1] = bin2bcd(p
->end_s
);
1702 mbx
.cmd
.data
.play
.end_msf
[2] = bin2bcd(p
->end_f
);
1703 sc
->lastpb
= mbx
.cmd
;
1705 return mcd_send(sc
, &mbx
, 1);
1709 mcd_playblocks(struct mcd_softc
*sc
, struct ioc_play_blocks
*p
)
1711 struct mcd_mbox mbx
;
1715 printf("%s: playblocks: blkno %d length %d\n",
1716 device_xname(&sc
->sc_dev
), p
->blk
, p
->len
);
1718 if (p
->blk
> sc
->disksize
|| p
->len
> sc
->disksize
||
1719 (p
->blk
+ p
->len
) > sc
->disksize
)
1722 if ((error
= mcd_setmode(sc
, MCD_MD_COOKED
)) != 0)
1725 mbx
.cmd
.opcode
= MCD_CMDREADSINGLESPEED
;
1726 mbx
.cmd
.length
= sizeof(mbx
.cmd
.data
.play
);
1727 hsg2msf(p
->blk
, mbx
.cmd
.data
.play
.start_msf
);
1728 hsg2msf(p
->blk
+ p
->len
, mbx
.cmd
.data
.play
.end_msf
);
1729 sc
->lastpb
= mbx
.cmd
;
1731 return mcd_send(sc
, &mbx
, 1);
1735 mcd_pause(struct mcd_softc
*sc
)
1737 union mcd_qchninfo q
;
1740 /* Verify current status. */
1741 if (sc
->audio_status
!= CD_AS_PLAY_IN_PROGRESS
) {
1742 printf("%s: pause: attempted when not playing\n",
1743 device_xname(&sc
->sc_dev
));
1747 /* Get the current position. */
1748 if ((error
= mcd_getqchan(sc
, &q
, CD_CURRENT_POSITION
)) != 0)
1751 /* Copy it into lastpb. */
1752 sc
->lastpb
.data
.seek
.start_msf
[0] = q
.current
.absolute_pos
[0];
1753 sc
->lastpb
.data
.seek
.start_msf
[1] = q
.current
.absolute_pos
[1];
1754 sc
->lastpb
.data
.seek
.start_msf
[2] = q
.current
.absolute_pos
[2];
1757 if ((error
= mcd_stop(sc
)) != 0)
1760 /* Set the proper status and exit. */
1761 sc
->audio_status
= CD_AS_PLAY_PAUSED
;
1766 mcd_resume(struct mcd_softc
*sc
)
1768 struct mcd_mbox mbx
;
1771 if (sc
->audio_status
!= CD_AS_PLAY_PAUSED
)
1774 if ((error
= mcd_setmode(sc
, MCD_MD_COOKED
)) != 0)
1777 mbx
.cmd
= sc
->lastpb
;
1779 return mcd_send(sc
, &mbx
, 1);
1783 mcd_eject(struct mcd_softc
*sc
)
1785 struct mcd_mbox mbx
;
1787 mbx
.cmd
.opcode
= MCD_CMDEJECTDISK
;
1790 return mcd_send(sc
, &mbx
, 0);
1794 mcd_setlock(struct mcd_softc
*sc
, int mode
)
1796 struct mcd_mbox mbx
;
1798 mbx
.cmd
.opcode
= MCD_CMDSETLOCK
;
1799 mbx
.cmd
.length
= sizeof(mbx
.cmd
.data
.lockmode
);
1800 mbx
.cmd
.data
.lockmode
.mode
= mode
;
1802 return mcd_send(sc
, &mbx
, 1);