示例#1
0
void *Sys_open(const char *name, bool read_only)
{
	static bool published_all = false;
	bool is_file = (strstr(name, "/dev/") != name);

	D(bug("Sys_open(%s, %s)\n", name, read_only ? "read-only" : "read/write"));

	// Print warning message and eventually unmount drive when this is an HFS volume mounted under BeOS (double mounting will corrupt the volume)
	char mount_name[B_FILE_NAME_LENGTH];
	if (!is_file && !read_only && is_drive_mounted(name, mount_name)) {
		char str[256 + B_FILE_NAME_LENGTH];
		sprintf(str, GetString(STR_VOLUME_IS_MOUNTED_WARN), mount_name);
		WarningAlert(str);
#warning TODO: unmount disk!
#if 0
		if (unmount(mount_name) != 0) {
			sprintf(str, GetString(STR_CANNOT_UNMOUNT_WARN), mount_name);
			WarningAlert(str);
			return NULL;
		}
#endif
	}

	int fd = open(name, read_only ? O_RDONLY : O_RDWR);
	if (fd < 0 && !published_all) {
		// Open failed, create all device nodes and try again, but only the first time
		system("mountvolume -publishall");
		published_all = true;
		fd = open(name, read_only ? O_RDONLY : O_RDWR);
	}
	if (fd >= 0) {
		file_handle *fh = new file_handle;
		fh->name = strdup(name);
		fh->fd = fd;
		fh->is_file = is_file;
		fh->read_only = read_only;
		fh->start_byte = 0;
		if (fh->is_file) {
			// Detect disk image file layout
			loff_t size = lseek(fd, 0, SEEK_END);
			uint8 data[256];
			lseek(fd, 0, SEEK_SET);
			read(fd, data, 256);
			FileDiskLayout(size, data, fh->start_byte, fh->file_size);
		}

		// Enqueue file handle
		fh->next = NULL;
		file_handle *q = first_file_handle;
		if (q) {
			while (q->next)
				q = q->next;
			q->next = fh;
		} else
			first_file_handle = fh;
		return fh;
	} else
		return NULL;
}
示例#2
0
void SCSIInit(void)
{
	int id;

	// Allocate buffer
	buffer = (uint8 *)malloc(buffer_size = 0x10000);

	// Open generic SCSI driver for all 8 units
    for (id=0; id<8; id++) {
		char prefs_name[16];
		sprintf(prefs_name, "scsi%d", id);
		const char *str = PrefsFindString(prefs_name);
		if (str) {
			int fd = fds[id] = open(str, O_RDWR | O_EXCL);
			if (fd > 0) {
				// Is it really a Generic SCSI device?
				int timeout = ioctl(fd, SG_GET_TIMEOUT);
				if (timeout < 0) {
					// Error with SG_GET_TIMEOUT, doesn't seem to be a Generic SCSI device
					char msg[256];
					sprintf(msg, GetString(STR_SCSI_DEVICE_NOT_SCSI_WARN), str);
					WarningAlert(msg);
					close(fd);
					fds[id] = -1;
				} else {
					// Flush unwanted garbage from previous use of device
					uint8 reply[256];
					int old_fl = fcntl(fd, F_GETFL);
					fcntl(fd, F_SETFL, old_fl | O_NONBLOCK);
					while (read(fd, reply, sizeof(reply)) != -1 || errno != EAGAIN) ;
					fcntl(fd, F_SETFL, old_fl);
				}
			} else {
				char msg[256];
				sprintf(msg, GetString(STR_SCSI_DEVICE_OPEN_WARN), str, strerror(errno));
				WarningAlert(msg);
			}
		}
    }

	// Reset SCSI bus
	SCSIReset();
}
示例#3
0
int main(int argc, char **argv)
{
	char str[256];
	int16 i16;
	HANDLE rom_fh;
	const char *rom_path;
	uint32 rom_size;
	DWORD actual;
	uint8 *rom_tmp;

	// Initialize variables
	RAMBase = 0;

	// Print some info
	printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
	printf(" %s\n", GetString(STR_ABOUT_TEXT2));

	// Read preferences
	PrefsInit(NULL, argc, argv);

	// Parse command line arguments
	for (int i=1; i<argc; i++) {
		if (strcmp(argv[i], "--help") == 0) {
			usage(argv[0]);
		} else if (argv[i][0] == '-') {
			fprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
			usage(argv[0]);
		}
	}

	// Check we are using a Windows NT kernel >= 4.0
	OSVERSIONINFO osvi;
	ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	if (!GetVersionEx(&osvi)) {
		ErrorAlert("Could not determine OS type");
		QuitEmulator();
	}
	win_os = osvi.dwPlatformId;
	win_os_major = osvi.dwMajorVersion;
	if (win_os != VER_PLATFORM_WIN32_NT || win_os_major < 4) {
		ErrorAlert(GetString(STR_NO_WIN32_NT_4));
		QuitEmulator();
	}

	// Check that drivers are installed
	if (!check_drivers())
		QuitEmulator();

	// Load win32 libraries
	KernelInit();

	// FIXME: default to DIB driver
	if (getenv("SDL_VIDEODRIVER") == NULL)
	    putenv("SDL_VIDEODRIVER=windib");

	// Initialize SDL system
	int sdl_flags = 0;
#ifdef USE_SDL_VIDEO
	sdl_flags |= SDL_INIT_VIDEO;
#endif
#ifdef USE_SDL_AUDIO
	sdl_flags |= SDL_INIT_AUDIO;
#endif
	assert(sdl_flags != 0);
	if (SDL_Init(sdl_flags) == -1) {
		char str[256];
		sprintf(str, "Could not initialize SDL: %s.\n", SDL_GetError());
		ErrorAlert(str);
		goto quit;
	}
	atexit(SDL_Quit);

#ifdef ENABLE_MON
	// Initialize mon
	mon_init();
#endif

	// Install SIGSEGV handler for CPU emulator
	if (!sigsegv_install_handler(sigsegv_handler)) {
		sprintf(str, GetString(STR_SIGSEGV_INSTALL_ERR), strerror(errno));
		ErrorAlert(str);
		goto quit;
	}

	// Initialize VM system
	vm_init();

	// Get system info
	PVR = 0x00040000;			// Default: 604
	CPUClockSpeed = 100000000;	// Default: 100MHz
	BusClockSpeed = 100000000;	// Default: 100MHz
	TimebaseSpeed =  25000000;	// Default:  25MHz
	PVR = 0x000c0000;			// Default: 7400 (with AltiVec)
	D(bug("PVR: %08x (assumed)\n", PVR));

	// Init system routines
	SysInit();

	// Show preferences editor
	if (!PrefsFindBool("nogui"))
		if (!PrefsEditor())
			goto quit;

	// Create areas for Kernel Data
	if (!kernel_data_init())
		goto quit;
	kernel_data = (KernelData *)Mac2HostAddr(KERNEL_DATA_BASE);
	emulator_data = &kernel_data->ed;
	KernelDataAddr = KERNEL_DATA_BASE;
	D(bug("Kernel Data at %p (%08x)\n", kernel_data, KERNEL_DATA_BASE));
	D(bug("Emulator Data at %p (%08x)\n", emulator_data, KERNEL_DATA_BASE + offsetof(KernelData, ed)));

	// Create area for DR Cache
	if (vm_mac_acquire(DR_EMULATOR_BASE, DR_EMULATOR_SIZE) < 0) {
		sprintf(str, GetString(STR_DR_EMULATOR_MMAP_ERR), strerror(errno));
		ErrorAlert(str);
		goto quit;
	}
	dr_emulator_area_mapped = true;
	if (vm_mac_acquire(DR_CACHE_BASE, DR_CACHE_SIZE) < 0) {
		sprintf(str, GetString(STR_DR_CACHE_MMAP_ERR), strerror(errno));
		ErrorAlert(str);
		goto quit;
	}
	dr_cache_area_mapped = true;
	DRCacheAddr = (uint32)Mac2HostAddr(DR_CACHE_BASE);
	D(bug("DR Cache at %p (%08x)\n", DRCacheAddr, DR_CACHE_BASE));

	// Create area for SheepShaver data
	if (!SheepMem::Init()) {
		sprintf(str, GetString(STR_SHEEP_MEM_MMAP_ERR), strerror(errno));
		ErrorAlert(str);
		goto quit;
	}

	// Create area for Mac ROM
	if (vm_mac_acquire(ROM_BASE, ROM_AREA_SIZE) < 0) {
		sprintf(str, GetString(STR_ROM_MMAP_ERR), strerror(errno));
		ErrorAlert(str);
		goto quit;
	}
	ROMBase = ROM_BASE;
	ROMBaseHost = Mac2HostAddr(ROMBase);
	rom_area_mapped = true;
	D(bug("ROM area at %p (%08x)\n", ROMBaseHost, ROMBase));

	// Create area for Mac RAM
	RAMSize = PrefsFindInt32("ramsize");
	if (RAMSize < 8*1024*1024) {
		WarningAlert(GetString(STR_SMALL_RAM_WARN));
		RAMSize = 8*1024*1024;
	}
	RAMBase = 0;
	if (vm_mac_acquire(RAMBase, RAMSize) < 0) {
		sprintf(str, GetString(STR_RAM_MMAP_ERR), strerror(errno));
		ErrorAlert(str);
		goto quit;
	}
	RAMBaseHost = Mac2HostAddr(RAMBase);
	ram_area_mapped = true;
	D(bug("RAM area at %p (%08x)\n", RAMBaseHost, RAMBase));

	if (RAMBase > ROMBase) {
		ErrorAlert(GetString(STR_RAM_HIGHER_THAN_ROM_ERR));
		goto quit;
	}

	// Load Mac ROM
	rom_path = PrefsFindString("rom");
	rom_fh = CreateFile(rom_path && *rom_path ? rom_path : ROM_FILE_NAME,
						GENERIC_READ, 0, NULL, OPEN_EXISTING,
						FILE_ATTRIBUTE_NORMAL, NULL);

	if (rom_fh == INVALID_HANDLE_VALUE) {
		rom_fh = CreateFile(ROM_FILE_NAME2,
							GENERIC_READ, 0, NULL, OPEN_EXISTING,
							FILE_ATTRIBUTE_NORMAL, NULL);

		if (rom_fh == INVALID_HANDLE_VALUE) {
			ErrorAlert(GetString(STR_NO_ROM_FILE_ERR));
			goto quit;
		}
	}
	printf(GetString(STR_READING_ROM_FILE));
	rom_size = GetFileSize(rom_fh, NULL);
	rom_tmp = new uint8[ROM_SIZE];
	ReadFile(rom_fh, (void *)rom_tmp, ROM_SIZE, &actual, NULL);
	CloseHandle(rom_fh);
	
	// Decode Mac ROM
	if (!DecodeROM(rom_tmp, actual)) {
		if (rom_size != 4*1024*1024) {
			ErrorAlert(GetString(STR_ROM_SIZE_ERR));
			goto quit;
		} else {
			ErrorAlert(GetString(STR_ROM_FILE_READ_ERR));
			goto quit;
		}
	}
	delete[] rom_tmp;
	
	// Initialize native timers
	timer_init();

	// Initialize everything
	if (!InitAll(NULL))
		goto quit;
	D(bug("Initialization complete\n"));

	// Write protect ROM
	vm_protect(ROMBaseHost, ROM_AREA_SIZE, VM_PAGE_READ);

	// Start 60Hz thread
	tick_thread_cancel = false;
	tick_thread_active = ((tick_thread = create_thread(tick_func)) != NULL);
	SetThreadPriority(tick_thread, THREAD_PRIORITY_ABOVE_NORMAL);
	D(bug("Tick thread installed (%ld)\n", tick_thread));

	// Start NVRAM watchdog thread
	memcpy(last_xpram, XPRAM, XPRAM_SIZE);
	nvram_thread_cancel = false;
	nvram_thread_active = ((nvram_thread = create_thread(nvram_func, NULL)) != NULL);
	SetThreadPriority(nvram_thread, THREAD_PRIORITY_BELOW_NORMAL);
	D(bug("NVRAM thread installed (%ld)\n", nvram_thread));

	// Get my thread ID and jump to ROM boot routine
	emul_thread = GetCurrentThread();
	D(bug("Jumping to ROM\n"));
#ifdef _MSC_VER
	__try {
#endif
		jump_to_rom(ROMBase + 0x310000);
#ifdef _MSC_VER
	} __except (main_exception_filter(GetExceptionInformation())) {}
#endif
	D(bug("Returned from ROM\n"));

quit:
	Quit();
	return 0;
}
示例#4
0
bool ether_init(void)
{
	char str[256];

	// Do nothing if no Ethernet device specified
	const char *name = PrefsFindString("ether");
	if (name == NULL)
		return false;

	ether_multi_mode = PrefsFindInt32("ethermulticastmode");
	ether_use_permanent = PrefsFindBool("etherpermanentaddress");

	// Determine Ethernet device type
	net_if_type = -1;
	if (PrefsFindBool("routerenabled") || strcmp(name, "router") == 0)
		net_if_type = NET_IF_ROUTER;
	else if (strcmp(name, "slirp") == 0)
		net_if_type = NET_IF_SLIRP;
	else if (strcmp(name, "tap") == 0)
		net_if_type = NET_IF_TAP;
	else
		net_if_type = NET_IF_B2ETHER;

	// Initialize NAT-Router
	if (net_if_type == NET_IF_ROUTER) {
		if (!router_init())
			net_if_type = NET_IF_FAKE;
	}

	// Initialize slirp library
	if (net_if_type == NET_IF_SLIRP) {
		if (slirp_init() < 0) {
			sprintf(str, GetString(STR_SLIRP_NO_DNS_FOUND_WARN));
			WarningAlert(str);
			return false;
		}
	}

	// Open ethernet device
	const char *dev_name;
	switch (net_if_type) {
	case NET_IF_B2ETHER:
		dev_name = PrefsFindString("etherguid");
		if (dev_name == NULL || strcmp(name, "b2ether") != 0)
			dev_name = name;
		break;
	case NET_IF_TAP:
		dev_name = PrefsFindString("etherguid");
		break;
	}
	if (net_if_type == NET_IF_B2ETHER) {
		if (dev_name == NULL) {
			WarningAlert("No ethernet device GUID specified. Ethernet is not available.");
			goto open_error;
		}

		fd = PacketOpenAdapter( dev_name, ether_multi_mode );
		if (!fd) {
			sprintf(str, "Could not open ethernet adapter %s.", dev_name);
			WarningAlert(str);
			goto open_error;
		}

		// Get Ethernet address
		if(!PacketGetMAC(fd,ether_addr,ether_use_permanent)) {
			sprintf(str, "Could not get hardware address of device %s. Ethernet is not available.", dev_name);
			WarningAlert(str);
			goto open_error;
		}
		D(bug("Real ethernet address %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5]));

		const char *ether_fake_address;
		ether_fake_address = PrefsFindString("etherfakeaddress");
		if(ether_fake_address && strlen(ether_fake_address) == 12) {
			char sm[10];
			strcpy( sm, "0x00" );
			for( int i=0; i<6; i++ ) {
				sm[2] = ether_fake_address[i*2];
				sm[3] = ether_fake_address[i*2+1];
				ether_addr[i] = (uint8)strtoul(sm,0,0);
			}
			D(bug("Fake ethernet address %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5]));
		}
	}
	else if (net_if_type == NET_IF_TAP) {
		if (dev_name == NULL) {
			WarningAlert("No ethernet device GUID specified. Ethernet is not available.");
			goto open_error;
		}

		fd = tap_open_adapter(dev_name);
		if (!fd) {
			sprintf(str, "Could not open ethernet adapter %s.", dev_name);
			WarningAlert(str);
			goto open_error;
		}

		if (!tap_check_version(fd)) {
			sprintf(str, "Minimal TAP-Win32 version supported is %d.%d.", TAP_VERSION_MIN_MAJOR, TAP_VERSION_MIN_MINOR);
			WarningAlert(str);
			goto open_error;
		}

		if (!tap_set_status(fd, true)) {
			sprintf(str, "Could not set media status to connected.");
			WarningAlert(str);
			goto open_error;
		}

		if (!tap_get_mac(fd, ether_addr)) {
			sprintf(str, "Could not get hardware address of device %s. Ethernet is not available.", dev_name);
			WarningAlert(str);
			goto open_error;
		}
		D(bug("Real ethernet address %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5]));

		const char *ether_fake_address;
		ether_fake_address = PrefsFindString("etherfakeaddress");
		if (ether_fake_address && strlen(ether_fake_address) == 12) {
			char sm[10];
			strcpy( sm, "0x00" );
			for( int i=0; i<6; i++ ) {
				sm[2] = ether_fake_address[i*2];
				sm[3] = ether_fake_address[i*2+1];
				ether_addr[i] = (uint8)strtoul(sm,0,0);
			}
		}
#if 1
		/*
		  If we bridge the underlying ethernet connection and the TAP
		  device altogether, we have to use a fake address.
		 */
		else {
			ether_addr[0] = 0x52;
			ether_addr[1] = 0x54;
			ether_addr[2] = 0x00;
		}
#endif
		D(bug("Fake ethernet address %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5]));
	}
	else if (net_if_type == NET_IF_SLIRP) {
		ether_addr[0] = 0x52;
		ether_addr[1] = 0x54;
		ether_addr[2] = 0x00;
		ether_addr[3] = 0x12;
		ether_addr[4] = 0x34;
		ether_addr[5] = 0x56;
		D(bug("Ethernet address %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5]));
	}
	else {
		memcpy( ether_addr, router_mac_addr, 6 );
		D(bug("Fake ethernet address (same as router) %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5]));
	}

	// Start packet reception thread
	int_ack = CreateSemaphore( 0, 0, 1, NULL);
	if(!int_ack) {
		WarningAlert("WARNING: Cannot create int_ack semaphore");
		goto open_error;
	}

	// nonsignaled
	int_sig = CreateSemaphore( 0, 0, 1, NULL);
	if(!int_sig) {
		WarningAlert("WARNING: Cannot create int_sig semaphore");
		goto open_error;
	}

	int_sig2 = CreateSemaphore( 0, 0, 1, NULL);
	if(!int_sig2) {
		WarningAlert("WARNING: Cannot create int_sig2 semaphore");
		goto open_error;
	}

	int_send_now = CreateSemaphore( 0, 0, 1, NULL);
	if(!int_send_now) {
		WarningAlert("WARNING: Cannot create int_send_now semaphore");
		goto open_error;
	}

	init_queue();

	if(!allocate_read_packets()) goto open_error;

	// No need to enter wait state if we can avoid it.
	// These all terminate fast.

	if(pfnInitializeCriticalSectionAndSpinCount) {
		pfnInitializeCriticalSectionAndSpinCount( &fetch_csection, 5000 );
	} else {
		InitializeCriticalSection( &fetch_csection );
	}
	if(pfnInitializeCriticalSectionAndSpinCount) {
		pfnInitializeCriticalSectionAndSpinCount( &queue_csection, 5000 );
	} else {
		InitializeCriticalSection( &queue_csection );
	}
	if(pfnInitializeCriticalSectionAndSpinCount) {
		pfnInitializeCriticalSectionAndSpinCount( &send_csection, 5000 );
	} else {
		InitializeCriticalSection( &send_csection );
	}
	if(pfnInitializeCriticalSectionAndSpinCount) {
		pfnInitializeCriticalSectionAndSpinCount( &wpool_csection, 5000 );
	} else {
		InitializeCriticalSection( &wpool_csection );
	}

	ether_th = (HANDLE)_beginthreadex( 0, 0, ether_thread_feed_int, 0, 0, &ether_tid );
	if (!ether_th) {
		D(bug("Failed to create ethernet thread\n"));
		goto open_error;
	}
	thread_active = true;

	unsigned int dummy;
	unsigned int (WINAPI *receive_func)(void *);
	switch (net_if_type) {
	case NET_IF_SLIRP:
	  receive_func = slirp_receive_func;
	  break;
	default:
	  receive_func = ether_thread_get_packets_nt;
	  break;
	}
	ether_th2 = (HANDLE)_beginthreadex( 0, 0, receive_func, 0, 0, &dummy );
	ether_th1 = (HANDLE)_beginthreadex( 0, 0, ether_thread_write_packets, 0, 0, &dummy );

	// Everything OK
	return true;

 open_error:
	if (thread_active) {
		TerminateThread(ether_th,0);
		ether_th = 0;
		if (int_ack)
			CloseHandle(int_ack);
		int_ack = 0;
		if(int_sig)
			CloseHandle(int_sig);
		int_sig = 0;
		if(int_sig2)
			CloseHandle(int_sig2);
		int_sig2 = 0;
		if(int_send_now)
			CloseHandle(int_send_now);
		int_send_now = 0;
		thread_active = false;
	}
	if (fd) {
		switch (net_if_type) {
		case NET_IF_B2ETHER:
			PacketCloseAdapter(fd);
			break;
		case NET_IF_TAP:
			tap_close_adapter(fd);
			break;
		}
		fd = 0;
	}
	return false;
}
示例#5
0
static __saveds void net_func(void)
{
	const char *str;
	BYTE od_error;
	struct MsgPort *write_port = NULL, *control_port = NULL;
	struct IOSana2Req *write_io = NULL, *control_io = NULL;
	bool opened = false;
	ULONG read_mask = 0, write_mask = 0, proc_port_mask = 0;
	struct Sana2DeviceQuery query_data = {sizeof(Sana2DeviceQuery)};
	ULONG buffer_tags[] = {
		S2_CopyToBuff, (uint32)copy_to_buff,
		S2_CopyFromBuff, (uint32)copy_from_buff,
		TAG_END
	};

	// Default: error occured
	proc_error = true;

	// Create message port for communication with main task
	proc_port = CreateMsgPort();
	if (proc_port == NULL)
		goto quit;
	proc_port_mask = 1 << proc_port->mp_SigBit;

	// Create message ports for device I/O
	read_port = CreateMsgPort();
	if (read_port == NULL)
		goto quit;
	read_mask = 1 << read_port->mp_SigBit;
	write_port = CreateMsgPort();
	if (write_port == NULL)
		goto quit;
	write_mask = 1 << write_port->mp_SigBit;
	control_port = CreateMsgPort();
	if (control_port == NULL)
		goto quit;

	// Create control IORequest
	control_io = (struct IOSana2Req *)CreateIORequest(control_port, sizeof(struct IOSana2Req));
	if (control_io == NULL)
		goto quit;
	control_io->ios2_Req.io_Message.mn_Node.ln_Type = 0;	// Avoid CheckIO() bug

	// Parse device name
	char dev_name[256];
	ULONG dev_unit;

	str = PrefsFindString("ether");
	if (str) {
		const char *FirstSlash = strchr(str, '/');
		const char *LastSlash = strrchr(str, '/');

		if (FirstSlash && FirstSlash && FirstSlash != LastSlash) {

			// Device name contains path, i.e. "Networks/xyzzy.device"
			const char *lp = str;
			char *dp = dev_name;

			while (lp != LastSlash)
				*dp++ = *lp++;
			*dp = '\0';

			if (strlen(dev_name) < 1)
				goto quit;

			if (sscanf(LastSlash, "/%ld", &dev_unit) != 1)
				goto quit;
		} else {
			if (sscanf(str, "%[^/]/%ld", dev_name, &dev_unit) != 2)
				goto quit;
		}
	} else
		goto quit;

	// Open device
	control_io->ios2_BufferManagement = buffer_tags;
	od_error = OpenDevice((UBYTE *) dev_name, dev_unit, (struct IORequest *)control_io, 0);
	if (od_error != 0 || control_io->ios2_Req.io_Device == 0) {
		printf("WARNING: OpenDevice(<%s>, unit=%d) returned error %d)\n", (UBYTE *)dev_name, dev_unit, od_error);
		goto quit;
	}
	opened = true;

	// Is it Ethernet?
	control_io->ios2_Req.io_Command = S2_DEVICEQUERY;
	control_io->ios2_StatData = (void *)&query_data;
	DoIO((struct IORequest *)control_io);
	if (control_io->ios2_Req.io_Error)
		goto quit;
	if (query_data.HardwareType != S2WireType_Ethernet) {
		WarningAlert(GetString(STR_NOT_ETHERNET_WARN));
		goto quit;
	}

	// Yes, create IORequest for writing
	write_io = (struct IOSana2Req *)CreateIORequest(write_port, sizeof(struct IOSana2Req));
	if (write_io == NULL)
		goto quit;
	memcpy(write_io, control_io, sizeof(struct IOSana2Req));
	write_io->ios2_Req.io_Message.mn_Node.ln_Type = 0;	// Avoid CheckIO() bug
	write_io->ios2_Req.io_Message.mn_ReplyPort = write_port;

	// Configure Ethernet
	control_io->ios2_Req.io_Command = S2_GETSTATIONADDRESS;
	DoIO((struct IORequest *)control_io);
	memcpy(ether_addr, control_io->ios2_DstAddr, 6);
	memcpy(control_io->ios2_SrcAddr, control_io->ios2_DstAddr, 6);
	control_io->ios2_Req.io_Command = S2_CONFIGINTERFACE;
	DoIO((struct IORequest *)control_io);
	D(bug("Ethernet address %08lx %08lx\n", *(uint32 *)ether_addr, *(uint16 *)(ether_addr + 4)));

	// Initialization went well, inform main task
	proc_error = false;
	Signal(MainTask, SIGF_SINGLE);

	// Main loop
	for (;;) {

		// Wait for I/O and messages (CTRL_C is used for quitting the task)
		ULONG sig = Wait(proc_port_mask | read_mask | write_mask | SIGBREAKF_CTRL_C);

		// Main task wants to quit us
		if (sig & SIGBREAKF_CTRL_C)
			break;

		// Main task sent a command to us
		if (sig & proc_port_mask) {
			struct NetMessage *msg;
			while (msg = (NetMessage *)GetMsg(proc_port)) {
				D(bug("net_proc received %08lx\n", msg->what));
				switch (msg->what) {
					case MSG_CLEANUP:
						remove_all_protocols();
						break;

					case MSG_ADD_MULTI:
						control_io->ios2_Req.io_Command = S2_ADDMULTICASTADDRESS;
						Mac2Host_memcpy(control_io->ios2_SrcAddr, msg->pointer + eMultiAddr, 6);
						DoIO((struct IORequest *)control_io);
						if (control_io->ios2_Req.io_Error == S2ERR_NOT_SUPPORTED) {
							WarningAlert(GetString(STR_NO_MULTICAST_WARN));
							msg->result = noErr;
						} else if (control_io->ios2_Req.io_Error)
							msg->result = eMultiErr;
						else
							msg->result = noErr;
						break;

					case MSG_DEL_MULTI:
						control_io->ios2_Req.io_Command = S2_DELMULTICASTADDRESS;
						Mac2Host_memcpy(control_io->ios2_SrcAddr, msg->pointer + eMultiAddr, 6);
						DoIO((struct IORequest *)control_io);
						if (control_io->ios2_Req.io_Error)
							msg->result = eMultiErr;
						else
							msg->result = noErr;
						break;

					case MSG_ATTACH_PH: {
						uint16 type = msg->type;
						uint32 handler = msg->pointer;

						// Protocol of that type already installed?
						NetProtocol *p = (NetProtocol *)prot_list.lh_Head, *next;
						while ((next = (NetProtocol *)p->ln_Succ) != NULL) {
							if (p->type == type) {
								msg->result = lapProtErr;
								goto reply;
							}
							p = next;
						}

						// Allocate NetProtocol, set type and handler
						p = (NetProtocol *)AllocMem(sizeof(NetProtocol), MEMF_PUBLIC);
						if (p == NULL) {
							msg->result = lapProtErr;
							goto reply;
						}
						p->type = type;
						p->handler = handler;

						// Set up and submit read requests
						for (int i=0; i<NUM_READ_REQUESTS; i++) {
							memcpy(p->read_io + i, control_io, sizeof(struct IOSana2Req));
							p->read_io[i].ios2_Req.io_Message.mn_Node.ln_Name = (char *)p;	// Hide pointer to NetProtocol in node name
							p->read_io[i].ios2_Req.io_Message.mn_Node.ln_Type = 0;			// Avoid CheckIO() bug
							p->read_io[i].ios2_Req.io_Message.mn_ReplyPort = read_port;
							p->read_io[i].ios2_Req.io_Command = CMD_READ;
							p->read_io[i].ios2_PacketType = type;
							p->read_io[i].ios2_Data = p->read_buf[i];
							p->read_io[i].ios2_Req.io_Flags = SANA2IOF_RAW;
							BeginIO((struct IORequest *)(p->read_io + i));
						}

						// Add protocol to list
						AddTail(&prot_list, p);

						// Everything OK
						msg->result = noErr;
						break;
					}

					case MSG_DETACH_PH: {
						uint16 type = msg->type;
						msg->result = lapProtErr;
						NetProtocol *p = (NetProtocol *)prot_list.lh_Head, *next;
						while ((next = (NetProtocol *)p->ln_Succ) != NULL) {
							if (p->type == type) {
								remove_protocol(p);
								msg->result = noErr;
								break;
							}
							p = next;
						}
						break;
					}

					case MSG_WRITE: {
						// Get pointer to Write Data Structure
						uint32 wds = msg->pointer;
						write_io->ios2_Data = (void *)wds;

						// Calculate total packet length
						long len = 0;
						uint32 tmp = wds;
						for (;;) {
							int16 w = ReadMacInt16(tmp);
							if (w == 0)
								break;
							len += w;
							tmp += 6;
						}
						write_io->ios2_DataLength = len;

						// Get destination address
						uint32 hdr = ReadMacInt32(wds + 2);
						Mac2Host_memcpy(write_io->ios2_DstAddr, hdr, 6);

						// Get packet type
						uint32 type = ReadMacInt16(hdr + 12);
						if (type <= 1500)
							type = 0;		// 802.3 packet
						write_io->ios2_PacketType = type;

						// Multicast/broadcard packet?
						if (write_io->ios2_DstAddr[0] & 1) {
							if (*(uint32 *)(write_io->ios2_DstAddr) == 0xffffffff && *(uint16 *)(write_io->ios2_DstAddr + 4) == 0xffff)
								write_io->ios2_Req.io_Command = S2_BROADCAST;
							else
								write_io->ios2_Req.io_Command = S2_MULTICAST;
						} else
							write_io->ios2_Req.io_Command = CMD_WRITE;

						// Send packet
						write_done = false;
						write_io->ios2_Req.io_Flags = SANA2IOF_RAW;
						BeginIO((IORequest *)write_io);
						break;
					}
				}
reply:			D(bug(" net_proc replying\n"));
				ReplyMsg(msg);
			}
		}

		// Packet received
		if (sig & read_mask) {
			D(bug(" packet received, triggering Ethernet interrupt\n"));
			SetInterruptFlag(INTFLAG_ETHER);
			TriggerInterrupt();
		}

		// Packet write completed
		if (sig & write_mask) {
			GetMsg(write_port);
			WriteMacInt32(ether_data + ed_Result, write_io->ios2_Req.io_Error ? excessCollsns : 0);
			write_done = true;
			D(bug(" packet write done, triggering Ethernet interrupt\n"));
			SetInterruptFlag(INTFLAG_ETHER);
			TriggerInterrupt();
		}
	}
quit:

	// Close everything
	remove_all_protocols();
	if (opened) {
		if (CheckIO((struct IORequest *)write_io) == 0) {
			AbortIO((struct IORequest *)write_io);
			WaitIO((struct IORequest *)write_io);
		}
		CloseDevice((struct IORequest *)control_io);
	}
	if (write_io)
		DeleteIORequest(write_io);
	if (control_io)
		DeleteIORequest(control_io);
	if (control_port)
		DeleteMsgPort(control_port);
	if (write_port)
		DeleteMsgPort(write_port);
	if (read_port)
		DeleteMsgPort(read_port);

	// Send signal to main task to confirm termination
	Forbid();
	Signal(MainTask, SIGF_SINGLE);
}
示例#6
0
void *Sys_open(const char *name, bool read_only)
{
	bool is_file = strncmp(name, "/dev/", 5) != 0;
#if defined(__FreeBSD__)
	                // SCSI                             IDE
	bool is_cdrom = strncmp(name, "/dev/cd", 7) == 0 || strncmp(name, "/dev/acd", 8) == 0;
#else
	bool is_cdrom = strncmp(name, "/dev/cd", 7) == 0;
#endif
	bool is_floppy = strncmp(name, "/dev/fd", 7) == 0;

	bool is_polled_media = strncmp(name, "/dev/poll/", 10) == 0;
	if (is_floppy) // Floppy open fails if there's no disk inserted
		is_polled_media = true;

#if defined __MACOSX__
	// There is no set filename in /dev which is the cdrom,
	// so we have to see if it is any of the devices that we found earlier
	{
		int index = 0;
		const char *str;
		while ((str = PrefsFindString("cdrom", index++)) != NULL) {
			if (is_polled_media || strcmp(str, name) == 0) {
				is_cdrom = true;
				read_only = true;
				break;
			}
		}
	}
#endif

	D(bug("Sys_open(%s, %s)\n", name, read_only ? "read-only" : "read/write"));

	// Check if write access is allowed, set read-only flag if not
	if (!read_only && access(name, W_OK))
		read_only = true;

	// Print warning message and eventually unmount drive when this is an HFS volume mounted under Linux (double mounting will corrupt the volume)
	char mount_name[256];
	if (!is_file && !read_only && is_drive_mounted(name, mount_name)) {
		char str[512];
		sprintf(str, GetString(STR_VOLUME_IS_MOUNTED_WARN), mount_name);
		WarningAlert(str);
		sprintf(str, "umount %s", mount_name);
		if (system(str)) {
			sprintf(str, GetString(STR_CANNOT_UNMOUNT_WARN), mount_name, strerror(errno));
			WarningAlert(str);
			return NULL;
		}
	}

	// Open file/device

#if defined(BINCUE)
	void *binfd = open_bincue(name);
	if (binfd) {
		su_file_handle *fh = open_filehandle(name);
		D(bug("opening %s as bincue\n", name));
		fh->bincue_fd = binfd;
		fh->is_bincue = true;
		fh->read_only = true;
		fh->is_media_present = true;
		sys_add_su_file_handle(fh);
		return fh;
	}
#endif


#if defined(HAVE_LIBVHD)
	int vhdsize;
	void *vhdfd = vhd_unix_open(name, &vhdsize, read_only);
	if (vhdfd) {
		su_file_handle *fh = open_filehandle(name);
		D(bug("opening %s as vnd\n", name));
		fh->is_vhd = true;
		fh->vhd_fd = vhdfd; 
		fh->read_only = read_only;
		fh->file_size = vhdsize;
		fh->is_media_present = true;
		sys_add_su_file_handle(fh);
		return fh;
	}
#endif

#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__MACOSX__)
	int fd = open(name, (read_only ? O_RDONLY : O_RDWR) | (is_cdrom ? O_NONBLOCK : 0));
#else
	int fd = open(name, read_only ? O_RDONLY : O_RDWR);
#endif
	if (fd < 0 && !read_only) {
		// Read-write failed, try read-only
		read_only = true;
		fd = open(name, O_RDONLY);
	}
	if (fd >= 0 || is_polled_media) {
		su_file_handle *fh = open_filehandle(name);
		fh->fd = fd;
		fh->is_file = is_file;
		fh->read_only = read_only;
		fh->is_floppy = is_floppy;
		fh->is_cdrom = is_cdrom;
		if (fh->is_file) {
			fh->is_media_present = true;
			// Detect disk image file layout
			loff_t size = 0;
			size = lseek(fd, 0, SEEK_END);
			uint8 data[256];
			lseek(fd, 0, SEEK_SET);
			read(fd, data, 256);
			FileDiskLayout(size, data, fh->start_byte, fh->file_size);
		} else {
			struct stat st;
			if (fstat(fd, &st) == 0) {
				fh->is_media_present = true;
				if (S_ISBLK(st.st_mode)) {
					fh->is_cdrom = is_cdrom;
#if defined(__linux__)
					fh->is_floppy = (MAJOR(st.st_rdev) == FLOPPY_MAJOR);
#ifdef CDROM_GET_CAPABILITY
					if (is_cdrom) {
						fh->cdrom_cap = ioctl(fh->fd, CDROM_GET_CAPABILITY);
						if (fh->cdrom_cap < 0)
							fh->cdrom_cap = 0;
					}
#endif
#elif defined(__FreeBSD__)
					fh->is_floppy = ((st.st_rdev >> 16) == 2);
#ifdef CDIOCCAPABILITY
					if (is_cdrom) {
						if (ioctl(fh->fd, CDIOCCAPABILITY, &fh->cdrom_cap) < 0)
							memset(&fh->cdrom_cap, 0, sizeof(fh->cdrom_cap));
					}
#endif
#elif defined(__NetBSD__)
					fh->is_floppy = ((st.st_rdev >> 16) == 2);
#endif
				}
#if defined __MACOSX__
				if (is_cdrom) {
					fh->is_cdrom = true;
					fh->is_floppy = false;
					if (cdrom_open_1(fh))
						fh->is_media_present = true;
				}
#endif
			}
示例#7
0
void WarningAlert(int string_id)
{
	WarningAlert(GetString(string_id));
}
示例#8
0
void PrefsWindow::MessageReceived(BMessage *msg)
{
	switch (msg->what) {
		case MSG_OK: {				// "Start" button clicked
			read_volumes_prefs();
			read_memory_prefs();
			read_graphics_prefs();
			SavePrefs();
			send_quit_on_close = false;
			PostMessage(B_QUIT_REQUESTED);
			be_app->PostMessage(ok_message);
			break;
		}

		case MSG_CANCEL:			// "Quit" button clicked
			send_quit_on_close = false;
			PostMessage(B_QUIT_REQUESTED);
			be_app->PostMessage(B_QUIT_REQUESTED);
			break;

		case B_ABOUT_REQUESTED: {	// "About" menu item selected
			ShowAboutWindow();
			break;
		}

		case MSG_ZAP_PRAM:			// "Zap PRAM File" menu item selected
			ZapPRAM();
			break;

		case MSG_VOLUME_INVOKED: {	// Double-clicked on volume name, toggle read-only flag
			int selected = volume_list->CurrentSelection();
			if (selected >= 0) {
				const char *str = PrefsFindString("disk", selected);
				BStringItem *item = (BStringItem *)volume_list->RemoveItem(selected);
				delete item;
				char newstr[256];
				if (str[0] == '*')
					strcpy(newstr, str+1);
				else {
					strcpy(newstr, "*");
					strcat(newstr, str);
				}
				PrefsReplaceString("disk", newstr, selected);
				volume_list->AddItem(new BStringItem(newstr), selected);
				volume_list->Select(selected);
			}
			break;
		}

		case MSG_ADD_VOLUME:
			add_volume_panel->Show();
			break;

		case MSG_CREATE_VOLUME:
			create_volume_panel->Show();
			break;

		case MSG_ADD_VOLUME_PANEL: {
			entry_ref ref;
			if (msg->FindRef("refs", &ref) == B_NO_ERROR) {
				BEntry entry(&ref, true);
				BPath path;
				entry.GetPath(&path);
				if (entry.IsFile()) {
					PrefsAddString("disk", path.Path());
					volume_list->AddItem(new BStringItem(path.Path()));
				} else if (entry.IsDirectory()) {
					BVolume volume;
					if (path.Path()[0] == '/' && strchr(path.Path()+1, '/') == NULL && entry.GetVolume(&volume) == B_NO_ERROR) {
						int32 i = 0;
						dev_t d;
						fs_info info;
						while ((d = next_dev(&i)) >= 0) {
							fs_stat_dev(d, &info);
							if (volume.Device() == info.dev) {
								PrefsAddString("disk", info.device_name);
								volume_list->AddItem(new BStringItem(info.device_name));
							}
						}
					}
				}
			}
			break;
		}

		case MSG_CREATE_VOLUME_PANEL: {
			entry_ref dir;
			if (msg->FindRef("directory", &dir) == B_NO_ERROR) {
				BEntry entry(&dir, true);
				BPath path;
				entry.GetPath(&path);
				path.Append(msg->FindString("name"));

				create_volume_panel->Window()->Lock();
				BView *background = create_volume_panel->Window()->ChildAt(0);
				NumberControl *v = (NumberControl *)background->FindView("hardfile_size");
				int size = v->Value();

				char cmd[1024];
				sprintf(cmd, "dd if=/dev/zero \"of=%s\" bs=1024k count=%d", path.Path(), size);
				int ret = system(cmd);
				if (ret == 0) {
					PrefsAddString("disk", path.Path());
					volume_list->AddItem(new BStringItem(path.Path()));
				} else {
					sprintf(cmd, GetString(STR_CREATE_VOLUME_WARN), strerror(ret));
					WarningAlert(cmd);
				}
			}
			break;
		}

		case MSG_REMOVE_VOLUME: {
			int selected = volume_list->CurrentSelection();
			if (selected >= 0) {
				PrefsRemoveItem("disk", selected);
				BStringItem *item = (BStringItem *)volume_list->RemoveItem(selected);
				delete item;
				volume_list->Select(selected);
			}
			break;
		}

		case MSG_BOOT_ANY:
			PrefsReplaceInt32("bootdriver", 0);
			break;

		case MSG_BOOT_CDROM:
			PrefsReplaceInt32("bootdriver", CDROMRefNum);
			break;

		case MSG_NOCDROM:
			PrefsReplaceBool("nocdrom", nocdrom_checkbox->Value() == B_CONTROL_ON);
			break;

		case MSG_VIDEO_WINDOW:
			display_type = DISPLAY_WINDOW;
			hide_show_graphics_ctrls();
			break;

		case MSG_VIDEO_SCREEN:
			display_type = DISPLAY_SCREEN;
			hide_show_graphics_ctrls();
			break;

		case MSG_REF_5HZ:
			PrefsReplaceInt32("frameskip", 12);
			break;

		case MSG_REF_7_5HZ:
			PrefsReplaceInt32("frameskip", 8);
			break;

		case MSG_REF_10HZ:
			PrefsReplaceInt32("frameskip", 6);
			break;

		case MSG_REF_15HZ:
			PrefsReplaceInt32("frameskip", 4);
			break;

		case MSG_REF_30HZ:
			PrefsReplaceInt32("frameskip", 2);
			break;

		case MSG_NOSOUND:
			PrefsReplaceBool("nosound", nosound_checkbox->Value() == B_CONTROL_ON);
			break;

		case MSG_SER_A: {
			BMenuItem *source = NULL;
			msg->FindPointer("source", (void **)&source);
			if (source)
				PrefsReplaceString("seriala", source->Label());
			break;
		}

		case MSG_SER_B: {
			BMenuItem *source = NULL;
			msg->FindPointer("source", (void **)&source);
			if (source)
				PrefsReplaceString("serialb", source->Label());
			break;
		}

		case MSG_ETHER:
			if (ether_checkbox->Value() == B_CONTROL_ON)
				PrefsReplaceString("ether", "yes");
			else
				PrefsRemoveItem("ether");
			break;

		case MSG_UDPTUNNEL:
			PrefsReplaceBool("udptunnel", udptunnel_checkbox->Value() == B_CONTROL_ON);
			hide_show_serial_ctrls();
			break;

		case MSG_RAMSIZE:
			PrefsReplaceInt32("ramsize", ramsize_slider->Value() * 1024 * 1024);
			break;

		case MSG_MODELID_5:
			PrefsReplaceInt32("modelid", 5);
			break;

		case MSG_MODELID_14:
			PrefsReplaceInt32("modelid", 14);
			break;

		case MSG_CPU_68020:
			PrefsReplaceInt32("cpu", 2);
			PrefsReplaceBool("fpu", false);
			break;

		case MSG_CPU_68020_FPU:
			PrefsReplaceInt32("cpu", 2);
			PrefsReplaceBool("fpu", true);
			break;

		case MSG_CPU_68030:
			PrefsReplaceInt32("cpu", 3);
			PrefsReplaceBool("fpu", false);
			break;

		case MSG_CPU_68030_FPU:
			PrefsReplaceInt32("cpu", 3);
			PrefsReplaceBool("fpu", true);
			break;

		case MSG_CPU_68040:
			PrefsReplaceInt32("cpu", 4);
			PrefsReplaceBool("fpu", true);
			break;

		default: {
			// Screen mode messages
			if ((msg->what & 0xffff0000) == MSG_SCREEN_MODE) {
				int m = msg->what & 0xffff;
				uint32 mask = scr_mode[m].mode_mask;
				for (int i=0; i<32; i++)
					if (mask & (1 << i))
						scr_mode_bit = i;
			} else
				BWindow::MessageReceived(msg);
		}
	}
}
示例#9
0
void EmulOp(M68kRegisters *r, uint32 pc, int selector)
{
	D(bug("EmulOp %04x at %08x\n", selector, pc));
	switch (selector) {
		case OP_BREAK:				// Breakpoint
			printf("*** Breakpoint\n");
			Dump68kRegs(r);
			break;

		case OP_XPRAM1: {			// Read/write from/to XPRam
			uint32 len = r->d[3];
			uint8 *adr = Mac2HostAddr(r->a[3]);
			D(bug("XPRAMReadWrite d3: %08lx, a3: %p\n", len, adr));
			int ofs = len & 0xffff;
			len >>= 16;
			if (len & 0x8000) {
				len &= 0x7fff;
				for (uint32 i=0; i<len; i++)
					XPRAM[((ofs + i) & 0xff) + 0x1300] = *adr++;
			} else {
				for (uint32 i=0; i<len; i++)
					*adr++ = XPRAM[((ofs + i) & 0xff) + 0x1300];
			}
			break;
		}

		case OP_XPRAM2:				// Read from XPRam
			r->d[1] = XPRAM[(r->d[1] & 0xff) + 0x1300];
			break;

		case OP_XPRAM3:				// Write to XPRam
			XPRAM[(r->d[1] & 0xff) + 0x1300] = r->d[2];
			break;

		case OP_NVRAM1: {			// Read from NVRAM
			int ofs = r->d[0];
			r->d[0] = XPRAM[ofs & 0x1fff];
			bool localtalk = !(XPRAM[0x13e0] || XPRAM[0x13e1]);	// LocalTalk enabled?
			switch (ofs) {
				case 0x13e0:			// Disable LocalTalk (use EtherTalk instead)
					if (localtalk)
						r->d[0] = 0x00;
					break;
				case 0x13e1:
					if (localtalk)
						r->d[0] = 0x01;
					break;
				case 0x13e2:
					if (localtalk)
						r->d[0] = 0x00;
					break;
				case 0x13e3:
					if (localtalk)
						r->d[0] = 0x0a;
					break;
			}
			break;
		}

		case OP_NVRAM2:				// Write to NVRAM
			XPRAM[r->d[0] & 0x1fff] = r->d[1];
			break;

		case OP_NVRAM3:				// Read/write from/to NVRAM
			if (r->d[3]) {
				r->d[0] = XPRAM[(r->d[4] + 0x1300) & 0x1fff];
			} else {
				XPRAM[(r->d[4] + 0x1300) & 0x1fff] = r->d[5];
				r->d[0] = 0;
			}
			break;

		case OP_FIX_MEMTOP:			// Fixes MemTop in BootGlobs during startup
			D(bug("Fix MemTop\n"));
			WriteMacInt32(BootGlobsAddr - 20, RAMBase + RAMSize);	// MemTop
			r->a[6] = RAMBase + RAMSize;
			break;

		case OP_FIX_MEMSIZE: {		// Fixes physical/logical RAM size during startup
			D(bug("Fix MemSize\n"));
			uint32 diff = ReadMacInt32(0x1ef8) - ReadMacInt32(0x1ef4);
			WriteMacInt32(0x1ef8, RAMSize);			// Physical RAM size
			WriteMacInt32(0x1ef4, RAMSize - diff);	// Logical RAM size
			break;
		}

		case OP_FIX_BOOTSTACK:		// Fixes boot stack pointer in boot 3 resource
			D(bug("Fix BootStack\n"));
			r->a[1] = r->a[7] = RAMBase + RAMSize * 3 / 4;
			break;

		case OP_SONY_OPEN:			// Floppy driver functions
			r->d[0] = SonyOpen(r->a[0], r->a[1]);
			break;
		case OP_SONY_PRIME:
			r->d[0] = SonyPrime(r->a[0], r->a[1]);
			break;
		case OP_SONY_CONTROL:
			r->d[0] = SonyControl(r->a[0], r->a[1]);
			break;
		case OP_SONY_STATUS:
			r->d[0] = SonyStatus(r->a[0], r->a[1]);
			break;

		case OP_DISK_OPEN:			// Disk driver functions
			r->d[0] = DiskOpen(r->a[0], r->a[1]);
			break;
		case OP_DISK_PRIME:
			r->d[0] = DiskPrime(r->a[0], r->a[1]);
			break;
		case OP_DISK_CONTROL:
			r->d[0] = DiskControl(r->a[0], r->a[1]);
			break;
		case OP_DISK_STATUS:
			r->d[0] = DiskStatus(r->a[0], r->a[1]);
			break;

		case OP_CDROM_OPEN:			// CD-ROM driver functions
			r->d[0] = CDROMOpen(r->a[0], r->a[1]);
			break;
		case OP_CDROM_PRIME:
			r->d[0] = CDROMPrime(r->a[0], r->a[1]);
			break;
		case OP_CDROM_CONTROL:
			r->d[0] = CDROMControl(r->a[0], r->a[1]);
			break;
		case OP_CDROM_STATUS:
			r->d[0] = CDROMStatus(r->a[0], r->a[1]);
			break;

		case OP_AUDIO_DISPATCH:		// Audio component functions
			r->d[0] = gMacAudio->Dispatch(r->a[3], r->a[4]);
			break;

		case OP_SOUNDIN_OPEN:		// Sound input driver functions
			r->d[0] = gMacAudio->InOpen(r->a[0], r->a[1]);
			break;
		case OP_SOUNDIN_PRIME:
			r->d[0] = gMacAudio->InPrime(r->a[0], r->a[1]);
			break;
		case OP_SOUNDIN_CONTROL:
			r->d[0] = gMacAudio->InControl(r->a[0], r->a[1]);
			break;
		case OP_SOUNDIN_STATUS:
			r->d[0] = gMacAudio->InStatus(r->a[0], r->a[1]);
			break;
		case OP_SOUNDIN_CLOSE:
			r->d[0] = gMacAudio->InClose(r->a[0], r->a[1]);
			break;

		case OP_ADBOP:				// ADBOp() replacement
			gADBInput->Op(r->d[0], Mac2HostAddr(ReadMacInt32(r->a[0])));
			break;

		case OP_INSTIME:			// InsTime() replacement
			r->d[0] = InsTime(r->a[0], r->d[1]);
			break;
		case OP_RMVTIME:			// RmvTime() replacement
			r->d[0] = RmvTime(r->a[0]);
			break;
		case OP_PRIMETIME:			// PrimeTime() replacement
			r->d[0] = PrimeTime(r->a[0], r->d[0]);
			break;

		case OP_MICROSECONDS:		// Microseconds() replacement
			Microseconds(r->a[0], r->d[0]);
			break;

		case OP_PUT_SCRAP:			// PutScrap() patch
			PutScrap(ReadMacInt32(r->a[7] + 8), Mac2HostAddr(ReadMacInt32(r->a[7] + 4)), ReadMacInt32(r->a[7] + 12));
			break;

		case OP_GET_SCRAP:			// GetScrap() patch
			GetScrap((void **)Mac2HostAddr(ReadMacInt32(r->a[7] + 4)), ReadMacInt32(r->a[7] + 8), ReadMacInt32(r->a[7] + 12));
			break;

		case OP_DEBUG_STR:			// DebugStr() shows warning message
			if (PrefsFindBool("nogui")) {
				uint8 *pstr = Mac2HostAddr(ReadMacInt32(r->a[7] + 4));
				char str[256];
				int i;
				for (i=0; i<pstr[0]; i++)
					str[i] = pstr[i+1];
				str[i] = 0;
				WarningAlert(str);
			}
			break;

		case OP_INSTALL_DRIVERS: {	// Patch to install our own drivers during startup
			// Install drivers
			InstallDrivers();

			// Patch MakeExecutable()
			MakeExecutableTvec = FindLibSymbol("\023PrivateInterfaceLib", "\016MakeExecutable");
			D(bug("MakeExecutable TVECT at %08x\n", MakeExecutableTvec));
			WriteMacInt32(MakeExecutableTvec, NativeFunction(NATIVE_MAKE_EXECUTABLE));
			
			#if defined(__powerpc__) /* Native PowerPC */
			WriteMacInt32(MakeExecutableTvec + 4, (uint32)TOC);
			#endif

			// Patch DebugStr()
			static const uint8 proc_template[] = {
				M68K_EMUL_OP_DEBUG_STR >> 8, M68K_EMUL_OP_DEBUG_STR & 0xFF,
				0x4e, 0x74,			// rtd	#4
				0x00, 0x04
			};
			BUILD_SHEEPSHAVER_PROCEDURE(proc);
			WriteMacInt32(0x1dfc, proc);
			break;
		}

		case OP_NAME_REGISTRY:		// Patch Name Registry and initialize CallUniversalProc
			r->d[0] = (uint32)-1;
			PatchNameRegistry();
			InitCallUniversalProc();
			break;

		case OP_RESET:				// Early in MacOS reset
			D(bug("*** RESET ***\n"));
			TimerReset();
			MacOSUtilReset();
			gMacAudio->Reset();

			// Enable DR emulator (disabled for now)
			if (PrefsFindBool("jit68k") && 0) {
				D(bug("DR activated\n"));
				WriteMacInt32(KernelDataAddr + 0x17a0, 3);		// Prepare for DR emulator activation
				WriteMacInt32(KernelDataAddr + 0x17c0, DR_CACHE_BASE);
				WriteMacInt32(KernelDataAddr + 0x17c4, DR_CACHE_SIZE);
				WriteMacInt32(KernelDataAddr + 0x1b04, DR_CACHE_BASE);
				WriteMacInt32(KernelDataAddr + 0x1b00, DR_EMULATOR_BASE);
				memcpy((void *)DR_EMULATOR_BASE, (void *)(ROMBase + 0x370000), DR_EMULATOR_SIZE);
				MakeExecutable(0, DR_EMULATOR_BASE, DR_EMULATOR_SIZE);
			}
			break;

		case OP_IRQ:			// Level 1 interrupt
			WriteMacInt16(ReadMacInt32(KernelDataAddr + 0x67c), 0);	// Clear interrupt
			r->d[0] = 0;
			if (HasMacStarted()) {
				if (InterruptFlags & INTFLAG_VIA) {
					ClearInterruptFlag(INTFLAG_VIA);
#if !PRECISE_TIMING
					TimerInterrupt();
#endif
					ExecuteNative(NATIVE_VIDEO_VBL);

					static int tick_counter = 0;
					if (++tick_counter >= 60) {
						tick_counter = 0;
						SonyInterrupt();
						DiskInterrupt();
						CDROMInterrupt();
					}

					r->d[0] = 1;		// Flag: 68k interrupt routine executes VBLTasks etc.
				}
				if (InterruptFlags & INTFLAG_SERIAL) {
					ClearInterruptFlag(INTFLAG_SERIAL);
					SerialInterrupt();
				}
				if (InterruptFlags & INTFLAG_ETHER) {
					ClearInterruptFlag(INTFLAG_ETHER);
					ExecuteNative(NATIVE_ETHER_IRQ);
				}
				if (InterruptFlags & INTFLAG_TIMER) {
					ClearInterruptFlag(INTFLAG_TIMER);
					TimerInterrupt();
				}
				if (InterruptFlags & INTFLAG_AUDIO) {
					ClearInterruptFlag(INTFLAG_AUDIO);
					gMacAudio->Interrupt();
				}
				if (InterruptFlags & INTFLAG_ADB) {
					ClearInterruptFlag(INTFLAG_ADB);
					gADBInput->Interrupt();
				}
			} else
				r->d[0] = 1;
			break;

		case OP_SCSI_DISPATCH: {	// SCSIDispatch() replacement
			uint32 ret = ReadMacInt32(r->a[7]);
			uint16 sel = ReadMacInt16(r->a[7] + 4);
			r->a[7] += 6;
//			D(bug("SCSIDispatch(%d)\n", sel));
			int stack;
			switch (sel) {
				case 0:		// SCSIReset
					WriteMacInt16(r->a[7], SCSIReset());
					stack = 0;
					break;
				case 1:		// SCSIGet
					WriteMacInt16(r->a[7], SCSIGet());
					stack = 0;
					break;
				case 2:		// SCSISelect
				case 11:	// SCSISelAtn
					WriteMacInt16(r->a[7] + 2, SCSISelect(ReadMacInt8(r->a[7] + 1)));
					stack = 2;
					break;
				case 3:		// SCSICmd
					WriteMacInt16(r->a[7] + 6, SCSICmd(ReadMacInt16(r->a[7]), Mac2HostAddr(ReadMacInt32(r->a[7] + 2))));
					stack = 6;
					break;
				case 4:		// SCSIComplete
					WriteMacInt16(r->a[7] + 12, SCSIComplete(ReadMacInt32(r->a[7]), ReadMacInt32(r->a[7] + 4), ReadMacInt32(r->a[7] + 8)));
					stack = 12;
					break;
				case 5:		// SCSIRead
				case 8:		// SCSIRBlind
					WriteMacInt16(r->a[7] + 4, SCSIRead(ReadMacInt32(r->a[7])));
					stack = 4;
					break;
				case 6:		// SCSIWrite
				case 9:		// SCSIWBlind
					WriteMacInt16(r->a[7] + 4, SCSIWrite(ReadMacInt32(r->a[7])));
					stack = 4;
					break;
				case 10:	// SCSIStat
					WriteMacInt16(r->a[7], SCSIStat());
					stack = 0;
					break;
				case 12:	// SCSIMsgIn
					WriteMacInt16(r->a[7] + 4, 0);
					stack = 4;
					break;
				case 13:	// SCSIMsgOut
					WriteMacInt16(r->a[7] + 2, 0);
					stack = 2;
					break;
				case 14:	// SCSIMgrBusy
					WriteMacInt16(r->a[7], SCSIMgrBusy());
					stack = 0;
					break;
				default:
					printf("FATAL: SCSIDispatch: illegal selector\n");
					stack = 0;
					//!! SysError(12)
			}
			r->a[0] = ret;
			r->a[7] += stack;
			break;
		}

		case OP_SCSI_ATOMIC:		// SCSIAtomic() replacement
			D(bug("SCSIAtomic\n"));
			r->d[0] = (uint32)-7887;
			break;

		case OP_CHECK_SYSV: {		// Check we are not using MacOS < 8.1 with a NewWorld ROM
			r->a[1] = r->d[1];
			r->a[0] = ReadMacInt32(r->d[1]);
			uint32 sysv = ReadMacInt16(r->a[0]);
			D(bug("Detected MacOS version %d.%d.%d\n", (sysv >> 8) & 0xf, (sysv >> 4) & 0xf, sysv & 0xf));
			if (ROMType == ROMTYPE_NEWWORLD && sysv < 0x0801)
				r->d[1] = 0;
			break;
		}

		case OP_NTRB_17_PATCH:
			r->a[2] = ReadMacInt32(r->a[7]);
			r->a[7] += 4;
			if (ReadMacInt16(r->a[2] + 6) == 17)
				PatchNativeResourceManager();
			break;

		case OP_NTRB_17_PATCH2:
			r->a[7] += 8;
			PatchNativeResourceManager();
			break;

		case OP_NTRB_17_PATCH3:
			r->a[2] = ReadMacInt32(r->a[7]);
			r->a[7] += 4;
		 	D(bug("%d %d\n", ReadMacInt16(r->a[2]), ReadMacInt16(r->a[2] + 6)));
			if (ReadMacInt16(r->a[2]) == 11 && ReadMacInt16(r->a[2] + 6) == 17)
				PatchNativeResourceManager();
			break;

		case OP_NTRB_17_PATCH4:
			r->d[0] = ReadMacInt16(r->a[7]);
			r->a[7] += 2;
		 	D(bug("%d %d\n", ReadMacInt16(r->a[2]), ReadMacInt16(r->a[2] + 6)));
			if (ReadMacInt16(r->a[2]) == 11 && ReadMacInt16(r->a[2] + 6) == 17)
				PatchNativeResourceManager();
			break;

		case OP_CHECKLOAD: {		// vCheckLoad() patch
			uint32 type = ReadMacInt32(r->a[7]);
			r->a[7] += 4;
			int16 id = ReadMacInt16(r->a[2]);
			if (r->a[0] == 0)
				break;
			uint32 adr = ReadMacInt32(r->a[0]);
			if (adr == 0)
				break;
			uint16 *p = (uint16 *)Mac2HostAddr(adr);
			uint32 size = ReadMacInt32(adr - 8) & 0xffffff;
			CheckLoad(type, id, p, size);
			break;
		}

		case OP_EXTFS_COMM:			// External file system routines
			WriteMacInt16(r->a[7] + 14, ExtFSComm(ReadMacInt16(r->a[7] + 12), ReadMacInt32(r->a[7] + 8), ReadMacInt32(r->a[7] + 4)));
			break;

		case OP_EXTFS_HFS:
			WriteMacInt16(r->a[7] + 20, ExtFSHFS(ReadMacInt32(r->a[7] + 16), ReadMacInt16(r->a[7] + 14), ReadMacInt32(r->a[7] + 10), ReadMacInt32(r->a[7] + 6), ReadMacInt16(r->a[7] + 4)));
			break;

		case OP_IDLE_TIME:
			// Sleep if no events pending
			if (ReadMacInt32(0x14c) == 0)
				idle_wait();
			r->a[0] = ReadMacInt32(0x2b6);
			break;

		case OP_IDLE_TIME_2:
			// Sleep if no events pending
			if (ReadMacInt32(0x14c) == 0)
				idle_wait();
			r->d[0] = (uint32)-2;
			break;

		default:
			printf("FATAL: EMUL_OP called with bogus selector %08x\n", selector);
			QuitEmulator();
			break;
	}
}