1 /* libcda; BeOS component.
2 *
3 * Partly based on CDButton sample, by Pavel Cisler.
4 *
5 * Peter Wang <tjaden@users.sf.net>
6 */
7
8 #include <Entry.h>
9 #include <Directory.h>
10 #include <Path.h>
11 #include <errno.h>
12 #include <scsi.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include "libcda.h"
16
17
18 #define MID(x,y,z) MAX((x), MIN((y), (z)))
19
20
21 static int fd = -1;
22
23 static char _cd_error[256];
24 const char *cd_error = _cd_error;
25
26
copy_cd_error(void)27 static void copy_cd_error(void)
28 {
29 strncpy(_cd_error, strerror(errno), sizeof _cd_error);
30 _cd_error[sizeof _cd_error - 1] = 0;
31 }
32
33
search_cd_drive(const char * root)34 static int search_cd_drive(const char *root)
35 {
36 BDirectory dir;
37 BEntry entry;
38 BPath path;
39 int fd;
40 device_geometry geo;
41
42 dir.SetTo(root);
43 if (dir.InitCheck() != B_NO_ERROR)
44 return -1;
45
46 dir.Rewind();
47
48 while (dir.GetNextEntry(&entry) >= 0) {
49
50 if (entry.GetPath(&path) != B_NO_ERROR)
51 continue;
52
53 if (entry.IsDirectory()) {
54 if (strcmp(path.Leaf(), "floppy") == 0)
55 continue;
56
57 fd = search_cd_drive(path.Path());
58 if (fd >= 0)
59 return fd;
60 }
61 else if (strcmp(path.Leaf(), "raw") == 0) {
62
63 fd = open(path.Path(), O_RDONLY);
64 if (fd < 0)
65 continue;
66
67 if (ioctl(fd, B_GET_GEOMETRY, &geo, sizeof geo) >= 0)
68 if (geo.device_type == B_CD)
69 return fd;
70
71 close(fd);
72 }
73 }
74
75 return -1;
76 }
77
78
cd_init(void)79 int cd_init(void)
80 {
81 fd = search_cd_drive("/dev/disk");
82 if (fd < 0) {
83 copy_cd_error();
84 return -1;
85 }
86 else {
87 return 0;
88 }
89 }
90
91
cd_exit(void)92 void cd_exit(void)
93 {
94 if (fd >= 0) {
95 close(fd);
96 fd = -1;
97 }
98 }
99
100
101 /* prevents us from getting a stupid `media changed' error */
get_media_status(void)102 static void get_media_status(void)
103 {
104 status_t status;
105 ioctl(fd, B_GET_MEDIA_STATUS, &status, sizeof status);
106 }
107
108
play(int start,int end)109 static int play(int start, int end)
110 {
111 scsi_play_track p;
112 int first, last;
113
114 get_media_status();
115
116 cd_get_tracks(&first, &last);
117 if ((start > end) || (start < first) || (end > last)) {
118 strcpy(_cd_error, "Invalid track range");
119 return -1;
120 }
121
122 p.start_track = start;
123 p.start_index = 1;
124 p.end_track = end;
125 p.end_index = 1;
126
127 if (ioctl(fd, B_SCSI_PLAY_TRACK, &p) != B_NO_ERROR) {
128 copy_cd_error();
129 return -1;
130 }
131
132 return 0;
133 }
134
135
cd_play(int track)136 int cd_play(int track)
137 {
138 return play(track, track);
139 }
140
141
cd_play_range(int start,int end)142 int cd_play_range(int start, int end)
143 {
144 return play(start, end);
145 }
146
147
cd_play_from(int track)148 int cd_play_from(int track)
149 {
150 return play(track, 100);
151 }
152
153
cd_current_track(void)154 int cd_current_track(void)
155 {
156 scsi_position pos;
157
158 if ((ioctl(fd, B_SCSI_GET_POSITION, &pos) != B_NO_ERROR)
159 || (!pos.position[1]) || (pos.position[1] >= 0x13)
160 || ((pos.position[1] == 0x12) && (!pos.position[6])))
161 return 0;
162
163 return pos.position[6];
164 }
165
166
cd_pause(void)167 void cd_pause(void)
168 {
169 ioctl(fd, B_SCSI_PAUSE_AUDIO);
170 }
171
172
cd_resume(void)173 void cd_resume(void)
174 {
175 ioctl(fd, B_SCSI_RESUME_AUDIO);
176 }
177
178
cd_is_paused(void)179 int cd_is_paused(void)
180 {
181 scsi_position pos;
182
183 if (ioctl(fd, B_SCSI_GET_POSITION, &pos) != B_NO_ERROR)
184 return 0;
185
186 if ((!pos.position[1]) || (pos.position[1] >= 0x13)
187 || ((pos.position[1] == 0x12) && (!pos.position[6]))
188 || (pos.position[1] == 0x11))
189 return 0;
190
191 return 1;
192 }
193
194
cd_stop(void)195 void cd_stop(void)
196 {
197 ioctl(fd, B_SCSI_STOP_AUDIO);
198 }
199
200
cd_get_tracks(int * first,int * last)201 int cd_get_tracks(int *first, int *last)
202 {
203 scsi_toc toc;
204
205 get_media_status();
206
207 if (ioctl(fd, B_SCSI_GET_TOC, &toc) != B_NO_ERROR) {
208 copy_cd_error();
209 return -1;
210 }
211
212 if (first) *first = 1; /* I don't have the SCSI standard on me. */
213 if (last) *last = toc.toc_data[3];
214
215 return 0;
216 }
217
218
cd_is_audio(int track)219 int cd_is_audio(int track)
220 {
221 scsi_toc toc;
222 int first, last;
223
224 get_media_status();
225
226 if (ioctl(fd, B_SCSI_GET_TOC, &toc) != B_NO_ERROR) {
227 copy_cd_error();
228 return -1;
229 }
230
231 if (cd_get_tracks(&first, &last) < 0)
232 return -1;
233
234 if ((track < first) || (track > last)) {
235 strcpy(_cd_error, "Track out of range");
236 return -1;
237 }
238
239 /*
240 * I derived from a snippet from a mailing list archive somewhere.
241 * Don't ask me how it works :-)
242 */
243 return !(toc.toc_data[((track - toc.toc_data[2]) * 8) + 4 + 1] & 4);
244 }
245
246
cd_get_volume(int * c0,int * c1)247 void cd_get_volume(int *c0, int *c1)
248 {
249 scsi_volume vol;
250
251 get_media_status();
252
253 ioctl(fd, B_SCSI_GET_VOLUME, &vol, sizeof vol);
254 if (c0) *c0 = vol.port0_volume;
255 if (c1) *c1 = vol.port1_volume;
256 }
257
258
cd_set_volume(int c0,int c1)259 void cd_set_volume(int c0, int c1)
260 {
261 scsi_volume vol;
262
263 get_media_status();
264
265 vol.flags = B_SCSI_PORT0_VOLUME | B_SCSI_PORT1_VOLUME;
266 vol.port0_volume = MID(0, c0, 255);
267 vol.port1_volume = MID(0, c1, 255);
268
269 ioctl(fd, B_SCSI_SET_VOLUME, &vol, sizeof vol);
270 }
271
272
door_status(void)273 static int door_status(void)
274 {
275 status_t status;
276
277 if (ioctl(fd, B_GET_MEDIA_STATUS, &status, sizeof status) == B_NO_ERROR)
278 return -1;
279
280 return (status == B_DEV_DOOR_OPEN) ? 1 : 0;
281 }
282
283 #define door_open() (door_status() == 1)
284 #define door_closed() (door_status() == 0)
285
286
cd_eject(void)287 void cd_eject(void)
288 {
289 if (!door_open())
290 ioctl(fd, B_EJECT_DEVICE);
291 }
292
293
cd_close(void)294 void cd_close(void)
295 {
296 if (door_open())
297 ioctl(fd, B_LOAD_MEDIA);
298 }
299