2 * Copyright (C) 2013, The AROS Development Team
4 * Author: Jason S. McMullan <jason.mcmullan@gmail.com>
6 * Licensed under the AROS PUBLIC LICENSE (APL) Version 1.1
9 #include <aros/debug.h>
11 #include <aros/symbolsets.h>
13 #include <devices/cd.h>
15 #include <proto/exec.h>
16 #include <proto/alib.h>
18 #include <hardware/intbits.h>
23 #include "cd_intern.h"
25 static inline ULONG
readl(ULONG addr
)
27 return *((volatile ULONG
*)addr
);
30 static inline VOID
writel(ULONG value
, ULONG addr
)
32 *((volatile ULONG
*)addr
) = value
;
35 static inline UWORD
readw(ULONG addr
)
37 return *((volatile UWORD
*)addr
);
40 static inline VOID
writew(UWORD value
, ULONG addr
)
42 *((volatile UWORD
*)addr
) = value
;
45 static inline UBYTE
readb(ULONG addr
)
47 return *((volatile UBYTE
*)addr
);
50 static inline VOID
writeb(UBYTE value
, ULONG addr
)
52 *((volatile UBYTE
*)addr
) = value
;
64 UBYTE cs_Reserved2
[8];
69 LIBBASETYPE
*cu_CDBase
;
73 } *cu_Data
; /* x16 of these */
75 UBYTE Response
[0x100];
78 UBYTE Reserved
[0x100];
80 struct Interrupt cu_Interrupt
;
81 UBYTE cu_TxHead
, cu_RxHead
;
83 struct CDInfo cu_CDInfo
;
84 struct QCode cu_QCode
;
85 ULONG cu_TotalSectors
;
88 union CDTOC cu_CDTOC
[100];
93 static inline void CD32_Mute(struct CD32Unit
*cu
, int muted
)
98 val
= readb(0xbfe001);
104 writeb(val
, 0xbfe001);
107 cu
->cu_Muted
= muted
? 1 : 0;
111 UBYTE
dec2bcd(UBYTE dec
)
115 return ((dec
/ 10) << 4) | (dec
% 10);
118 static void sec2msf(LONG sec
, UBYTE
*msf
)
120 msf
[0] = dec2bcd(sec
/ (60 * 75));
121 sec
= sec
% (60 * 75);
122 msf
[1] = dec2bcd(sec
/ 75);
123 msf
[2] = dec2bcd(sec
% 75);
126 static ULONG
msf2sec(struct RMSF
*msf
)
128 return ((msf
->Minute
* 60) + msf
->Second
) * 75 + msf
->Frame
;
131 static VOID
CD32_IntEnable(struct CD32Unit
*cu
, ULONG mask
)
133 cu
->cu_IntEnable
|= mask
;
134 writel(cu
->cu_IntEnable
, AKIKO_CDINTENA
);
137 static VOID
CD32_IntDisable(struct CD32Unit
*cu
, ULONG mask
)
139 cu
->cu_IntEnable
&= ~mask
;
140 writel(cu
->cu_IntEnable
, AKIKO_CDINTENA
);
143 static AROS_INTH1(CD32_Interrupt
, struct CD32Unit
*, cu
)
145 const UBYTE resp_len
[16] = {
146 1, 2, 2, 2, 2, 2, 15, 20, 0, 0, 2, 0, 0, 0, 0, 0
153 status
= readl(AKIKO_CDINTREQ
);
157 if (status
& AKIKO_CDINT_RXDMA
) {
158 rxtail
= readb(AKIKO_CDRXINX
);
159 if (((cu
->cu_RxHead
+1)&0xff) == rxtail
) {
160 /* Add the correct length for the full response */
161 UBYTE len
= resp_len
[cu
->cu_Misc
->Response
[cu
->cu_RxHead
] & 0xf];
163 D(bug("%s: Insane response byte 0x%02x\n", cu
->cu_Misc
->Response
[cu
->cu_RxHead
]));
165 writeb(cu
->cu_RxHead
+len
+1, AKIKO_CDRXCMP
);
168 CD32_IntDisable(cu
, AKIKO_CDINT_RXDMA
);
169 D(bug("%s: Signal %p\n", __func__
, cu
->cu_Task
));
170 Signal(cu
->cu_Task
, SIGF_SINGLE
);
173 if (status
& AKIKO_CDINT_TXDMA
) {
174 CD32_IntDisable(cu
, AKIKO_CDINT_TXDMA
);
178 if (status
& AKIKO_CDINT_OVERFLOW
) {
179 CD32_IntDisable(cu
, AKIKO_CDINT_OVERFLOW
);
180 Signal(cu
->cu_Task
, SIGF_SINGLE
);
184 if (status
& AKIKO_CDINT_PBX
) {
185 UWORD pbx
= readw(AKIKO_CDPBX
);
186 writew(0, AKIKO_CDPBX
);
188 Signal(cu
->cu_Task
, SIGF_SINGLE
);
196 static UBYTE
bcd2dec(UBYTE bcd
)
198 return (bcd
& 0xf) + ((bcd
>> 4) & 0xf) * 10;
201 static VOID
CD32_UpdateTOC(struct CD32Unit
*cu
)
203 struct QCode
*qc
= &cu
->cu_QCode
;
205 D(bug("%s: Index 0x%02x\n", __func__
, qc
->Index
));
208 cu
->cu_CDTOC
[0].Summary
.FirstTrack
= bcd2dec(qc
->DiskPosition
.MSF
.Minute
);
211 cu
->cu_CDTOC
[0].Summary
.LastTrack
= bcd2dec(qc
->DiskPosition
.MSF
.Minute
);
214 cu
->cu_CDTOC
[0].Summary
.LeadOut
= qc
->DiskPosition
;
215 cu
->cu_CDInfo
.Status
|= CDSTSF_TOC
;
218 if (((qc
->Index
& 0xf) <= 9) && ((qc
->Index
& 0xf0) <= 0x90) &&
220 int track
= bcd2dec(qc
->Index
);
221 cu
->cu_CDTOC
[track
].Entry
.CtlAdr
= qc
->CtlAdr
;
222 cu
->cu_CDTOC
[track
].Entry
.Track
= track
;
223 cu
->cu_CDTOC
[track
].Entry
.Position
= qc
->DiskPosition
;
224 if (track
== 1 && qc
->CtlAdr
== 0x41) {
225 cu
->cu_CDInfo
.Status
|= CDSTSF_CDROM
;
228 D(bug("%s: Illegal track number 0x%02x ignored\n", __func__
, qc
->Index
));
234 static LONG
CD32_Cmd(struct CD32Unit
*cu
, UBYTE
*cmd
, LONG cmd_len
, UBYTE
*resp
, LONG resp_len
)
240 if (cu
->cu_Sequence
>= 16)
243 cmd
[0] = (cmd
[0] & 0xf) | (cu
->cu_Sequence
<< 4);
246 for (i
= 0; i
< cmd_len
; i
++) {
247 /* NOTE: We are relying on the fact that cu_TxHead is a
248 * UBYTE, so that it wraps at 0x100
250 cu
->cu_Misc
->Command
[cu
->cu_TxHead
++] = cmd
[i
];
254 cu
->cu_Misc
->Command
[cu
->cu_TxHead
++] = ~csum
;
256 /* Just wait for the RX to complete of the status */
257 CD32_IntEnable(cu
, AKIKO_CDINT_RXDMA
| AKIKO_CDINT_TXDMA
);
258 writel(AKIKO_CDFLAG_TXD
| AKIKO_CDFLAG_RXD
| AKIKO_CDFLAG_CAS
| AKIKO_CDFLAG_PBX
| AKIKO_CDFLAG_MSB
, AKIKO_CDFLAG
);
260 /* Trigger the command by updating AKIKO_CDTXCMP */
261 SetSignal(0, SIGF_SINGLE
);
262 writeb((cu
->cu_RxHead
+ 1) & 0xff, AKIKO_CDRXCMP
);
263 writeb(cu
->cu_TxHead
, AKIKO_CDTXCMP
);
266 UBYTE RxHead
= cu
->cu_RxHead
;
268 D(bug("%s: %02x Wait...\n", __func__
, cmd
[0]));
270 D(bug("%s: %02x Waited.\n", __func__
, cmd
[0]));
272 RxTail
= readb(AKIKO_CDRXINX
);
273 D(bug("%s: RxHead=%02x RxTail=%02x\n", __func__
, RxHead
, RxTail
));
275 if (cu
->cu_Misc
->Response
[RxHead
] == cmd
[0])
278 D(bug("%s: Found unexpected: 0x%02x (%d)\n", __func__
, cu
->cu_Misc
->Response
[RxHead
], (RxTail
+ 256 - RxHead
) & 0xff));
281 while (RxHead
!= RxTail
) {
282 /* NOTE: We are relying on the fact that cu_RxHead is a
283 * UBYTE, so that it wraps at 0x100
285 UBYTE val
= cu
->cu_Misc
->Response
[RxHead
++];
286 D(bug("%02x ", val
));
289 D(bug(" (%02x)\n", csum
));
292 D(bug("%s: Checksum failed on RX\n", __func__
));
293 return CDERR_NotSpecified
;
296 RxHead
= cu
->cu_RxHead
;
297 cu
->cu_RxHead
= RxTail
;
299 switch (cu
->cu_Misc
->Response
[RxHead
]) {
302 if (cu
->cu_Misc
->Response
[RxHead
] == 0x83) {
303 if (!(cu
->cu_CDInfo
.Status
& CDSTSF_DISK
)) {
305 cu
->cu_CDInfo
.Status
|= CDSTSF_CLOSED
| CDSTSF_DISK
| CDSTSF_SPIN
;
308 if (cu
->cu_CDInfo
.Status
& CDSTSF_DISK
) {
310 cu
->cu_CDInfo
.Status
= 0;
318 cu
->cu_QCode
.CtlAdr
= cu
->cu_Misc
->Response
[RxHead
++];
319 cu
->cu_QCode
.Track
= cu
->cu_Misc
->Response
[RxHead
++];
320 cu
->cu_QCode
.Index
= cu
->cu_Misc
->Response
[RxHead
++];
321 cu
->cu_QCode
.Zero
= 0;
322 cu
->cu_QCode
.TrackPosition
.MSF
.Reserved
= 0;
323 cu
->cu_QCode
.TrackPosition
.MSF
.Minute
= cu
->cu_Misc
->Response
[RxHead
++];
324 cu
->cu_QCode
.TrackPosition
.MSF
.Second
= cu
->cu_Misc
->Response
[RxHead
++];
325 cu
->cu_QCode
.TrackPosition
.MSF
.Frame
= cu
->cu_Misc
->Response
[RxHead
++];
326 cu
->cu_QCode
.DiskPosition
.MSF
.Reserved
= cu
->cu_Misc
->Response
[RxHead
++];
327 cu
->cu_QCode
.DiskPosition
.MSF
.Minute
= cu
->cu_Misc
->Response
[RxHead
++];
328 cu
->cu_QCode
.DiskPosition
.MSF
.Second
= cu
->cu_Misc
->Response
[RxHead
++];
329 cu
->cu_QCode
.DiskPosition
.MSF
.Frame
= cu
->cu_Misc
->Response
[RxHead
++];
330 if (!(cu
->cu_CDInfo
.Status
& CDSTSF_TOC
))
336 D(bug("%s: Command mismatch: got 0x%02x, expected 0x%02x\n", __func__
, cu
->cu_Misc
->Response
[RxHead
], cmd
[0]));
337 return CDERR_InvalidState
;
340 writeb((RxTail
+ 1) & 0xff, AKIKO_CDRXCMP
);
343 D(bug("%s: Found expected: 0x%02x (%d)\n", __func__
, cu
->cu_Misc
->Response
[cu
->cu_RxHead
], (RxTail
+ 256 - cu
->cu_RxHead
) & 0xff));
346 while (cu
->cu_RxHead
!= RxTail
) {
347 /* NOTE: We are relying on the fact that cu_RxHead is a
348 * UBYTE, so that it wraps at 0x100
350 UBYTE val
= cu
->cu_Misc
->Response
[cu
->cu_RxHead
++];
351 D(bug("%02x ", val
));
358 D(bug("(%02x)\n", csum
));
361 D(bug("%s: Checksum failed on RX\n", __func__
));
362 return CDERR_NotSpecified
;
365 D(bug("%s: -- RXHead %2x --\n", __func__
, cu
->cu_RxHead
));
370 static VOID
CD32_Led(struct CD32Unit
*cu
, BOOL led_on
)
372 UBYTE cmd
[2] = { CHCD_LED
, (led_on
? 1 : 0) | 0x80 };
375 CD32_Cmd(cu
, cmd
, 2, resp
, 2);
378 static LONG
CD32_CmdRead(struct CD32Unit
*cu
, LONG sect_start
, LONG sectors
, void (*copy_sector
)(APTR sector
, APTR priv
), APTR priv
)
381 UBYTE cmd
[12], resp
[2];
382 UBYTE cmd_pause
[1] = { CHCD_PAUSE
};
383 UBYTE cmd_unpause
[1] = { CHCD_UNPAUSE
};
387 while (sectors
> 0) {
388 cu
->cu_CDInfo
.Status
&= ~(CDSTSF_PLAYING
| CDSTSF_PAUSED
| CDSTSF_SEARCH
| CDSTSF_DIRECTION
);
391 sec2msf(sect_start
, &cmd
[1]);
392 sec2msf(sect_start
+ 16, &cmd
[4]);
393 cmd
[7] = 0x80; /* Data read */
394 cmd
[8] = (cu
->cu_CDInfo
.PlaySpeed
>= 150) ? 0x40 : 0x00;
397 cmd
[10] = 0x04; /* 0x04 to enable the motor */
400 writew(0xffff, AKIKO_CDPBX
);
404 CD32_Cmd(cu
, cmd_unpause
, 1, resp
, sizeof(resp
));
405 err
= CD32_Cmd(cu
, cmd
, sizeof(cmd
), resp
, sizeof(resp
));
409 if ((resp
[1] & 2) != 2)
410 return CDERR_SeekError
;
413 /* Wait for (most) sectors to come in */
414 CD32_IntEnable(cu
, AKIKO_CDINT_PBX
);
416 writel(readl(AKIKO_CDFLAG
) | AKIKO_CDFLAG_ENABLE
, AKIKO_CDFLAG
);
419 CD32_Cmd(cu
, cmd_pause
, 1, resp
, sizeof(resp
));
421 pbx
= readw(AKIKO_CDPBX
);
424 D(bug("%s: Overflow during read\n", __func__
));
428 for (i
= 15; i
>= 0; i
--) {
429 if (!(pbx
& (1 << i
))) {
430 D(bug("%s: SECTOR: %d\n", __func__
, *(ULONG
*)(&cu
->cu_Data
[i
])));
431 copy_sector(&cu
->cu_Data
[i
], priv
);
444 static UBYTE
CD32_Status(struct CD32Unit
*cu
)
446 UBYTE cmd
[1], res
[21];
448 cu
->cu_Task
= FindTask(NULL
);
449 D(bug("%s: %p\n", __func__
, cu
));
450 cmd
[0] = CHCD_STATUS
;
452 CD32_Cmd(cu
, cmd
, 1, res
, 20);
454 D(bug("%s: Drive \"%s\", state 0x%02x\n", __func__
, &res
[2], res
[1]));
456 if (res
[1] & CHERR_BADCOMMAND
) {
457 if (cu
->cu_CDInfo
.Status
& CDSTSF_DISK
) {
459 cu
->cu_CDInfo
.Status
= 0;
461 } else if (res
[1] & CHERR_DISKPRESENT
) {
462 if (!(cu
->cu_CDInfo
.Status
& CDSTSF_DISK
)) {
464 cu
->cu_CDInfo
.Status
|= CDSTSF_CLOSED
| CDSTSF_DISK
| CDSTSF_SPIN
;
468 D(bug("%s: %p = 0x%08x\n", __func__
, cu
, cu
->cu_CDInfo
.Status
));
469 return cu
->cu_CDInfo
.Status
;
472 static VOID
CD32_ReadTOC(struct CD32Unit
*cu
)
474 UBYTE toc_cmd
[12] = { CHCD_MULTI
, 0, 0, 0, 0, 0, 0, 0x03, 0x40, 0, 0x00, 0 };
475 UBYTE idle_cmd
[1] = { CHCD_UNPAUSE
};
477 ULONG timeout
= 5 * 1000; /* 5 second timeout */
480 /* Start the read TOC command */
481 if (CD32_Cmd(cu
, toc_cmd
, 12, resp
, 2) != 0)
484 /* Until the TOC is read, blink the LED and unpause */
485 D(bug("%s: Waiting for TOC for up to 10 seconds\n", __func__
));
486 while (!(cu
->cu_CDInfo
.Status
& CDSTSF_TOC
) && timeout
> 0) {
489 cdDelayMS(cu
->cu_CDBase
, 100); /* Delay 100ms */
490 CD32_Cmd(cu
, idle_cmd
, 1, resp
, 2);
494 if (cu
->cu_CDInfo
.Status
& CDSTSF_CDROM
) {
495 if (cu
->cu_CDTOC
[0].Summary
.LastTrack
== 1) {
496 cu
->cu_TotalSectors
= msf2sec(&cu
->cu_CDTOC
[0].Summary
.LeadOut
.MSF
) -
497 msf2sec(&cu
->cu_CDTOC
[1].Entry
.Position
.MSF
);
499 cu
->cu_TotalSectors
= msf2sec(&cu
->cu_CDTOC
[2].Entry
.Position
.MSF
) -
500 msf2sec(&cu
->cu_CDTOC
[1].Entry
.Position
.MSF
);
503 cu
->cu_TotalSectors
= 0;
506 D(bug("%s: TotalSectors = %d\n", __func__
, cu
->cu_TotalSectors
));
509 static LONG
CD32_IsCDROM(struct CD32Unit
*cu
)
511 if ((cu
->cu_CDInfo
.Status
& CDSTSF_DISK
) == 0) {
512 if ((CD32_Status(cu
) & CDSTSF_DISK
) == 0)
516 if ((cu
->cu_CDInfo
.Status
& CDSTSF_TOC
) == 0) {
520 if ((cu
->cu_CDInfo
.Status
& CDSTSF_CDROM
) == 0) {
521 return CDERR_SeekError
;
534 static VOID
CD32_CopyREAD(APTR frame
, APTR priv
)
536 struct CD32Mode1
*mode1
= frame
;
537 struct CopyREAD
*cr
= priv
;
540 tocopy
= 2048 - cr
->offset
;
541 if (tocopy
> cr
->length
)
544 D(bug("%s: Copy from 0x%08x to 0x%08x, %d\n", __func__
, &mode1
->cs_Data
[cr
->offset
], cr
->buffer
, tocopy
));
545 CopyMem(&mode1
->cs_Data
[cr
->offset
], cr
->buffer
, tocopy
);
547 for (i
= 0; i
< tocopy
; i
++) {
549 if (mod
== 0) D(bug("%08x:", cr
->buffer
- (UBYTE
*)cr
->io
->io_Data
+ i
));
550 D(bug("%c%02x", (mod
==8) ? '-' : ' ', cr
->buffer
[i
]));
551 if (mod
== 15) D(bug("\n"));
557 cr
->length
-= tocopy
;
558 cr
->buffer
+= tocopy
;
559 cr
->io
->io_Actual
+= tocopy
;
563 static LONG
CD32_DoIO(struct IOStdReq
*io
, APTR priv
)
565 struct CD32Unit
*cu
= priv
;
566 LONG err
= CDERR_NOCMD
;
567 UBYTE cmd
[16], res
[16];
568 LONG sect_start
, sect_end
, origin
;
571 D(bug("%s:%p io_Command=%d\n", __func__
, io
, io
->io_Command
));
573 cu
->cu_Task
= FindTask(NULL
);
575 switch (io
->io_Command
) {
577 io
->io_Actual
= cu
->cu_ChangeNum
;
581 io
->io_Actual
= (cu
->cu_CDInfo
.Status
& CDSTSF_TOC
) ? 0 : 1;
582 D(bug("CD_CHANGESTATE: %d\n", io
->io_Actual
));
586 D(bug("CD_CONFIG: Data %p, Length %d\n", io
->io_Data
, io
->io_Length
));
587 if (io
->io_Length
!= 0) {
588 err
= CDERR_BADLENGTH
;
591 /* Gah. Some bright spark decided to use tags with
592 * the same values as TAG_IGNORE, TAG_MORE, and TAG_SKIP,
593 * so we have to process the TagItem array manually.
596 if (io
->io_Data
!= NULL
) {
597 struct TagItem
*ti
= io
->io_Data
;
600 switch (ti
->ti_Tag
) {
601 case TAGCD_PLAYSPEED
:
602 if (((ti
->ti_Data
% 75) != 0) ||
603 (ti
->ti_Data
> cu
->cu_CDInfo
.MaxSpeed
)) {
604 err
= CDERR_InvalidState
;
608 cu
->cu_CDInfo
.PlaySpeed
= ti
->ti_Data
;
610 case TAGCD_READSPEED
:
611 if (((ti
->ti_Data
% 75) != 0) ||
612 (ti
->ti_Data
> cu
->cu_CDInfo
.MaxSpeed
)) {
613 err
= CDERR_InvalidState
;
617 cu
->cu_CDInfo
.ReadSpeed
= ti
->ti_Data
;
620 case TAGCD_READXLSPEED
:
621 if (((ti
->ti_Data
% 75) != 0) ||
622 (ti
->ti_Data
> cu
->cu_CDInfo
.MaxSpeed
)) {
623 err
= CDERR_InvalidState
;
627 cu
->cu_CDInfo
.ReadXLSpeed
= ti
->ti_Data
;
630 case TAGCD_SECTORSIZE
:
631 if (ti
->ti_Data
!= 2048 &&
632 ti
->ti_Data
!= 2328) {
633 err
= CDERR_InvalidState
;
637 cu
->cu_CDInfo
.SectorSize
= ti
->ti_Data
;
641 cu
->cu_CDInfo
.XLECC
= ti
->ti_Data
? 1 : 0;
643 case TAGCD_EJECTRESET
:
644 cu
->cu_CDInfo
.EjectReset
= ti
->ti_Data
? 1 : 0;
653 D(bug("CD_CONFIG: Tag %d, Item %d, err %d, done %d\n", ti
->ti_Tag
, ti
->ti_Data
, err
, done
));
658 D(bug("CD_TOCMSF: %d\n", io
->io_Length
));
659 err
= CD32_IsCDROM(cu
);
660 D(bug("CD_TOCMSF: check %d\n", err
));
661 if (io
->io_Data
!= NULL
&& (cu
->cu_CDInfo
.Status
& CDSTSF_TOC
)) {
663 ULONG track
= io
->io_Offset
;
664 APTR buff
= io
->io_Data
;
665 for (i
= 0; i
< io
->io_Length
&& track
<= cu
->cu_CDTOC
[0].Summary
.LastTrack
; i
++, track
++) {
666 CopyMem(&cu
->cu_CDTOC
[track
], buff
, sizeof(union CDTOC
));
668 buff
+=sizeof(union CDTOC
);
670 io
->io_Actual
= actual
;
673 D(bug("CD_TOCMSF: err %d\n", err
));
680 err
= CD32_IsCDROM(cu
);
682 D(bug("CD_GETGEOMETRY: Not a data disk\n"));
686 if (io
->io_Length
>= sizeof(struct DriveGeometry
)) {
687 struct DriveGeometry
*dg
= (struct DriveGeometry
*)io
->io_Data
;
688 dg
->dg_SectorSize
= cu
->cu_CDInfo
.SectorSize
;
689 dg
->dg_TotalSectors
= cu
->cu_TotalSectors
;
690 dg
->dg_Cylinders
= cu
->cu_TotalSectors
;
691 dg
->dg_CylSectors
= 1;
693 dg
->dg_TrackSectors
= 1;
694 dg
->dg_BufMemType
= MEMF_PUBLIC
;
695 dg
->dg_DeviceType
= DG_CDROM
;
696 dg
->dg_Flags
= DGF_REMOVABLE
;
698 io
->io_Actual
= sizeof(*dg
);
701 err
= CDERR_BADLENGTH
;
705 if (io
->io_Length
>= sizeof(struct CDInfo
)) {
707 CopyMem(&cu
->cu_CDInfo
, io
->io_Data
, sizeof(struct CDInfo
));
708 io
->io_Actual
= sizeof(struct CDInfo
);
714 io
->io_Actual
= (cu
->cu_CDInfo
.Status
& CDSTSF_PAUSED
) ? 1 : 0;
715 if (cu
->cu_CDInfo
.Status
& CDSTSF_TOC
) {
716 UBYTE cmd
[1] = { io
->io_Length
? CHCD_PAUSE
: CHCD_UNPAUSE
};
718 err
= CD32_Cmd(cu
, cmd
, 1, res
, 1);
721 cu
->cu_CDInfo
.Status
|= CDSTSF_PAUSED
;
723 cu
->cu_CDInfo
.Status
&= ~CDSTSF_PAUSED
;
729 io
->io_Actual
= (cu
->cu_CDInfo
.Status
& CDSTSF_SPIN
);
730 if (io
->io_Length
== 0) {
731 UBYTE cmd
[1] = { CHCD_STOP
}, res
[1];
732 err
= CD32_Cmd(cu
, cmd
, 1, res
, 1);
734 cu
->cu_CDInfo
.Status
&= ~CDSTSF_SPIN
;
737 cu
->cu_CDInfo
.Status
|= CDSTSF_SPIN
;
741 if (io
->io_Offset
<= cu
->cu_CDTOC
[0].Summary
.LastTrack
) {
742 ULONG last
= io
->io_Offset
+ io
->io_Length
;
743 UBYTE cmd
[12], res
[2];
745 cmd
[1] = cu
->cu_CDTOC
[io
->io_Offset
].Entry
.Position
.MSF
.Minute
;
746 cmd
[2] = cu
->cu_CDTOC
[io
->io_Offset
].Entry
.Position
.MSF
.Second
;
747 cmd
[3] = cu
->cu_CDTOC
[io
->io_Offset
].Entry
.Position
.MSF
.Frame
;
748 if (last
> cu
->cu_CDTOC
[0].Summary
.LastTrack
) {
749 cmd
[4] = cu
->cu_CDTOC
[0].Summary
.LeadOut
.MSF
.Minute
;
750 cmd
[5] = cu
->cu_CDTOC
[0].Summary
.LeadOut
.MSF
.Minute
;
751 cmd
[6] = cu
->cu_CDTOC
[0].Summary
.LeadOut
.MSF
.Minute
;
753 cmd
[4] = cu
->cu_CDTOC
[last
].Entry
.Position
.MSF
.Minute
;
754 cmd
[5] = cu
->cu_CDTOC
[last
].Entry
.Position
.MSF
.Second
;
755 cmd
[6] = cu
->cu_CDTOC
[last
].Entry
.Position
.MSF
.Frame
;
758 cmd
[8] = (cu
->cu_CDInfo
.ReadSpeed
>= 150) ? 0x40 : 0x00;
762 err
= CD32_Cmd(cu
, cmd
, 12, res
, 2);
763 D(bug("CD_PLAYTRACK: err=%d, res[1]=0x%02x\n", err
, res
[1]));
764 if (!err
&& (res
[1] & 0x80) == 0) {
765 cu
->cu_CDInfo
.Status
&= ~(CDSTSF_PLAYING
| CDSTSF_PAUSED
| CDSTSF_SEARCH
| CDSTSF_DIRECTION
);
766 cu
->cu_CDInfo
.Status
|= CDSTSF_PLAYING
;
767 D(bug("CD_PLAYTRACK: Playing tracks %d-%d\n", io
->io_Offset
, last
-1));
773 err
= CD32_IsCDROM(cu
);
777 /* Convert offset and length to MSF */
783 origin
= msf2sec(&cu
->cu_CDTOC
[1].Entry
.Position
.MSF
);
784 sect_start
= io
->io_Offset
/ cu
->cu_CDInfo
.SectorSize
;
785 sect_end
= (io
->io_Offset
+ io
->io_Length
+ cu
->cu_CDInfo
.SectorSize
- 1) / cu
->cu_CDInfo
.SectorSize
;
788 cr
.buffer
= io
->io_Data
;
789 cr
.offset
= io
->io_Offset
% cu
->cu_CDInfo
.SectorSize
;
790 cr
.length
= io
->io_Length
;
792 err
= CD32_CmdRead(cu
, sect_start
+ origin
, sect_end
- sect_start
, CD32_CopyREAD
, &cr
);
796 err
= CD32_Cmd(cu
, cmd
, 1, res
, 1);
800 io
->io_Actual
= cu
->cu_Muted
? 0 : 0x7fff;
801 if (io
->io_Offset
> 0 && io
->io_Offset
< 0x7fff) {
802 CD32_Mute(cu
, io
->io_Offset
== 0);
810 D(bug("%s:%p err=%d (Actual %d)\n", __func__
, io
, err
, io
->io_Actual
));
814 static VOID
CD32_Expunge(APTR priv
)
816 struct CD32Unit
*cu
= priv
;
817 RemIntServer(INTB_PORTS
, &cu
->cu_Interrupt
);
818 FreeMem(cu
->cu_Misc
, sizeof(struct CD32Misc
));
819 FreeMem(cu
->cu_Data
, sizeof(struct CD32Data
) * 16);
823 static const struct cdUnitOps CD32Ops
= {
824 .uo_Name
= "CD32 (Akiko)",
825 .uo_Expunge
= CD32_Expunge
,
826 .uo_DoIO
= CD32_DoIO
,
829 static const struct DosEnvec CD32Envec
= {
830 .de_TableSize
= DE_MASK
,
831 .de_SizeBlock
= 2048 >> 2,
833 .de_SectorPerBlock
= 1,
834 .de_BlocksPerTrack
= 1,
841 .de_BufMemType
= MEMF_24BITDMA
,
842 .de_MaxTransfer
= 32 * 2048,
843 .de_Mask
= 0x00fffffe,
847 static int CD32_InitLib(LIBBASETYPE
*cb
)
850 struct CD32Unit
*priv
;
852 if (readw(AKIKO_ID
) != AKIKO_ID_MAGIC
) {
853 D(bug("%s: No Akiko detected\n", __func__
));
857 /* Reset the Akiko CD32 interface */
858 writeb(readb(AKIKO_CDRESET
) | 0x80, AKIKO_CDRESET
);
859 writeb(readb(AKIKO_CDRESET
) & ~0x80, AKIKO_CDRESET
);
861 /* Disable the CD32 interface for the moment */
862 priv
= AllocVec(sizeof(*priv
), MEMF_ANY
| MEMF_CLEAR
);
864 priv
->cu_CDBase
= cb
;
865 priv
->cu_Misc
= LibAllocAligned(sizeof(struct CD32Misc
), MEMF_24BITDMA
| MEMF_CLEAR
, 1024);
867 priv
->cu_Data
= LibAllocAligned(sizeof(struct CD32Data
) * 16, MEMF_24BITDMA
| MEMF_CLEAR
, 4096);
869 priv
->cu_Interrupt
.is_Node
.ln_Pri
= 0;
870 priv
->cu_Interrupt
.is_Node
.ln_Name
= (STRPTR
)CD32Ops
.uo_Name
;
871 priv
->cu_Interrupt
.is_Node
.ln_Type
= NT_INTERRUPT
;
872 priv
->cu_Interrupt
.is_Data
= priv
;
873 priv
->cu_Interrupt
.is_Code
= (VOID_FUNC
)CD32_Interrupt
;
874 AddIntServer(INTB_PORTS
, &priv
->cu_Interrupt
);
876 writel((IPTR
)priv
->cu_Data
, AKIKO_CDADRDATA
);
877 writel((IPTR
)priv
->cu_Misc
, AKIKO_CDADRMISC
);
878 priv
->cu_TxHead
= readb(AKIKO_CDTXINX
);
879 priv
->cu_RxHead
= readb(AKIKO_CDRXINX
);
880 writeb(priv
->cu_TxHead
, AKIKO_CDTXCMP
);
881 writeb(priv
->cu_RxHead
, AKIKO_CDRXCMP
);
883 priv
->cu_CDInfo
.SectorSize
= 2048;
884 priv
->cu_CDInfo
.MaxSpeed
= 150;
885 priv
->cu_CDInfo
.PlaySpeed
= 75;
886 priv
->cu_CDInfo
.ReadSpeed
= 150;
887 priv
->cu_CDInfo
.ReadXLSpeed
= 150;
888 priv
->cu_CDInfo
.AudioPrecision
= 1;
891 unit
= cdAddUnit(cb
, &CD32Ops
, priv
, &CD32Envec
);
893 D(bug("%s: Akiko as CD Unit %d\n", __func__
, unit
));
897 /* Unmute the CDROM */
900 RemIntServer(INTB_PORTS
, &priv
->cu_Interrupt
);
902 FreeMem(priv
->cu_Data
, sizeof(struct CD32Data
) * 16);
904 FreeMem(priv
->cu_Misc
, sizeof(struct CD32Misc
));
912 static int CD32_ExpungeLib(LIBBASETYPE
*cb
)
919 ADD2INITLIB(CD32_InitLib
, 32);
920 ADD2EXPUNGELIB(CD32_ExpungeLib
, 32);