2
$Id: common_interface.c,v 1.13 2005/02/05 12:37:35 rocky Exp $
4
Copyright (C) 2004, 2005 Rocky Bernstein <rocky@panix.com>
5
Copyright (C) 1998, 2002 Monty monty@xiph.org
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or
10
(at your option) any later version.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
/******************************************************************
23
* CDROM communication common to all interface methods is done here
24
* (mostly ioctl stuff, but not ioctls specific to the 'cooked'
27
******************************************************************/
30
#include "common_interface.h"
34
/* Variables to hold debugger-helping enumerations */
35
enum paranoia_cdda_enums;
36
enum paranoia_jitter_enums;
38
/*! Determine Endian-ness of the CD-drive based on reading data from
39
it. Some drives return audio data Big Endian while some (most)
40
return data Little Endian. Drives known to return data bigendian are
41
SCSI drives from Kodak, Ricoh, HP, Philips, Plasmon, Grundig
42
CDR100IPW, and Mitsumi CD-R. ATAPI and MMC drives are little endian.
44
rocky: As someone who didn't write the code, I have to say this is
45
nothing less than brilliant. An FFT is done both ways and the the
46
transform is looked at to see which has data in the FFT (or audible)
47
portion. (Or so that's how I understand it.)
49
@return 1 if big-endian, 0 if little-endian, -1 if we couldn't
50
figure things out or some error.
53
data_bigendianp(cdrom_drive_t *d)
58
int endiancache=d->bigendianp;
59
float *a=calloc(1024,sizeof(float));
60
float *b=calloc(1024,sizeof(float));
62
int16_t *buff=malloc(readsectors*CDIO_CD_FRAMESIZE_RAW);
63
memset(buff, 0, readsectors*CDIO_CD_FRAMESIZE_RAW);
65
/* look at the starts of the audio tracks */
66
/* if real silence, tool in until some static is found */
68
/* Force no swap for now */
71
cdmessage(d,"\nAttempting to determine drive endianness from data...");
73
for(i=0,checked=0;i<d->tracks;i++){
76
if(cdda_track_audiop(d,i+1)==1){
77
long firstsector=cdda_track_firstsector(d,i+1);
78
long lastsector=cdda_track_lastsector(d,i+1);
82
/* find a block with nonzero data */
84
while(firstsector+readsectors<=lastsector){
87
if(d->read_audio(d,buff,firstsector,readsectors)>0){
89
/* Avoid scanning through jitter at the edges */
90
for(beginsec=0;beginsec<readsectors;beginsec++){
91
int offset=beginsec*CDIO_CD_FRAMESIZE_RAW/2;
93
for(j=460;j<128+460;j++)
94
if(buff[offset+j]!=0){
101
firstsector+=readsectors;
111
beginsec*=CDIO_CD_FRAMESIZE_RAW/2;
113
/* un-interleave for an FFT */
118
a[j] = le16_to_cpu(buff[j*2+beginsec+460]);
120
b[j] = le16_to_cpu(buff[j*2+beginsec+461]);
122
fft_forward(128,a,NULL,NULL);
123
fft_forward(128,b,NULL,NULL);
126
lsb_energy+=fabs(a[j])+fabs(b[j]);
129
a[j] = be16_to_cpu(buff[j*2+beginsec+460]);
132
b[j] = be16_to_cpu(buff[j*2+beginsec+461]);
134
fft_forward(128,a,NULL,NULL);
135
fft_forward(128,b,NULL,NULL);
138
msb_energy+=fabs(a[j])+fabs(b[j]);
141
if(lsb_energy<msb_energy){
142
lsb_votes+=msb_energy/lsb_energy;
145
if(lsb_energy>msb_energy){
146
msb_votes+=lsb_energy/msb_energy;
150
if(checked==5 && (lsb_votes==0 || msb_votes==0))break;
157
d->bigendianp=endiancache;
160
/* How did we vote? Be potentially noisy */
161
if (lsb_votes>msb_votes) {
163
cdmessage(d,"\n\tData appears to be coming back Little Endian.\n");
164
sprintf(buffer,"\tcertainty: %d%%\n",(int)
165
(100.*lsb_votes/(lsb_votes+msb_votes)+.5));
169
if(msb_votes>lsb_votes){
171
cdmessage(d,"\n\tData appears to be coming back Big Endian.\n");
172
sprintf(buffer,"\tcertainty: %d%%\n",(int)
173
(100.*msb_votes/(lsb_votes+msb_votes)+.5));
178
cdmessage(d,"\n\tCannot determine CDROM drive endianness.\n");
179
return(bigendianp());
184
/************************************************************************/
186
/*! Here we fix up a couple of things that will never happen. yeah,
189
rocky OMITTED FOR NOW:
190
The multisession stuff is from Hannu's code; it assumes it knows
191
the leadout/leadin size.
193
@return -1 if we can't get multisession info, 0 if there is one
194
session only or the multi-session LBA is less than or 100 (don't
195
ask me why -- I don't know), and 1 if the multi-session lba is
199
FixupTOC(cdrom_drive_t *d, track_t i_tracks)
203
/* First off, make sure the 'starting sector' is >=0 */
205
for( j=0; j<i_tracks; j++){
206
if (d->disc_toc[j].dwStartSector<0 ) {
207
cdmessage(d,"\n\tTOC entry claims a negative start offset: massaging"
209
d->disc_toc[j].dwStartSector=0;
211
if( j<i_tracks-1 && d->disc_toc[j].dwStartSector>
212
d->disc_toc[j+1].dwStartSector ) {
213
cdmessage(d,"\n\tTOC entry claims an overly large start offset: massaging"
215
d->disc_toc[j].dwStartSector=0;
219
/* Make sure the listed 'starting sectors' are actually increasing.
220
Flag things that are blatant/stupid/wrong */
222
lsn_t last=d->disc_toc[0].dwStartSector;
223
for ( j=1; j<i_tracks; j++){
224
if ( d->disc_toc[j].dwStartSector<last ) {
225
cdmessage(d,"\n\tTOC entries claim non-increasing offsets: massaging"
227
d->disc_toc[j].dwStartSector=last;
230
last=d->disc_toc[j].dwStartSector;
235
/* For a scsi device, the ioctl must go to the specialized SCSI
236
CDROM device, not the generic device. */
238
if (d->ioctl_fd != -1) {
239
struct cdrom_multisession ms_str;
242
ms_str.addr_format = CDROM_LBA;
243
result = ioctl(d->ioctl_fd, CDROMMULTISESSION, &ms_str);
244
if (result == -1) return -1;
246
if (ms_str.addr.lba > 100) {
248
/* This is an odd little piece of code --Monty */
250
/* believe the multisession offset :-) */
251
/* adjust end of last audio track to be in the first session */
252
for (j = i_tracks-1; j >= 0; j--) {
253
if (j > 0 && !IS_AUDIO(d,j) && IS_AUDIO(d,j-1)) {
254
if ((d->disc_toc[j].dwStartSector > ms_str.addr.lba - 11400) &&
255
(ms_str.addr.lba - 11400 > d->disc_toc[j-1].dwStartSector))
256
d->disc_toc[j].dwStartSector = ms_str.addr.lba - 11400;