1 /* --------------------------------------------------------------------------
2 
3    MusicBrainz -- The Internet music metadatabase
4 
5    Copyright (C) 2000 Robert Kaye
6    Copyright (C) 1999 Marc E E van Woerkom
7    Copyright (C) 1999 Stephen van Egmond
8 
9    This library is free software; you can redistribute it and/or
10    modify it under the terms of the GNU Lesser General Public
11    License as published by the Free Software Foundation; either
12    version 2.1 of the License, or (at your option) any later version.
13 
14    This library is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    Lesser General Public License for more details.
18 
19    You should have received a copy of the GNU Lesser General Public
20    License along with this library; if not, write to the Free Software
21    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 
23      $Id: mb_beos.cpp,v 1.3 2001/07/06 21:32:13 robert Exp $
24 
25 ----------------------------------------------------------------------------*/
26 
27 #include "mb.h"
28 #include "diskid.h"
29 #include "config.h"
30 
31 // BeOS layer includes
32 #include <Path.h>
33 #include <Directory.h>
34 #include <String.h>
35 #include <scsi.h>
36 #include <Roster.h>
37 
38 // POSIX layer includes
39 #include <string.h>
40 #include <stdio.h>
41 #include <unistd.h>
42 #include <stdlib.h>
43 #include <assert.h>
44 
45 
46 // forward declarations
47 static void FindCDPlayerDevice();
48 static uint32 msf_to_lba(uint8 m, uint8 s, uint8 f);
49 
50 // global variables
51 BString gCDPlayerDeviceName;
52 int gCDPlayerDevice;
53 
54 // initializer -- call before using above globals
gConfigureGlobals()55 status_t gConfigureGlobals() {
56     gCDPlayerDevice = 0;
57 
58     FindCDPlayerDevice();
59     if (gCDPlayerDevice == 0) {
60         return B_DEV_BAD_DRIVE_NUM;
61     }
62 
63     return B_NO_ERROR;
64 }
65 
ReadTOC(char * device,MUSICBRAINZ_CDINFO & cdinfo)66 bool DiskId::ReadTOC(char *device,
67                      MUSICBRAINZ_CDINFO& cdinfo) {
68     // how does it get the device?
69     status_t rc = gConfigureGlobals();
70     if (rc != B_NO_ERROR) {
71         char err[255];
72         sprintf(err, "Error while accessing the CD drive: %s.",
73                 strerror(rc));
74         ReportError(err);
75 
76         return false;
77     }
78 
79     scsi_toc toc;
80 
81     rc = ioctl(gCDPlayerDevice, B_SCSI_GET_TOC, &toc);
82 
83     if (rc != B_NO_ERROR) {
84         char err[255];
85         sprintf(err, "Error while accessing %s: %s.",
86                 gCDPlayerDeviceName.String(), strerror(rc));
87         ReportError(err);
88 
89         return false;
90     }
91 
92     /*
93 
94       typedef struct {
95           byte FirstTrack;         // The first track on CD : normally 1
96           byte LastTrack;          // The last track on CD: max number 99
97 
98           dword FrameOffset[100];  // Track 2 is TrackFrameOffset[2] etc.
99 
100           // Leadout Track will be TrackFrameOffset[0]
101 
102       } MUSICBRAINZ_CDINFO, *PMUSICBRAINZ_CDINFO;
103 
104     */
105 
106 
107     /*
108 
109       SCSI toc format
110 
111         http://www.symbios.com/t10
112 
113         All multibyte values big-endian
114 
115         uint16 data_length;  // of following data, not including these 2 bytes
116         uint8  first_track;
117         uint8  last_track;
118 
119         struct {
120             uint8 reserved;
121             uint8 flag_bits; // ADR and CONTROL, whatever
122             uint8 track_number;
123             uint8 reserved2;
124             uint32 logical_block_address;
125         } [n];
126 
127         // where n fills out the data length
128     */
129 
130 
131     uint16 data_length = * ((uint16*)toc.toc_data);
132     data_length = B_BENDIAN_TO_HOST_INT16(data_length);
133     data_length += 2; // to include the length itself
134 
135     cdinfo.FirstTrack = toc.toc_data[2];
136     cdinfo.LastTrack = toc.toc_data[3];
137     assert(cdinfo.FirstTrack >= 1 && cdinfo.FirstTrack<=99);
138     assert(cdinfo.LastTrack >= 1 && cdinfo.LastTrack<=99);
139 
140     int indexer = 4;
141     while (indexer < data_length) {
142         indexer+=2;
143         int track_number = toc.toc_data[indexer];
144         indexer+=2;
145         uint32 lba = msf_to_lba(toc.toc_data[indexer+1],toc.toc_data[indexer+2],toc.toc_data[indexer+3]);
146 
147         indexer+=4;
148 
149         assert(track_number == 0xaa || (track_number>=1 && track_number <= cdinfo.LastTrack));
150         if (track_number == 0xaa)
151             track_number = 0;
152 
153         cdinfo.FrameOffset[track_number] = lba + 150;
154     }
155 
156     return true;
157 }
158 
159 
try_dir(const char * directory)160 static bool try_dir(const char *directory)
161 {
162     BDirectory dir;
163     dir.SetTo(directory);
164     if(dir.InitCheck() != B_NO_ERROR) {
165         return false;
166     }
167     dir.Rewind();
168     BEntry entry;
169     while(dir.GetNextEntry(&entry) >= 0) {
170         BPath path;
171         const char *name;
172         entry_ref e;
173 
174         if(entry.GetPath(&path) != B_NO_ERROR)
175             continue;
176         name = path.Path();
177 
178 
179         if(entry.GetRef(&e) != B_NO_ERROR)
180             continue;
181 
182         if(entry.IsDirectory()) {
183             if(strcmp(e.name, "floppy") == 0)
184                 continue; // ignore floppy (it is not silent)
185             if (try_dir(name))
186                 return true;
187         }
188         else {
189             int devfd;
190             device_geometry g;
191 
192             if(strcmp(e.name, "raw") != 0)
193                 continue; // ignore partitions
194 
195             devfd = open(name, O_RDONLY);
196             if(devfd < 0)
197                 continue;
198 
199             if(ioctl(devfd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0) {
200                 if(g.device_type == B_CD)
201                     {
202                         gCDPlayerDevice = devfd;
203                         gCDPlayerDeviceName = name;
204                         return true;
205                     }
206             }
207             close(devfd);
208         }
209     }
210 
211     return false;
212 }
213 
214 
FindCDPlayerDevice()215 static void FindCDPlayerDevice()
216 {
217     try_dir("/dev/disk");
218 }
219 
220 
msf_to_lba(uint8 m,uint8 s,uint8 f)221 static uint32 msf_to_lba(uint8 m, uint8 s, uint8 f)
222 {
223     return (((m * 60) + s) * 75 + f) - 150;
224 }
225