3 * Basic interaction with the CDROM drive.
5 * ----------------------------------------------------------------------
6 * This code is (C) Copyright 1993,1994 by Frank Munkert.
7 * (C) Copyright 2002-2011 The AROS Development Team
9 * This software may be freely distributed and redistributed for
10 * non-commercial purposes, provided this notice is included.
11 * ----------------------------------------------------------------------
14 * 18-Dec-11 twilen Added media change interrupt support.
15 * 11-Aug-10 sonic Fixed comparison warning in Has_Audio_Tracks()
16 * 01-Mar-10 neil Do not read past end of disc.
17 * 12-Jun-09 neil If drive returns incorrect TOC length, calculate it
18 * based on the number of tracks.
19 * 09-May-09 weissms - Let Do_SCSI_Command result depend on DoIO result.
20 * - Removed redundant checks of io_Error, some code reuse
21 * (Clear_Sector_Buffers).
22 * 20-Mar-09 sonic - Removed usage of AROS-specific include
23 * 08-Mar-09 error - Corrected Test_Unit_Ready returning only NO_DISC state
24 * 06-Mar-09 error - Removed madness, fixed insanity. Cleanup started
25 * 06-Jun-08 sonic - Fixed to compile with gcc v2
26 * 30-Mar-08 error - Updated 'Find_Last_Session' with a generic command
27 * mandatory for all MMC devices; corrected major flaw
28 * with uninitialized variables
29 * 12-Aug-07 sonic - Added some debug output.
30 * 09-Apr-07 sonic - Disabled DirectSCSI on AROS.
31 * 08-Apr-07 sonic - Removed redundant TRACKDISK option.
32 * - Added trackdisk64 support.
33 * - Removed unneeded dealing with block length.
34 * 07-Jul-02 sheutlin various changes when porting to AROS
35 * - global variables are now in a struct Globals *global
36 * 02-Sep-94 fmu Display READ TOC for Apple CD 150 drives.
37 * 01-Sep-94 fmu Workaround for bad NEC 3X READ TOC command in
38 * Has_Audio_Tracks() and Data_Tracks().
39 * 20-Aug-94 fmu New function Find_Last_Session ().
40 * 23-Jul-94 fmu Last index modified from 99 to 1 in Start_Play_Audio().
41 * 18-May-94 fmu New drive model: MODEL_CDU_8002 (= Apple CD 150).
42 * 17-May-94 fmu Sense length 20 instead of 18 (needed by ALF controller).
43 * 17-Feb-94 fmu Added support for Toshiba 4101.
44 * 06-Feb-94 dmb - Fixed bug in Test_Unit_Ready() trackdisk support.
45 * - Fixed bug in Open_CDROM (size of request)
46 * - Added function Clear_Sector_Buffers().
47 * 01-Jan-94 fmu Added function Data_Tracks() for multisession support.
48 * 11-Dec-93 fmu - Memory type can now be chosen by the user.
49 * - Addional parameter p_direction for Do_SCSI_Command().
50 * - Start_Play_Audio() now plays all tracks.
51 * - Mode_Select() instead of Select_XA_Mode().
52 * - Support for CDROM drives with 512, 1024 or 2048 bytes
54 * 06-Dec-93 fmu New drive type DRIVE_SCSI_2.
55 * 09-Nov-93 fmu Added Select_XA_Mode.
56 * 23-Oct-93 fmu Open_CDROM now returns an error code that tell what
58 * 09-Oct-93 fmu SAS/C support added.
59 * 03-Oct-93 fmu New buffering algorithm.
60 * 27-Sep-93 fmu Added support for multi-LUN devices.
61 * 24-Sep-93 fmu - SCSI buffers may now reside in fast or chip memory.
62 * - TD_CHANGESTATE instead of CMD_READ in Test_Unit_Ready
65 #include <proto/alib.h>
66 #include <proto/exec.h>
67 #include <devices/trackdisk.h>
70 #include <devices/newstyle.h>
71 #define TD_READ64 NSCMD_TD_READ64
82 #include "clib_stuff.h"
83 #include <exec/interrupts.h>
85 AROS_INTH1(CDChangeHandler
, struct CDVDBase
*, global
)
89 Signal(&global
->DosProc
->pr_Task
, global
->g_changeint_sigbit
);
96 * i decided to change few things to make this code less insane.
97 * biggest change is - i don't care any more if anyone reads one sector at a time
98 * reading disc 1 sector at a time is totally insane.
99 * presently our schema will read 16 sectors instead, that is, 32768bytes at a time
100 * that should give us SIGNIFICANT speed improvement. unfortunately has some impact
101 * on a cache, too, but that will change over time. currently, cache will eat
102 * STD_BUFFERS * 16 * 2048 bytes
107 struct CDVDBase
*global
,
110 uint32_t p_memory_type
,
117 int err
= CDROMERR_OK
;
124 err
= CDROMERR_NO_MEMORY
;
125 cd
= AllocVec (sizeof (CDROM
), MEMF_PUBLIC
| MEMF_CLEAR
| p_memory_type
);
131 cd
->buffers_cnt
= p_std_buffers
;
134 * change: allocating 16 * SCSI_BUFSIZE * bufs; min access unit 32kB!
136 cd
->buffer_data
= AllocVec (((SCSI_BUFSIZE
* p_std_buffers
) << 4) + 15, MEMF_PUBLIC
| p_memory_type
);
137 if (NULL
== cd
->buffer_data
)
140 cd
->buffer_io
= AllocVec(SCSI_BUFSIZE
, p_memory_type
);
141 if (NULL
== cd
->buffer_io
)
144 cd
->buffers
= AllocVec (sizeof (unsigned char *) * p_std_buffers
, MEMF_PUBLIC
);
145 if (NULL
== cd
->buffers
)
148 cd
->current_sectors
= AllocVec (sizeof (long) * p_std_buffers
, MEMF_PUBLIC
);
149 if (NULL
== cd
->current_sectors
)
152 cd
->last_used
= AllocVec (sizeof (uint32_t) * p_std_buffers
, MEMF_PUBLIC
| MEMF_CLEAR
);
153 if (NULL
== cd
->last_used
)
158 * make the buffer quad-word aligned. This greatly helps
159 * performance on '040-powered systems with DMA SCSI
162 cd
->buffers
[0] = (UBYTE
*)(((IPTR
)cd
->buffer_data
+ 15) & ~15);
163 cd
->current_sectors
[0] = -1;
165 for (i
=1; i
<cd
->buffers_cnt
; i
++)
167 cd
->current_sectors
[i
] = -1;
168 cd
->buffers
[i
] = cd
->buffers
[i
-1] + (SCSI_BUFSIZE
<< 4);
171 err
= CDROMERR_MSGPORT
;
172 cd
->port
= CreateMsgPort ();
173 if (NULL
== cd
->port
)
176 err
= CDROMERR_IOREQ
;
177 cd
->scsireq
= (struct IOStdReq
*)CreateIORequest (cd
->port
, sizeof (struct IOExtTD
));
178 if (NULL
== cd
->scsireq
)
181 err
= CDROMERR_DEVICE
;
182 if (OpenDevice ((UBYTE
*) p_device
, p_scsi_id
, (struct IORequest
*) cd
->scsireq
, 0))
185 cd
->device_open
= TRUE
;
187 if (global
->g_scan_interval
< 0) {
188 /* Add media change interrupts */
189 cd
->iochangeint
= (struct IOStdReq
*)AllocVec(sizeof (struct IOExtTD
), MEMF_PUBLIC
);
190 if (NULL
== cd
->iochangeint
)
192 CopyMem(cd
->scsireq
, cd
->iochangeint
, sizeof (struct IOExtTD
));
193 cd
->changeint
.is_Node
.ln_Type
= NT_INTERRUPT
;
194 cd
->changeint
.is_Node
.ln_Name
= "CDFS ChangeInt";
195 cd
->changeint
.is_Data
= (APTR
)global
;
196 cd
->changeint
.is_Code
= (VOID_FUNC
)CDChangeHandler
;
197 cd
->iochangeint
->io_Length
= sizeof(struct Interrupt
);
198 cd
->iochangeint
->io_Data
= &cd
->changeint
;
199 cd
->iochangeint
->io_Command
= TD_ADDCHANGEINT
;
200 SendIO((struct IORequest
*)cd
->iochangeint
);
203 cd
->scsireq
->io_Command
= CMD_CLEAR
;
204 DoIO ((struct IORequest
*) cd
->scsireq
);
206 cd
->t_changeint
= -1;
207 cd
->t_changeint2
= -2;
209 /* The LUN is the 2nd digit of the SCSI id number: */
210 cd
->lun
= (p_scsi_id
/ 10) % 10;
212 /* 'tick' is incremented every time a sector is accessed. */
217 if (CDROMERR_OK
!= err
)
229 unsigned char *p_buf
,
231 unsigned char *p_command
,
236 p_cd
->scsireq
->io_Length
= sizeof (struct SCSICmd
);
237 p_cd
->scsireq
->io_Data
= (APTR
) &p_cd
->cmd
;
238 p_cd
->scsireq
->io_Command
= HD_SCSICMD
;
240 p_cd
->cmd
.scsi_Data
= (UWORD
*) p_buf
;
241 p_cd
->cmd
.scsi_Length
= p_buf_length
;
242 p_cd
->cmd
.scsi_Flags
= SCSIF_AUTOSENSE
| p_direction
;
243 p_cd
->cmd
.scsi_SenseData
= (UBYTE
*) p_cd
->sense
;
244 p_cd
->cmd
.scsi_SenseLength
= 20;
245 p_cd
->cmd
.scsi_SenseActual
= 0;
246 p_cd
->cmd
.scsi_Command
= (UBYTE
*) p_command
;
247 p_cd
->cmd
.scsi_CmdLength
= p_length
;
249 p_command
[1] |= p_cd
->lun
<< 5;
251 if (0 != DoIO((struct IORequest
*) p_cd
->scsireq
) ||
252 0 != p_cd
->cmd
.scsi_Status
)
254 Clear_Sector_Buffers(p_cd
);
264 unsigned char *p_buf
,
268 int p_number_of_sectors
271 p_cd
->scsireq
->io_Length
= 2048 * p_number_of_sectors
;
272 p_cd
->scsireq
->io_Data
= (APTR
) p_buf
;
273 p_cd
->scsireq
->io_Offset
= (ULONG
) p_sector
<< 11;
274 p_cd
->scsireq
->io_Actual
= (ULONG
) p_sector
>> 21;
275 p_cd
->scsireq
->io_Command
= p_cd
->scsireq
->io_Actual
? TD_READ64
: CMD_READ
;
277 D(bug("[CDVDFS]\tAccessing sectors %ld:%ld\n", (long)p_sector
, (long)p_number_of_sectors
));
279 if (0 != DoIO((struct IORequest
*) p_cd
->scsireq
))
281 D(bug("[CDVDFS]\tTransfer failed: %ld\n", (long)p_cd
->scsireq
->io_Error
));
282 Clear_Sector_Buffers(p_cd
);
286 D(bug("[CDVDFS]\tTransfer successful.\n"));
291 * USAGE NOTE >> VERY IMPORTANT <<
292 * this procedure delivers you buffer that is 'valid' until the next 16-sector-boundary.
293 * if you want to read from sec 14 till 34, then you have to do 3 calls (14-16, 16-32, 32-34)
295 int Read_Chunk(CDROM
*p_cd
, long p_sector
)
297 struct CDVDBase
*global
= p_cd
->global
;
305 D(bug("[CDVDFS]\tClient requested sector %ld\n", p_sector
));
307 for (i
=0; i
<p_cd
->buffers_cnt
; i
++)
309 if ((p_sector
& ~0xf) != p_cd
->current_sectors
[i
])
315 D(bug("[CDVDFS]\tSector already cached\n"));
316 p_cd
->buffer
= p_cd
->buffers
[i
] + ((p_sector
& 0xf) << 11);
319 * try most frequently used
321 p_cd
->last_used
[i
] += 2;
322 for (i
=0; i
<p_cd
->buffers_cnt
; i
++)
324 if (p_cd
->last_used
[i
] > 0)
325 p_cd
->last_used
[i
] -= 1;
332 * find an empty buffer position:
334 for (loc
=0; loc
<p_cd
->buffers_cnt
; loc
++)
335 if (p_cd
->current_sectors
[loc
] == -1)
339 * no free buffer position; remove the buffer that is unused
340 * for the longest time
342 if (loc
==p_cd
->buffers_cnt
)
344 uint32_t oldest_tick
= UINT_MAX
;
347 for (loc
=0, i
=0; i
<p_cd
->buffers_cnt
; i
++)
349 tick
= p_cd
->last_used
[i
];
350 if (tick
< oldest_tick
)
351 loc
= i
, oldest_tick
= tick
;
356 * read **16** sectors
357 * NOTE: all DVD discs require chunk size to be at least n*16 sectors
358 * most of the CDs have enough padding (18 sectors) at the end
361 start
= p_sector
& ~0xf;
363 if (global
->g_volume
!= NULL
)
364 vol_size
= Volume_Size(global
->g_volume
);
367 if (vol_size
!= 0 && vol_size
- start
< count
)
368 count
= vol_size
- start
;
370 Read_From_Drive(p_cd
, p_cd
->buffers
[loc
], SCSI_BUFSIZE
, start
, count
);
374 p_cd
->current_sectors
[loc
] = p_sector
& ~0xf;
375 p_cd
->buffer
= p_cd
->buffers
[loc
] + ((p_sector
& 0xf) << 11);
376 p_cd
->last_used
[loc
] = 1000;
382 int Test_Unit_Ready(CDROM
*p_cd
)
384 p_cd
->scsireq
->io_Command
= TD_CHANGENUM
;
386 if (0 != DoIO ((struct IORequest
*) p_cd
->scsireq
))
389 p_cd
->t_changeint
= p_cd
->scsireq
->io_Actual
;
391 p_cd
->scsireq
->io_Command
= TD_CHANGESTATE
;
392 if ((0 != DoIO ((struct IORequest
*) p_cd
->scsireq
)) ||
393 (0 != p_cd
->scsireq
->io_Actual
))
406 uint8_t cmd
[6] = { };
407 unsigned char mode
[12] = { };
415 mode
[9] = p_block_length
>> 16;
416 mode
[10] = (p_block_length
>> 8) & 0xff;
417 mode
[11] = p_block_length
& 0xff;
419 CopyMem(mode
, p_cd
->buffer_io
, sizeof (mode
));
420 return Do_SCSI_Command(p_cd
, p_cd
->buffer_io
, sizeof(mode
), cmd
, 6, SCSIF_WRITE
);
423 int Inquire (CDROM
*p_cd
, t_inquiry_data
*p_data
)
425 uint8_t cmd
[6] = { };
429 if (!Do_SCSI_Command(p_cd
,p_cd
->buffer_io
,96,cmd
,6,SCSIF_READ
))
432 CopyMem(p_cd
->buffer_io
, p_data
, sizeof (*p_data
));
440 t_toc_header
*p_toc_header
443 uint8_t cmd
[10] = { };
444 uint32_t toc_len
= 0;
445 uint8_t *buf
= p_cd
->buffer_io
;
453 if (0 == Do_SCSI_Command(p_cd
, buf
, 4, cmd
, 10, SCSIF_READ
))
457 * toc len = len field + field contents
458 * Some drives don't return the full TOC length when the buffer is too
459 * small for the whole TOC: in this case, calculate it based on the
462 toc_len
= 2 + ((buf
[0] << 8) | (buf
[1]));
464 toc_len
= 4 + (buf
[3] - buf
[2] + 2) * 8;
467 * make sure it never happens (shouldn't)
469 if (toc_len
> SCSI_BUFSIZE
)
475 cmd
[7] = toc_len
>> 8;
476 cmd
[8] = toc_len
& 0xff;
477 if (0 == Do_SCSI_Command(p_cd
, buf
, toc_len
, cmd
, 10, SCSIF_READ
))
481 * that's a bit stupid (4 bytes and CopyMem) but still..
483 CopyMem(buf
, p_toc_header
, sizeof (*p_toc_header
));
484 return (t_toc_data
*) (buf
+ 4);
487 int Has_Audio_Tracks(CDROM
*p_cd
)
493 toc
= Read_TOC (p_cd
, &hdr
);
498 * calc num TOC entries
499 * last entry is usually LEADOUT (0xAA)
501 len
= hdr
.length
>> 3;
504 * traverse all tracks, check for audio?
506 for (i
=0; i
<len
; i
++)
508 if ((99 >= toc
[i
].track_number
) &&
509 (0 == (toc
[i
].flags
& 4)))
510 return toc
[i
].track_number
;
516 * Create a buffer containing the start addresses of all data tracks
520 * number of tracks or -1 on error.
523 int Data_Tracks(CDROM
*p_cd
, uint32_t** p_buf
)
533 toc
= Read_TOC(p_cd
, &hdr
);
538 * calc TOC entries count
540 len
= hdr
.length
>> 3;
543 * count number of data tracks:
545 for (i
=0; i
<len
; i
++)
547 if ((99 >= toc
[i
].track_number
) &&
548 (0 != (toc
[i
].flags
& 4)))
556 * allocate memory for output buffer:
558 *p_buf
= (uint32_t*) AllocVec (cnt
* sizeof (uint32_t*), MEMF_PUBLIC
);
563 * fill output buffer:
565 for (i
=0, j
=0; i
<len
; i
++)
567 if ((99 >= toc
[i
].track_number
) &&
568 (0 != (toc
[i
].flags
& 4)))
569 (*p_buf
)[j
++] = toc
[i
].address
;
575 inline void block2msf (uint32_t blk
, unsigned char *msf
)
577 blk
= (blk
+150) & 0xffffff;
578 msf
[0] = blk
/ 4500; /* 4500 = 60 seconds * 75 frames */
584 int Start_Play_Audio(CDROM
*p_cd
)
586 uint8_t cmd
[10] = { };
587 uint32_t start
= 0xffffffff,end
;
597 toc
= Read_TOC (p_cd
, &hdr
);
604 len
= hdr
.length
>> 3;
607 * find beginning of audio track
609 for (i
=0; i
<len
; i
++)
611 if ((99 >= toc
[i
].track_number
) &&
612 (0 == (toc
[i
].flags
& 4)))
614 start
=toc
[i
].address
;
622 if (0xffffffff == start
)
626 * find end of audio track
630 if (((99 < toc
[i
].track_number
) && (toc
[i
].track_number
> 99)) ||
631 (0 != (toc
[i
].flags
& 4)))
637 * fill up request and send
639 block2msf(start
, &cmd
[3]);
640 block2msf(end
-1, &cmd
[6]);
642 return Do_SCSI_Command(p_cd
, 0, 0, cmd
, 10, SCSIF_READ
);
645 int Stop_Play_Audio(CDROM
*p_cd
)
647 uint8_t cmd
[6] = { };
649 return Do_SCSI_Command(p_cd
, 0, 0, cmd
, 6, SCSIF_READ
);
652 void Cleanup_CDROM (CDROM
*p_cd
)
654 if (p_cd
->iochangeint
) {
655 p_cd
->iochangeint
->io_Length
= sizeof(struct Interrupt
);
656 p_cd
->iochangeint
->io_Data
= &p_cd
->changeint
;
657 p_cd
->iochangeint
->io_Command
= TD_REMCHANGEINT
;
658 DoIO((struct IORequest
*)p_cd
->iochangeint
);
659 FreeVec(p_cd
->iochangeint
);
661 if (p_cd
->device_open
)
662 CloseDevice ((struct IORequest
*) p_cd
->scsireq
);
664 DeleteIORequest((struct IORequest
*)p_cd
->scsireq
);
666 DeleteMsgPort (p_cd
->port
);
668 FreeVec (p_cd
->last_used
);
669 if (p_cd
->current_sectors
)
670 FreeVec (p_cd
->current_sectors
);
672 FreeVec (p_cd
->buffers
);
674 FreeVec (p_cd
->buffer_io
);
675 if (p_cd
->buffer_data
)
676 FreeVec (p_cd
->buffer_data
);
680 void Clear_Sector_Buffers (CDROM
*p_cd
)
684 for (i
=0; i
<p_cd
->buffers_cnt
; i
++)
685 p_cd
->current_sectors
[i
] = -1;
688 /* Finds offset of last session. (Not supported by all CDROM drives)
690 * Returns: - FALSE if there is no special SCSI command to determine the
691 * offset of the last session.
692 * - TRUE if the offset of the last session has been determined.
695 int Find_Last_Session(CDROM
*p_cd
, uint32_t *p_result
)
697 uint8_t cmd
[10] = { };
698 uint8_t *data
= p_cd
->buffer_io
;
704 * first: READTOC IS MANDATORY
705 * drives not conforming to MMC2 died in 1995.
710 * Ask the scsi device for the length of this TOC
714 if (!Do_SCSI_Command(p_cd
, data
, 12, cmd
, sizeof(cmd
), SCSIF_READ
))
718 * check if we are dealing with a DATA track here.
719 * nobody would like to spend an hour trying to get his mixed mode cd read
721 D(bug("[CDVDFS]\tFirst track in last session has type %lx\n", data
[5]));
722 if ((data
[5] & 0xfc) != 0x14)
724 D(bug("[CDVDFS]\tThis track is not a DATA track. Will default to track 1.\n"));
727 * this indeed sets the address of first track in first session, but we have no idea if this really is a data track.
728 * we don't care anyways. it will be detected by higher layer
734 * the ReadTOC has MSF field set to 0 so we treat obtained values as logical block address
737 *p_result
= (data
[8] << 24) | (data
[9] << 16) | (data
[10] << 8) | (data
[11]);