1 |
cebix |
1.1 |
/* |
2 |
|
|
* sys_beos.cpp - System dependent routines, BeOS implementation |
3 |
|
|
* |
4 |
cebix |
1.5 |
* Basilisk II (C) 1997-2004 Christian Bauer |
5 |
cebix |
1.1 |
* |
6 |
|
|
* This program is free software; you can redistribute it and/or modify |
7 |
|
|
* it under the terms of the GNU General Public License as published by |
8 |
|
|
* the Free Software Foundation; either version 2 of the License, or |
9 |
|
|
* (at your option) any later version. |
10 |
|
|
* |
11 |
|
|
* This program is distributed in the hope that it will be useful, |
12 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
|
|
* GNU General Public License for more details. |
15 |
|
|
* |
16 |
|
|
* You should have received a copy of the GNU General Public License |
17 |
|
|
* along with this program; if not, write to the Free Software |
18 |
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 |
|
|
*/ |
20 |
|
|
|
21 |
|
|
#include <StorageKit.h> |
22 |
|
|
#include <InterfaceKit.h> |
23 |
|
|
#include <kernel/fs_info.h> |
24 |
|
|
#include <drivers/Drivers.h> |
25 |
|
|
#include <device/scsi.h> |
26 |
|
|
|
27 |
|
|
#include <unistd.h> |
28 |
|
|
#include <stdio.h> |
29 |
|
|
#include <stdlib.h> |
30 |
|
|
#include <string.h> |
31 |
|
|
#include <fcntl.h> |
32 |
|
|
|
33 |
|
|
#include "sysdeps.h" |
34 |
|
|
#include "main.h" |
35 |
|
|
#include "macos_util.h" |
36 |
|
|
#include "prefs.h" |
37 |
|
|
#include "user_strings.h" |
38 |
|
|
#include "sys.h" |
39 |
|
|
|
40 |
|
|
#define DEBUG 0 |
41 |
|
|
#include "debug.h" |
42 |
|
|
|
43 |
|
|
|
44 |
|
|
// File handles are pointers to these structures |
45 |
|
|
struct file_handle { |
46 |
|
|
file_handle *next; // Pointer to next file handle (must be first in struct!) |
47 |
|
|
const char *name; // File/device name (copied, for mount menu) |
48 |
|
|
int fd; // fd of file/device |
49 |
|
|
bool is_file; // Flag: plain file or /dev/something? |
50 |
|
|
bool read_only; // Copy of Sys_open() flag |
51 |
|
|
loff_t start_byte; // Size of file header (if any) |
52 |
|
|
loff_t file_size; // Size of file data (only valid if is_file is true) |
53 |
|
|
}; |
54 |
|
|
|
55 |
|
|
// Linked list of file handles |
56 |
|
|
static file_handle *first_file_handle; |
57 |
|
|
|
58 |
|
|
// Temporary buffer for transfers from/to kernel space |
59 |
|
|
const int TMP_BUF_SIZE = 0x10000; |
60 |
|
|
static uint8 *tmp_buf; |
61 |
|
|
|
62 |
|
|
// For B_SCSI_PREVENT_ALLOW |
63 |
|
|
static const int32 PREVENT = 1; |
64 |
|
|
static const int32 ALLOW = 0; |
65 |
|
|
|
66 |
|
|
|
67 |
|
|
/* |
68 |
|
|
* Check if device is a mounted HFS volume, get mount name |
69 |
|
|
*/ |
70 |
|
|
|
71 |
|
|
static bool is_drive_mounted(const char *dev_name, char *mount_name) |
72 |
|
|
{ |
73 |
|
|
int32 i = 0; |
74 |
|
|
dev_t d; |
75 |
|
|
fs_info info; |
76 |
|
|
while ((d = next_dev(&i)) >= 0) { |
77 |
|
|
fs_stat_dev(d, &info); |
78 |
|
|
if (strcmp(dev_name, info.device_name) == 0) { |
79 |
|
|
status_t err = -1; |
80 |
|
|
BPath mount; |
81 |
|
|
BDirectory dir; |
82 |
|
|
BEntry entry; |
83 |
|
|
node_ref node; |
84 |
|
|
node.device = info.dev; |
85 |
|
|
node.node = info.root; |
86 |
|
|
err = dir.SetTo(&node); |
87 |
|
|
if (!err) |
88 |
|
|
err = dir.GetEntry(&entry); |
89 |
|
|
if (!err) |
90 |
|
|
err = entry.GetPath(&mount); |
91 |
|
|
if (!err) { |
92 |
|
|
strcpy(mount_name, mount.Path()); |
93 |
|
|
return true; |
94 |
|
|
} |
95 |
|
|
} |
96 |
|
|
} |
97 |
|
|
return false; |
98 |
|
|
} |
99 |
|
|
|
100 |
|
|
|
101 |
|
|
/* |
102 |
|
|
* Initialization |
103 |
|
|
*/ |
104 |
|
|
|
105 |
|
|
void SysInit(void) |
106 |
|
|
{ |
107 |
|
|
first_file_handle = NULL; |
108 |
|
|
|
109 |
|
|
// Allocate temporary buffer |
110 |
|
|
tmp_buf = new uint8[TMP_BUF_SIZE]; |
111 |
|
|
} |
112 |
|
|
|
113 |
|
|
|
114 |
|
|
/* |
115 |
|
|
* Deinitialization |
116 |
|
|
*/ |
117 |
|
|
|
118 |
|
|
void SysExit(void) |
119 |
|
|
{ |
120 |
|
|
delete[] tmp_buf; |
121 |
|
|
} |
122 |
|
|
|
123 |
|
|
|
124 |
|
|
/* |
125 |
|
|
* Create menu of used volumes (for "mount" menu) |
126 |
|
|
*/ |
127 |
|
|
|
128 |
|
|
void SysCreateVolumeMenu(BMenu *menu, uint32 msg) |
129 |
|
|
{ |
130 |
|
|
for (file_handle *fh=first_file_handle; fh; fh=fh->next) |
131 |
|
|
if (!SysIsFixedDisk(fh)) |
132 |
|
|
menu->AddItem(new BMenuItem(fh->name, new BMessage(msg))); |
133 |
|
|
} |
134 |
|
|
|
135 |
|
|
|
136 |
|
|
/* |
137 |
|
|
* Mount volume given name from mount menu |
138 |
|
|
*/ |
139 |
|
|
|
140 |
|
|
void SysMountVolume(const char *name) |
141 |
|
|
{ |
142 |
|
|
file_handle *fh; |
143 |
|
|
for (fh=first_file_handle; fh && strcmp(fh->name, name); fh=fh->next) ; |
144 |
|
|
if (fh) |
145 |
|
|
MountVolume(fh); |
146 |
|
|
} |
147 |
|
|
|
148 |
|
|
|
149 |
|
|
/* |
150 |
|
|
* This gets called when no "floppy" prefs items are found |
151 |
|
|
* It scans for available floppy drives and adds appropriate prefs items |
152 |
|
|
*/ |
153 |
|
|
|
154 |
|
|
void SysAddFloppyPrefs(void) |
155 |
|
|
{ |
156 |
|
|
// Only one floppy drive under BeOS |
157 |
|
|
PrefsAddString("floppy", "/dev/disk/floppy/raw"); |
158 |
|
|
} |
159 |
|
|
|
160 |
|
|
|
161 |
|
|
/* |
162 |
|
|
* This gets called when no "disk" prefs items are found |
163 |
|
|
* It scans for available HFS volumes and adds appropriate prefs items |
164 |
|
|
*/ |
165 |
|
|
|
166 |
|
|
void SysAddDiskPrefs(void) |
167 |
|
|
{ |
168 |
|
|
// Let BeOS scan for HFS drives |
169 |
|
|
D(bug("Looking for Mac volumes...\n")); |
170 |
|
|
system("mountvolume -allhfs"); |
171 |
|
|
|
172 |
|
|
// Add all HFS volumes |
173 |
|
|
int32 i = 0; |
174 |
|
|
dev_t d; |
175 |
|
|
fs_info info; |
176 |
|
|
while ((d = next_dev(&i)) >= 0) { |
177 |
|
|
fs_stat_dev(d, &info); |
178 |
|
|
status_t err = -1; |
179 |
|
|
BPath mount; |
180 |
|
|
if (!strcmp(info.fsh_name, "hfs")) { |
181 |
|
|
BDirectory dir; |
182 |
|
|
BEntry entry; |
183 |
|
|
node_ref node; |
184 |
|
|
node.device = info.dev; |
185 |
|
|
node.node = info.root; |
186 |
|
|
err = dir.SetTo(&node); |
187 |
|
|
if (!err) |
188 |
|
|
err = dir.GetEntry(&entry); |
189 |
|
|
if (!err) |
190 |
|
|
err = entry.GetPath(&mount); |
191 |
|
|
} |
192 |
|
|
if (!err) |
193 |
|
|
err = unmount(mount.Path()); |
194 |
|
|
if (!err) { |
195 |
|
|
char dev_name[B_FILE_NAME_LENGTH]; |
196 |
|
|
if (info.flags & B_FS_IS_READONLY) { |
197 |
|
|
dev_name[0] = '*'; |
198 |
|
|
dev_name[1] = 0; |
199 |
|
|
} else |
200 |
|
|
dev_name[0] = 0; |
201 |
|
|
strcat(dev_name, info.device_name); |
202 |
|
|
PrefsAddString("disk", dev_name); |
203 |
|
|
} |
204 |
|
|
} |
205 |
|
|
} |
206 |
|
|
|
207 |
|
|
|
208 |
|
|
/* |
209 |
|
|
* This gets called when no "cdrom" prefs items are found |
210 |
|
|
* It scans for available CD-ROM drives and adds appropriate prefs items |
211 |
|
|
*/ |
212 |
|
|
|
213 |
|
|
// Scan directory for CD-ROM drives, add them to prefs |
214 |
|
|
static void scan_for_cdrom_drives(const char *directory) |
215 |
|
|
{ |
216 |
|
|
// Set directory |
217 |
|
|
BDirectory dir; |
218 |
|
|
dir.SetTo(directory); |
219 |
|
|
if (dir.InitCheck() != B_NO_ERROR) |
220 |
|
|
return; |
221 |
|
|
dir.Rewind(); |
222 |
|
|
|
223 |
|
|
// Scan each entry |
224 |
|
|
BEntry entry; |
225 |
|
|
while (dir.GetNextEntry(&entry) >= 0) { |
226 |
|
|
|
227 |
|
|
// Get path and ref for entry |
228 |
|
|
BPath path; |
229 |
|
|
if (entry.GetPath(&path) != B_NO_ERROR) |
230 |
|
|
continue; |
231 |
|
|
const char *name = path.Path(); |
232 |
|
|
entry_ref e; |
233 |
|
|
if (entry.GetRef(&e) != B_NO_ERROR) |
234 |
|
|
continue; |
235 |
|
|
|
236 |
|
|
// Recursively enter subdirectories (except for floppy) |
237 |
|
|
if (entry.IsDirectory()) { |
238 |
|
|
if (!strcmp(e.name, "floppy")) |
239 |
|
|
continue; |
240 |
|
|
scan_for_cdrom_drives(name); |
241 |
|
|
} else { |
242 |
|
|
|
243 |
|
|
D(bug(" checking '%s'\n", name)); |
244 |
|
|
|
245 |
|
|
// Ignore partitions |
246 |
|
|
if (strcmp(e.name, "raw")) |
247 |
|
|
continue; |
248 |
|
|
|
249 |
|
|
// Open device |
250 |
|
|
int fd = open(name, O_RDONLY); |
251 |
|
|
if (fd < 0) |
252 |
|
|
continue; |
253 |
|
|
|
254 |
|
|
// Get geometry and device type |
255 |
|
|
device_geometry g; |
256 |
|
|
if (ioctl(fd, B_GET_GEOMETRY, &g, sizeof(g)) < 0) { |
257 |
|
|
close(fd); |
258 |
|
|
continue; |
259 |
|
|
} |
260 |
|
|
|
261 |
|
|
// Insert to list if it is a CD drive |
262 |
|
|
if (g.device_type == B_CD) |
263 |
|
|
PrefsAddString("cdrom", name); |
264 |
|
|
close(fd); |
265 |
|
|
} |
266 |
|
|
} |
267 |
|
|
} |
268 |
|
|
|
269 |
|
|
void SysAddCDROMPrefs(void) |
270 |
|
|
{ |
271 |
|
|
// Don't scan for drives if nocdrom option given |
272 |
|
|
if (PrefsFindBool("nocdrom")) |
273 |
|
|
return; |
274 |
|
|
|
275 |
|
|
// Look for CD-ROM drives and add prefs items |
276 |
|
|
D(bug("Looking for CD-ROM drives...\n")); |
277 |
|
|
scan_for_cdrom_drives("/dev/disk"); |
278 |
|
|
} |
279 |
|
|
|
280 |
|
|
|
281 |
|
|
/* |
282 |
|
|
* Add default serial prefs (must be added, even if no ports present) |
283 |
|
|
*/ |
284 |
|
|
|
285 |
|
|
void SysAddSerialPrefs(void) |
286 |
|
|
{ |
287 |
|
|
system_info info; |
288 |
|
|
get_system_info(&info); |
289 |
|
|
switch (info.platform_type) { |
290 |
|
|
case B_BEBOX_PLATFORM: |
291 |
|
|
case B_AT_CLONE_PLATFORM: |
292 |
|
|
PrefsAddString("seriala", "serial1"); |
293 |
|
|
PrefsAddString("serialb", "serial2"); |
294 |
|
|
break; |
295 |
|
|
case B_MAC_PLATFORM: |
296 |
|
|
PrefsAddString("seriala", "modem"); |
297 |
|
|
PrefsAddString("serialb", "printer"); |
298 |
|
|
break; |
299 |
|
|
default: |
300 |
|
|
PrefsAddString("seriala", "none"); |
301 |
|
|
PrefsAddString("serialb", "none"); |
302 |
|
|
break; |
303 |
|
|
} |
304 |
|
|
} |
305 |
|
|
|
306 |
|
|
|
307 |
|
|
/* |
308 |
|
|
* Open file/device, create new file handle (returns NULL on error) |
309 |
|
|
*/ |
310 |
|
|
|
311 |
|
|
void *Sys_open(const char *name, bool read_only) |
312 |
|
|
{ |
313 |
|
|
static bool published_all = false; |
314 |
|
|
bool is_file = (strstr(name, "/dev/") != name); |
315 |
|
|
|
316 |
|
|
D(bug("Sys_open(%s, %s)\n", name, read_only ? "read-only" : "read/write")); |
317 |
|
|
|
318 |
|
|
// Print warning message and eventually unmount drive when this is an HFS volume mounted under BeOS (double mounting will corrupt the volume) |
319 |
|
|
char mount_name[B_FILE_NAME_LENGTH]; |
320 |
|
|
if (!is_file && !read_only && is_drive_mounted(name, mount_name)) { |
321 |
|
|
char str[256 + B_FILE_NAME_LENGTH]; |
322 |
|
|
sprintf(str, GetString(STR_VOLUME_IS_MOUNTED_WARN), mount_name); |
323 |
|
|
WarningAlert(str); |
324 |
|
|
if (unmount(mount_name) != 0) { |
325 |
|
|
sprintf(str, GetString(STR_CANNOT_UNMOUNT_WARN), mount_name); |
326 |
|
|
WarningAlert(str); |
327 |
|
|
return NULL; |
328 |
|
|
} |
329 |
|
|
} |
330 |
|
|
|
331 |
|
|
int fd = open(name, read_only ? O_RDONLY : O_RDWR); |
332 |
|
|
if (fd < 0 && !published_all) { |
333 |
|
|
// Open failed, create all device nodes and try again, but only the first time |
334 |
|
|
system("mountvolume -publishall"); |
335 |
|
|
published_all = true; |
336 |
|
|
fd = open(name, read_only ? O_RDONLY : O_RDWR); |
337 |
|
|
} |
338 |
|
|
if (fd >= 0) { |
339 |
|
|
file_handle *fh = new file_handle; |
340 |
|
|
fh->name = strdup(name); |
341 |
|
|
fh->fd = fd; |
342 |
|
|
fh->is_file = is_file; |
343 |
|
|
fh->read_only = read_only; |
344 |
|
|
fh->start_byte = 0; |
345 |
|
|
if (fh->is_file) { |
346 |
|
|
// Detect disk image file layout |
347 |
|
|
loff_t size = lseek(fd, 0, SEEK_END); |
348 |
|
|
uint8 data[256]; |
349 |
|
|
lseek(fd, 0, SEEK_SET); |
350 |
|
|
read(fd, data, 256); |
351 |
|
|
FileDiskLayout(size, data, fh->start_byte, fh->file_size); |
352 |
|
|
} |
353 |
|
|
|
354 |
|
|
// Enqueue file handle |
355 |
|
|
fh->next = NULL; |
356 |
|
|
file_handle *q = first_file_handle; |
357 |
|
|
if (q) { |
358 |
|
|
while (q->next) |
359 |
|
|
q = q->next; |
360 |
|
|
q->next = fh; |
361 |
|
|
} else |
362 |
|
|
first_file_handle = fh; |
363 |
|
|
return fh; |
364 |
|
|
} else |
365 |
|
|
return NULL; |
366 |
|
|
} |
367 |
|
|
|
368 |
|
|
|
369 |
|
|
/* |
370 |
|
|
* Close file/device, delete file handle |
371 |
|
|
*/ |
372 |
|
|
|
373 |
|
|
void Sys_close(void *arg) |
374 |
|
|
{ |
375 |
|
|
file_handle *fh = (file_handle *)arg; |
376 |
|
|
if (!fh) |
377 |
|
|
return; |
378 |
|
|
|
379 |
|
|
// Free device name and close file/device |
380 |
|
|
free((void *)fh->name); |
381 |
|
|
close(fh->fd); |
382 |
|
|
|
383 |
|
|
// Dequeue file handle |
384 |
|
|
file_handle *q = first_file_handle; |
385 |
|
|
if (q == fh) { |
386 |
|
|
first_file_handle = NULL; |
387 |
|
|
delete fh; |
388 |
|
|
return; |
389 |
|
|
} |
390 |
|
|
while (q) { |
391 |
|
|
if (q->next == fh) { |
392 |
|
|
q->next = fh->next; |
393 |
|
|
delete fh; |
394 |
|
|
return; |
395 |
|
|
} |
396 |
|
|
q = q->next; |
397 |
|
|
} |
398 |
|
|
} |
399 |
|
|
|
400 |
|
|
|
401 |
|
|
/* |
402 |
|
|
* Read "length" bytes from file/device, starting at "offset", to "buffer", |
403 |
|
|
* returns number of bytes read (or 0) |
404 |
|
|
*/ |
405 |
|
|
|
406 |
|
|
static inline ssize_t sread(int fd, void *buf, size_t count) |
407 |
|
|
{ |
408 |
|
|
ssize_t res; |
409 |
|
|
while ((res = read(fd, buf, count)) == B_INTERRUPTED) ; |
410 |
|
|
return res; |
411 |
|
|
} |
412 |
|
|
|
413 |
|
|
size_t Sys_read(void *arg, void *buffer, loff_t offset, size_t length) |
414 |
|
|
{ |
415 |
|
|
file_handle *fh = (file_handle *)arg; |
416 |
|
|
if (!fh) |
417 |
|
|
return 0; |
418 |
|
|
|
419 |
|
|
// D(bug("Sys_read(%08lx, %08lx, %Ld, %d)\n", fh, buffer, offset, length)); |
420 |
|
|
|
421 |
|
|
// Seek to position |
422 |
|
|
if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0) |
423 |
|
|
return 0; |
424 |
|
|
|
425 |
|
|
// Buffer in kernel space? |
426 |
|
|
size_t actual = 0; |
427 |
|
|
if ((uint32)buffer < 0x80000000) { |
428 |
|
|
|
429 |
|
|
// Yes, transfer via buffer |
430 |
|
|
while (length) { |
431 |
|
|
size_t transfer_size = (length > TMP_BUF_SIZE) ? TMP_BUF_SIZE : length; |
432 |
|
|
if (sread(fh->fd, tmp_buf, transfer_size) != transfer_size) |
433 |
|
|
return actual; |
434 |
|
|
memcpy(buffer, tmp_buf, transfer_size); |
435 |
|
|
buffer = (void *)((uint8 *)buffer + transfer_size); |
436 |
|
|
length -= transfer_size; |
437 |
|
|
actual += transfer_size; |
438 |
|
|
} |
439 |
|
|
|
440 |
|
|
} else { |
441 |
|
|
|
442 |
|
|
// No, transfer directly |
443 |
|
|
actual = sread(fh->fd, buffer, length); |
444 |
|
|
if (actual < 0) |
445 |
|
|
actual = 0; |
446 |
|
|
} |
447 |
|
|
return actual; |
448 |
|
|
} |
449 |
|
|
|
450 |
|
|
|
451 |
|
|
/* |
452 |
|
|
* Write "length" bytes from "buffer" to file/device, starting at "offset", |
453 |
|
|
* returns number of bytes written (or 0) |
454 |
|
|
*/ |
455 |
|
|
|
456 |
|
|
static inline ssize_t swrite(int fd, void *buf, size_t count) |
457 |
|
|
{ |
458 |
|
|
ssize_t res; |
459 |
|
|
while ((res = write(fd, buf, count)) == B_INTERRUPTED) ; |
460 |
|
|
return res; |
461 |
|
|
} |
462 |
|
|
|
463 |
|
|
size_t Sys_write(void *arg, void *buffer, loff_t offset, size_t length) |
464 |
|
|
{ |
465 |
|
|
file_handle *fh = (file_handle *)arg; |
466 |
|
|
if (!fh) |
467 |
|
|
return 0; |
468 |
|
|
|
469 |
|
|
// D(bug("Sys_write(%08lx, %08lx, %Ld, %d)\n", fh, buffer, offset, length)); |
470 |
|
|
|
471 |
|
|
// Seek to position |
472 |
|
|
if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0) |
473 |
|
|
return 0; |
474 |
|
|
|
475 |
|
|
// Buffer in kernel space? |
476 |
|
|
size_t actual = 0; |
477 |
|
|
if ((uint32)buffer < 0x80000000) { |
478 |
|
|
|
479 |
|
|
// Yes, transfer via buffer |
480 |
|
|
while (length) { |
481 |
|
|
size_t transfer_size = (length > TMP_BUF_SIZE) ? TMP_BUF_SIZE : length; |
482 |
|
|
memcpy(tmp_buf, buffer, transfer_size); |
483 |
|
|
if (swrite(fh->fd, tmp_buf, transfer_size) != transfer_size) |
484 |
|
|
return actual; |
485 |
|
|
buffer = (void *)((uint8 *)buffer + transfer_size); |
486 |
|
|
length -= transfer_size; |
487 |
|
|
actual += transfer_size; |
488 |
|
|
} |
489 |
|
|
|
490 |
|
|
} else { |
491 |
|
|
|
492 |
|
|
// No, transfer directly |
493 |
|
|
actual = swrite(fh->fd, buffer, length); |
494 |
|
|
if (actual < 0) |
495 |
|
|
actual = 0; |
496 |
|
|
} |
497 |
|
|
return actual; |
498 |
|
|
} |
499 |
|
|
|
500 |
|
|
|
501 |
|
|
/* |
502 |
|
|
* Return size of file/device (minus header) |
503 |
|
|
*/ |
504 |
|
|
|
505 |
|
|
loff_t SysGetFileSize(void *arg) |
506 |
|
|
{ |
507 |
|
|
file_handle *fh = (file_handle *)arg; |
508 |
|
|
if (!fh) |
509 |
|
|
return true; |
510 |
|
|
|
511 |
|
|
if (fh->is_file) |
512 |
|
|
return fh->file_size; |
513 |
|
|
else { |
514 |
|
|
device_geometry g; |
515 |
|
|
if (ioctl(fh->fd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0) |
516 |
|
|
return (loff_t)g.bytes_per_sector * g.sectors_per_track * g.cylinder_count * g.head_count; |
517 |
|
|
else |
518 |
|
|
return 0; |
519 |
|
|
} |
520 |
|
|
} |
521 |
|
|
|
522 |
|
|
|
523 |
|
|
/* |
524 |
|
|
* Eject volume (if applicable) |
525 |
|
|
*/ |
526 |
|
|
|
527 |
|
|
void SysEject(void *arg) |
528 |
|
|
{ |
529 |
|
|
file_handle *fh = (file_handle *)arg; |
530 |
|
|
if (!fh) |
531 |
|
|
return; |
532 |
|
|
|
533 |
|
|
if (!fh->is_file) |
534 |
|
|
ioctl(fh->fd, B_EJECT_DEVICE); |
535 |
|
|
} |
536 |
|
|
|
537 |
|
|
|
538 |
|
|
/* |
539 |
|
|
* Format volume (if applicable) |
540 |
|
|
*/ |
541 |
|
|
|
542 |
|
|
bool SysFormat(void *arg) |
543 |
|
|
{ |
544 |
|
|
file_handle *fh = (file_handle *)arg; |
545 |
|
|
if (!fh) |
546 |
|
|
return false; |
547 |
|
|
|
548 |
|
|
if (!fh->is_file) |
549 |
|
|
return ioctl(fh->fd, B_FORMAT_DEVICE) >= 0; |
550 |
|
|
else |
551 |
|
|
return false; |
552 |
|
|
} |
553 |
|
|
|
554 |
|
|
|
555 |
|
|
/* |
556 |
|
|
* Check if file/device is read-only (this includes the read-only flag on Sys_open()) |
557 |
|
|
*/ |
558 |
|
|
|
559 |
|
|
bool SysIsReadOnly(void *arg) |
560 |
|
|
{ |
561 |
|
|
file_handle *fh = (file_handle *)arg; |
562 |
|
|
if (!fh) |
563 |
|
|
return true; |
564 |
|
|
|
565 |
|
|
if (fh->is_file) { |
566 |
|
|
|
567 |
|
|
// File, return flag given to Sys_open |
568 |
|
|
return fh->read_only; |
569 |
|
|
|
570 |
|
|
} else { |
571 |
|
|
|
572 |
|
|
// Device, check write protection |
573 |
|
|
device_geometry g; |
574 |
|
|
if (ioctl(fh->fd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0) |
575 |
|
|
return g.read_only | fh->read_only; |
576 |
|
|
else |
577 |
|
|
return fh->read_only; // Removable but not inserted |
578 |
|
|
} |
579 |
|
|
} |
580 |
|
|
|
581 |
|
|
|
582 |
|
|
/* |
583 |
|
|
* Check if the given file handle refers to a fixed or a removable disk |
584 |
|
|
*/ |
585 |
|
|
|
586 |
|
|
bool SysIsFixedDisk(void *arg) |
587 |
|
|
{ |
588 |
|
|
file_handle *fh = (file_handle *)arg; |
589 |
|
|
if (!fh) |
590 |
|
|
return true; |
591 |
|
|
|
592 |
|
|
if (fh->is_file) |
593 |
|
|
return true; |
594 |
|
|
else { |
595 |
|
|
device_geometry g; |
596 |
|
|
if (ioctl(fh->fd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0) |
597 |
|
|
return !g.removable; |
598 |
|
|
else |
599 |
|
|
return false; // Removable but not inserted |
600 |
|
|
} |
601 |
|
|
} |
602 |
|
|
|
603 |
|
|
|
604 |
|
|
/* |
605 |
|
|
* Check if a disk is inserted in the drive (always true for files) |
606 |
|
|
*/ |
607 |
|
|
|
608 |
|
|
bool SysIsDiskInserted(void *arg) |
609 |
|
|
{ |
610 |
|
|
file_handle *fh = (file_handle *)arg; |
611 |
|
|
if (!fh) |
612 |
|
|
return false; |
613 |
|
|
|
614 |
|
|
if (fh->is_file) |
615 |
|
|
return true; |
616 |
|
|
else { |
617 |
|
|
status_t l; |
618 |
|
|
if (ioctl(fh->fd, B_GET_MEDIA_STATUS, &l, sizeof(l)) >= 0 && l == B_NO_ERROR) |
619 |
|
|
return true; |
620 |
|
|
else |
621 |
|
|
return false; |
622 |
|
|
} |
623 |
|
|
} |
624 |
|
|
|
625 |
|
|
|
626 |
|
|
/* |
627 |
|
|
* Prevent medium removal (if applicable) |
628 |
|
|
*/ |
629 |
|
|
|
630 |
|
|
void SysPreventRemoval(void *arg) |
631 |
|
|
{ |
632 |
|
|
file_handle *fh = (file_handle *)arg; |
633 |
|
|
if (!fh) |
634 |
|
|
return; |
635 |
|
|
|
636 |
|
|
if (!fh->is_file) |
637 |
|
|
ioctl(fh->fd, B_SCSI_PREVENT_ALLOW, &PREVENT, sizeof(PREVENT)); |
638 |
|
|
} |
639 |
|
|
|
640 |
|
|
|
641 |
|
|
/* |
642 |
|
|
* Allow medium removal (if applicable) |
643 |
|
|
*/ |
644 |
|
|
|
645 |
|
|
void SysAllowRemoval(void *arg) |
646 |
|
|
{ |
647 |
|
|
file_handle *fh = (file_handle *)arg; |
648 |
|
|
if (!fh) |
649 |
|
|
return; |
650 |
|
|
|
651 |
|
|
if (!fh->is_file) |
652 |
|
|
ioctl(fh->fd, B_SCSI_PREVENT_ALLOW, &ALLOW, sizeof(ALLOW)); |
653 |
|
|
} |
654 |
|
|
|
655 |
|
|
|
656 |
|
|
/* |
657 |
|
|
* Read CD-ROM TOC (binary MSF format, 804 bytes max.) |
658 |
|
|
*/ |
659 |
|
|
|
660 |
|
|
bool SysCDReadTOC(void *arg, uint8 *toc) |
661 |
|
|
{ |
662 |
|
|
file_handle *fh = (file_handle *)arg; |
663 |
|
|
if (!fh) |
664 |
|
|
return false; |
665 |
|
|
|
666 |
|
|
if (!fh->is_file) { |
667 |
|
|
memset(tmp_buf, 0, 804); |
668 |
|
|
if (ioctl(fh->fd, B_SCSI_GET_TOC, tmp_buf, 804) < 0) |
669 |
|
|
return false; |
670 |
|
|
memcpy(toc, tmp_buf, 804); |
671 |
|
|
return true; |
672 |
|
|
} else |
673 |
|
|
return false; |
674 |
|
|
} |
675 |
|
|
|
676 |
|
|
|
677 |
|
|
/* |
678 |
|
|
* Read CD-ROM position data (Sub-Q Channel, 16 bytes, see SCSI standard) |
679 |
|
|
*/ |
680 |
|
|
|
681 |
|
|
bool SysCDGetPosition(void *arg, uint8 *pos) |
682 |
|
|
{ |
683 |
|
|
file_handle *fh = (file_handle *)arg; |
684 |
|
|
if (!fh) |
685 |
|
|
return false; |
686 |
|
|
|
687 |
|
|
if (!fh->is_file) { |
688 |
|
|
if (ioctl(fh->fd, B_SCSI_GET_POSITION, tmp_buf, 16) < 0) |
689 |
|
|
return false; |
690 |
|
|
memcpy(pos, tmp_buf, 16); |
691 |
|
|
return true; |
692 |
|
|
} else |
693 |
|
|
return false; |
694 |
|
|
} |
695 |
|
|
|
696 |
|
|
|
697 |
|
|
/* |
698 |
|
|
* Play CD audio |
699 |
|
|
*/ |
700 |
|
|
|
701 |
|
|
bool SysCDPlay(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, uint8 end_m, uint8 end_s, uint8 end_f) |
702 |
|
|
{ |
703 |
|
|
file_handle *fh = (file_handle *)arg; |
704 |
|
|
if (!fh) |
705 |
|
|
return false; |
706 |
|
|
|
707 |
|
|
if (!fh->is_file) { |
708 |
|
|
scsi_play_position *p = (scsi_play_position *)tmp_buf; |
709 |
|
|
p->start_m = start_m; |
710 |
|
|
p->start_s = start_s; |
711 |
|
|
p->start_f = start_f; |
712 |
|
|
p->end_m = end_m; |
713 |
|
|
p->end_s = end_s; |
714 |
|
|
p->end_f = end_f; |
715 |
|
|
return ioctl(fh->fd, B_SCSI_PLAY_POSITION, p, sizeof(scsi_play_position)) == 0; |
716 |
|
|
} else |
717 |
|
|
return false; |
718 |
|
|
} |
719 |
|
|
|
720 |
|
|
|
721 |
|
|
/* |
722 |
|
|
* Pause CD audio |
723 |
|
|
*/ |
724 |
|
|
|
725 |
|
|
bool SysCDPause(void *arg) |
726 |
|
|
{ |
727 |
|
|
file_handle *fh = (file_handle *)arg; |
728 |
|
|
if (!fh) |
729 |
|
|
return true; |
730 |
|
|
|
731 |
|
|
if (!fh->is_file) |
732 |
|
|
return ioctl(fh->fd, B_SCSI_PAUSE_AUDIO) == 0; |
733 |
|
|
else |
734 |
|
|
return false; |
735 |
|
|
} |
736 |
|
|
|
737 |
|
|
|
738 |
|
|
/* |
739 |
|
|
* Resume paused CD audio |
740 |
|
|
*/ |
741 |
|
|
|
742 |
|
|
bool SysCDResume(void *arg) |
743 |
|
|
{ |
744 |
|
|
file_handle *fh = (file_handle *)arg; |
745 |
|
|
if (!fh) |
746 |
|
|
return false; |
747 |
|
|
|
748 |
|
|
if (!fh->is_file) |
749 |
|
|
return ioctl(fh->fd, B_SCSI_RESUME_AUDIO) == 0; |
750 |
|
|
else |
751 |
|
|
return false; |
752 |
|
|
} |
753 |
|
|
|
754 |
|
|
|
755 |
|
|
/* |
756 |
|
|
* Stop CD audio |
757 |
|
|
*/ |
758 |
|
|
|
759 |
|
|
bool SysCDStop(void *arg, uint8 lead_out_m, uint8 lead_out_s, uint8 lead_out_f) |
760 |
|
|
{ |
761 |
|
|
file_handle *fh = (file_handle *)arg; |
762 |
|
|
if (!fh) |
763 |
|
|
return false; |
764 |
|
|
|
765 |
|
|
if (!fh->is_file) |
766 |
|
|
return ioctl(fh->fd, B_SCSI_STOP_AUDIO) == 0; |
767 |
|
|
else |
768 |
|
|
return false; |
769 |
|
|
} |
770 |
|
|
|
771 |
|
|
|
772 |
|
|
/* |
773 |
|
|
* Perform CD audio fast-forward/fast-reverse operation starting from specified address |
774 |
|
|
*/ |
775 |
|
|
|
776 |
|
|
bool SysCDScan(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, bool reverse) |
777 |
|
|
{ |
778 |
|
|
file_handle *fh = (file_handle *)arg; |
779 |
|
|
if (!fh) |
780 |
|
|
return false; |
781 |
|
|
|
782 |
|
|
if (!fh->is_file) { |
783 |
|
|
scsi_scan *p = (scsi_scan *)tmp_buf; |
784 |
|
|
p->speed = 0; |
785 |
|
|
p->direction = reverse ? -1 : 1; |
786 |
|
|
return ioctl(fh->fd, B_SCSI_SCAN, p, sizeof(scsi_scan)) == 0; |
787 |
|
|
} else |
788 |
|
|
return false; |
789 |
|
|
} |
790 |
|
|
|
791 |
|
|
|
792 |
|
|
/* |
793 |
|
|
* Set CD audio volume (0..255 each channel) |
794 |
|
|
*/ |
795 |
|
|
|
796 |
|
|
void SysCDSetVolume(void *arg, uint8 left, uint8 right) |
797 |
|
|
{ |
798 |
|
|
file_handle *fh = (file_handle *)arg; |
799 |
|
|
if (!fh) |
800 |
|
|
return; |
801 |
|
|
|
802 |
|
|
if (!fh->is_file) { |
803 |
|
|
scsi_volume *p = (scsi_volume *)tmp_buf; |
804 |
|
|
p->flags = B_SCSI_PORT0_VOLUME | B_SCSI_PORT1_VOLUME; |
805 |
|
|
p->port0_volume = left; |
806 |
|
|
p->port1_volume = right; |
807 |
|
|
ioctl(fh->fd, B_SCSI_SET_VOLUME, p, sizeof(scsi_volume)); |
808 |
|
|
} |
809 |
|
|
} |
810 |
|
|
|
811 |
|
|
|
812 |
|
|
/* |
813 |
|
|
* Get CD audio volume (0..255 each channel) |
814 |
|
|
*/ |
815 |
|
|
|
816 |
|
|
void SysCDGetVolume(void *arg, uint8 &left, uint8 &right) |
817 |
|
|
{ |
818 |
|
|
file_handle *fh = (file_handle *)arg; |
819 |
|
|
if (!fh) |
820 |
|
|
return; |
821 |
|
|
|
822 |
|
|
left = right = 0; |
823 |
|
|
if (!fh->is_file) { |
824 |
|
|
scsi_volume *p = (scsi_volume *)tmp_buf; |
825 |
|
|
p->flags = B_SCSI_PORT0_VOLUME | B_SCSI_PORT1_VOLUME; |
826 |
|
|
if (ioctl(fh->fd, B_SCSI_GET_VOLUME, p, sizeof(scsi_volume)) == 0) { |
827 |
|
|
left = p->port0_volume; |
828 |
|
|
right = p->port1_volume; |
829 |
|
|
} |
830 |
|
|
} |
831 |
|
|
} |