File: common_interface.c

package info (click to toggle)
cdparanoia 3.10.2%2Bdebian-11
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd, stretch
  • size: 1,904 kB
  • sloc: ansic: 8,026; sh: 2,642; makefile: 61
file content (255 lines) | stat: -rw-r--r-- 6,972 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
/******************************************************************
 * CopyPolicy: GNU Lesser Public License 2.1 applies
 * Copyright (C) 1998-2008 Monty monty@xiph.org
 *
 * CDROM communication common to all interface methods is done here 
 * (mostly ioctl stuff, but not ioctls specific to the 'cooked'
 * interface) 
 *
 ******************************************************************/

#include <math.h>
#include "low_interface.h"
#include "utils.h"
#include "smallft.h"

#if defined(__linux__)
#include <linux/hdreg.h>
#endif

/* Test for presence of a cdrom by pinging with the 'CDROMVOLREAD' ioctl() */
/* Also test using CDROM_GET_CAPABILITY (if available) as some newer DVDROMs will
   reject CDROMVOLREAD ioctl for god-knows-what reason */
int ioctl_ping_cdrom(int fd){
#if defined(__linux__)
  struct cdrom_volctrl volctl;
  if (ioctl(fd, CDROMVOLREAD, &volctl) &&
      ioctl(fd, CDROM_GET_CAPABILITY, NULL)<0)
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
  struct ioc_vol volctl;
  if (ioctl(fd, CDIOCGETVOL, &volctl))
#endif
    return(1); /* failure */

  return(0);
  /* success! */
}


#if defined(__linux__)
/* Use the ioctl thingy above ping the cdrom; this will get model info */
char *atapi_drive_info(int fd){
  /* Work around the fact that the struct grew without warning in
     2.1/2.0.34 */
  
  struct hd_driveid *id=malloc(512); /* the size in 2.0.34 */
  char *ret;

  if (!(ioctl(fd, HDIO_GET_IDENTITY, id))) {

    if(id->model==0 || id->model[0]==0)
      ret=copystring("Generic Unidentifiable ATAPI CDROM");
    else
      ret=copystring(id->model);
  }else
    ret=copystring("Generic Unidentifiable CDROM");

  free(id);
  return(ret);
}
#endif

int data_bigendianp(cdrom_drive *d){
  float lsb_votes=0;
  float msb_votes=0;
  int i,checked;
  int endiancache=d->bigendianp;
  float *a=calloc(1024,sizeof(float));
  float *b=calloc(1024,sizeof(float));
  long readsectors=5;
  int16_t *buff=malloc(readsectors*CD_FRAMESIZE_RAW);

  /* look at the starts of the audio tracks */
  /* if real silence, tool in until some static is found */

  /* Force no swap for now */
  d->bigendianp=-1;
  
  cdmessage(d,"\nAttempting to determine drive endianness from data...");
  d->enable_cdda(d,1);
  for(i=0,checked=0;i<d->tracks;i++){
    float lsb_energy=0;
    float msb_energy=0;
    if(cdda_track_audiop(d,i+1)==1){
      long firstsector=cdda_track_firstsector(d,i+1);
      long lastsector=cdda_track_lastsector(d,i+1);
      int zeroflag=-1;
      long beginsec=0;
      
      /* find a block with nonzero data */
      
      while(firstsector+readsectors<=lastsector){
	int j;
	
	if(d->read_audio(d,buff,firstsector,readsectors)>0){
	  
	  /* Avoid scanning through jitter at the edges */
	  for(beginsec=0;beginsec<readsectors;beginsec++){
	    int offset=beginsec*CD_FRAMESIZE_RAW/2;
	    /* Search *half* */
	    for(j=460;j<128+460;j++)
	      if(buff[offset+j]!=0){
		zeroflag=0;
		break;
	      }
	    if(!zeroflag)break;
	  }
	  if(!zeroflag)break;
	  firstsector+=readsectors;
	}else{
	  d->enable_cdda(d,0);
	  free(a);
	  free(b);
	  free(buff);
	  return(-1);
	}
      }

      beginsec*=CD_FRAMESIZE_RAW/2;
      
      /* un-interleave for an fft */
      if(!zeroflag){
	int j;
	
	for(j=0;j<128;j++)a[j]=le16_to_cpu(buff[j*2+beginsec+460]);
	for(j=0;j<128;j++)b[j]=le16_to_cpu(buff[j*2+beginsec+461]);
	fft_forward(128,a,NULL,NULL);
	fft_forward(128,b,NULL,NULL);
	for(j=0;j<128;j++)lsb_energy+=fabs(a[j])+fabs(b[j]);
	
	for(j=0;j<128;j++)a[j]=be16_to_cpu(buff[j*2+beginsec+460]);
	for(j=0;j<128;j++)b[j]=be16_to_cpu(buff[j*2+beginsec+461]);
	fft_forward(128,a,NULL,NULL);
	fft_forward(128,b,NULL,NULL);
	for(j=0;j<128;j++)msb_energy+=fabs(a[j])+fabs(b[j]);
      }
    }
    if(lsb_energy<msb_energy){
      lsb_votes+=msb_energy/lsb_energy;
      checked++;
    }else
      if(lsb_energy>msb_energy){
	msb_votes+=lsb_energy/msb_energy;
	checked++;
      }

    if(checked==5 && (lsb_votes==0 || msb_votes==0))break;
    cdmessage(d,".");
  }

  free(buff);
  free(a);
  free(b);
  d->bigendianp=endiancache;
  d->enable_cdda(d,0);

  /* How did we vote?  Be potentially noisy */
  if(lsb_votes>msb_votes){
    char buffer[256];
    cdmessage(d,"\n\tData appears to be coming back little endian.\n");
    sprintf(buffer,"\tcertainty: %d%%\n",(int)
	    (100.*lsb_votes/(lsb_votes+msb_votes)+.5));
    cdmessage(d,buffer);
    return(0);
  }else{
    if(msb_votes>lsb_votes){
      char buffer[256];
      cdmessage(d,"\n\tData appears to be coming back big endian.\n");
      sprintf(buffer,"\tcertainty: %d%%\n",(int)
	      (100.*msb_votes/(lsb_votes+msb_votes)+.5));
      cdmessage(d,buffer);
      return(1);
    }

    cdmessage(d,"\n\tCannot determine CDROM drive endianness.\n");
    return(bigendianp());
    return(-1);
  }
}

/************************************************************************/
/* Here we fix up a couple of things that will never happen.  yeah,
   right.  The multisession stuff is from Hannu's code; it assumes it
   knows the leadout/leadin size. */

int FixupTOC(cdrom_drive *d,int tracks){
#if defined(__linux__)
  struct cdrom_multisession ms_str;
#endif
  int j;
  
  /* First off, make sure the 'starting sector' is >=0 */
  
  for(j=0;j<tracks;j++){
    if(d->disc_toc[j].dwStartSector<0){
      cdmessage(d,"\n\tTOC entry claims a negative start offset: massaging"
		".\n");
      d->disc_toc[j].dwStartSector=0;
    }
    if(j<tracks-1 && d->disc_toc[j].dwStartSector>
       d->disc_toc[j+1].dwStartSector){
      cdmessage(d,"\n\tTOC entry claims an overly large start offset: massaging"
		".\n");
      d->disc_toc[j].dwStartSector=0;
    }

  }
  /* Make sure the listed 'starting sectors' are actually increasing.
     Flag things that are blatant/stupid/wrong */
  {
    long last=d->disc_toc[0].dwStartSector;
    for(j=1;j<tracks;j++){
      if(d->disc_toc[j].dwStartSector<last){
	cdmessage(d,"\n\tTOC entries claim non-increasing offsets: massaging"
		  ".\n");
	 d->disc_toc[j].dwStartSector=last;
	
      }
      last=d->disc_toc[j].dwStartSector;
    }
  }

  /* For a scsi device, the ioctl must go to the specialized SCSI
     CDROM device, not the generic device. */

  /* XXX */
#if defined(__linux__)
  if (d->ioctl_fd != -1) {
    int result;

    ms_str.addr_format = CDROM_LBA;
    result = ioctl(d->ioctl_fd, CDROMMULTISESSION, &ms_str);
    if (result == -1) return -1;

    if (ms_str.addr.lba > 100) {

      /* This is an odd little piece of code --Monty */

      /* believe the multisession offset :-) */
      /* adjust end of last audio track to be in the first session */
      for (j = tracks-1; j >= 0; j--) {
	if (j > 0 && !IS_AUDIO(d,j) && IS_AUDIO(d,j-1)) {
	  if ((d->disc_toc[j].dwStartSector > ms_str.addr.lba - 11400) &&
	      (ms_str.addr.lba - 11400 > d->disc_toc[j-1].dwStartSector))
	    d->disc_toc[j].dwStartSector = ms_str.addr.lba - 11400;
	  break;
	}
      }
      return 1;
    }
  }
#endif
  return 0;
}