ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/BeOS/sys_beos.cpp
Revision: 1.5
Committed: 2004-01-12T15:29:23Z (20 years, 10 months ago) by cebix
Branch: MAIN
CVS Tags: nigel-build-16, nigel-build-15
Changes since 1.4: +1 -1 lines
Log Message:
Happy New Year! :)

File Contents

# Content
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 }