ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/BeOS/sys_beos.cpp
Revision: 1.1
Committed: 1999-10-03T14:16:25Z (25 years, 2 months ago) by cebix
Branch: MAIN
Branch point for: cebix
Log Message:
Initial revision

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * sys_beos.cpp - System dependent routines, BeOS implementation
3     *
4     * Basilisk II (C) 1997-1999 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     }