1
/******************************************************************
2
* CopyPolicy: GNU Public License 2 applies
3
* Copyright (C) 1998 Monty xiphmont@mit.edu
5
* CDROM communication common to all interface methods is done here
6
* (mostly ioctl stuff, but not ioctls specific to the 'cooked'
9
******************************************************************/
12
#include "low_interface.h"
16
#include <linux/hdreg.h>
18
/* Test for presence of a cdrom by pinging with the 'CDROMVOLREAD' ioctl() */
19
int ioctl_ping_cdrom(int fd){
20
struct cdrom_volctrl volctl;
21
if (ioctl(fd, CDROMVOLREAD, &volctl))
22
return(1); /* failure */
29
/* Use the ioctl thingy above ping the cdrom; this will get model info */
30
char *atapi_drive_info(int fd){
31
/* Work around the fact that the struct grew without warning in
34
struct hd_driveid *id=malloc(512); /* the size in 2.0.34 */
37
if (!(ioctl(fd, HDIO_GET_IDENTITY, id))) {
39
if(id->model==0 || id->model[0]==0)
40
ret=copystring("Generic Unidentifiable ATAPI CDROM");
42
ret=copystring(id->model);
44
ret=copystring("Generic Unidentifiable CDROM");
50
int data_bigendianp(cdrom_drive *d){
54
int endiancache=d->bigendianp;
55
float *a=calloc(1024,sizeof(float));
56
float *b=calloc(1024,sizeof(float));
58
int16_t *buff=malloc(readsectors*CD_FRAMESIZE_RAW);
60
/* look at the starts of the audio tracks */
61
/* if real silence, tool in until some static is found */
63
/* Force no swap for now */
66
cdmessage(d,"\nAttempting to determine drive endianness from data...");
68
for(i=0,checked=0;i<d->tracks;i++){
71
if(cdda_track_audiop(d,i+1)==1){
72
long firstsector=cdda_track_firstsector(d,i+1);
73
long lastsector=cdda_track_lastsector(d,i+1);
77
/* find a block with nonzero data */
79
while(firstsector+readsectors<=lastsector){
82
if(d->read_audio(d,buff,firstsector,readsectors)>0){
84
/* Avoid scanning through jitter at the edges */
85
for(beginsec=0;beginsec<readsectors;beginsec++){
86
int offset=beginsec*CD_FRAMESIZE_RAW/2;
88
for(j=460;j<128+460;j++)
89
if(buff[offset+j]!=0){
96
firstsector+=readsectors;
106
beginsec*=CD_FRAMESIZE_RAW/2;
108
/* un-interleave for an fft */
112
for(j=0;j<128;j++)a[j]=le16_to_cpu(buff[j*2+beginsec+460]);
113
for(j=0;j<128;j++)b[j]=le16_to_cpu(buff[j*2+beginsec+461]);
114
fft_forward(128,a,NULL,NULL);
115
fft_forward(128,b,NULL,NULL);
116
for(j=0;j<128;j++)lsb_energy+=fabs(a[j])+fabs(b[j]);
118
for(j=0;j<128;j++)a[j]=be16_to_cpu(buff[j*2+beginsec+460]);
119
for(j=0;j<128;j++)b[j]=be16_to_cpu(buff[j*2+beginsec+461]);
120
fft_forward(128,a,NULL,NULL);
121
fft_forward(128,b,NULL,NULL);
122
for(j=0;j<128;j++)msb_energy+=fabs(a[j])+fabs(b[j]);
125
if(lsb_energy<msb_energy){
126
lsb_votes+=msb_energy/lsb_energy;
129
if(lsb_energy>msb_energy){
130
msb_votes+=lsb_energy/msb_energy;
134
if(checked==5 && (lsb_votes==0 || msb_votes==0))break;
141
d->bigendianp=endiancache;
144
/* How did we vote? Be potentially noisy */
145
if(lsb_votes>msb_votes){
147
cdmessage(d,"\n\tData appears to be coming back little endian.\n");
148
sprintf(buffer,"\tcertainty: %d%%\n",(int)
149
(100.*lsb_votes/(lsb_votes+msb_votes)+.5));
153
if(msb_votes>lsb_votes){
155
cdmessage(d,"\n\tData appears to be coming back big endian.\n");
156
sprintf(buffer,"\tcertainty: %d%%\n",(int)
157
(100.*msb_votes/(lsb_votes+msb_votes)+.5));
162
cdmessage(d,"\n\tCannot determine CDROM drive endianness.\n");
163
return(bigendianp());
168
/************************************************************************/
169
/* Here we fix up a couple of things that will never happen. yeah,
170
right. The multisession stuff is from Hannu's code; it assumes it
171
knows the leasoud/leadin size. */
173
int FixupTOC(cdrom_drive *d,int tracks){
174
struct cdrom_multisession ms_str;
177
/* First off, make sure the 'starting sector' is >=0 */
179
for(j=0;j<tracks;j++){
180
if(d->disc_toc[j].dwStartSector<0){
181
cdmessage(d,"\n\tTOC entry claims a negative start offset: massaging"
183
d->disc_toc[j].dwStartSector=0;
185
if(j<tracks-1 && d->disc_toc[j].dwStartSector>
186
d->disc_toc[j+1].dwStartSector){
187
cdmessage(d,"\n\tTOC entry claims an overly large start offset: massaging"
189
d->disc_toc[j].dwStartSector=0;
193
/* Make sure the listed 'starting sectors' are actually increasing.
194
Flag things that are blatant/stupid/wrong */
196
long last=d->disc_toc[0].dwStartSector;
197
for(j=1;j<tracks;j++){
198
if(d->disc_toc[j].dwStartSector<last){
199
cdmessage(d,"\n\tTOC entries claim non-increasing offsets: massaging"
201
d->disc_toc[j].dwStartSector=last;
204
last=d->disc_toc[j].dwStartSector;
208
/* For a scsi device, the ioctl must go to the specialized SCSI
209
CDROM device, not the generic device. */
211
if (d->ioctl_fd != -1) {
214
ms_str.addr_format = CDROM_LBA;
215
result = ioctl(d->ioctl_fd, CDROMMULTISESSION, &ms_str);
216
if (result == -1) return -1;
218
if (ms_str.addr.lba > 100) {
220
/* This is an odd little piece of code --Monty */
222
/* believe the multisession offset :-) */
223
/* adjust end of last audio track to be in the first session */
224
for (j = tracks-1; j >= 0; j--) {
225
if (j > 0 && !IS_AUDIO(d,j) && IS_AUDIO(d,j-1)) {
226
if (d->disc_toc[j].dwStartSector > ms_str.addr.lba - 11400)
227
d->disc_toc[j].dwStartSector = ms_str.addr.lba - 11400;