1 |
/* |
2 |
* sys_beos.cpp - System dependent routines, BeOS implementation |
3 |
* |
4 |
* Basilisk II (C) 1997-2004 Christian Bauer |
5 |
* |
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 |
} |