void get_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir) { // Set default finder info Mac_memset(finfo, 0, SIZEOF_FInfo); if (fxinfo) Mac_memset(fxinfo, 0, SIZEOF_FXInfo); WriteMacInt16(finfo + fdFlags, DEFAULT_FINDER_FLAGS); WriteMacInt32(finfo + fdLocation, (uint32)-1); // Read Finder info file int fd = open_finf(path, O_RDONLY); if (fd >= 0) { ssize_t actual = read(fd, Mac2HostAddr(finfo), SIZEOF_FInfo); if (fxinfo) actual += read(fd, Mac2HostAddr(fxinfo), SIZEOF_FXInfo); close(fd); if (actual >= SIZEOF_FInfo) return; } // No Finder info file, translate file name extension to MacOS type/creator if (!is_dir) { int path_len = strlen(path); for (int i=0; e2t_translation[i].ext; i++) { int ext_len = strlen(e2t_translation[i].ext); if (path_len < ext_len) continue; if (!strcmp(path + path_len - ext_len, e2t_translation[i].ext)) { WriteMacInt32(finfo + fdType, e2t_translation[i].type); WriteMacInt32(finfo + fdCreator, e2t_translation[i].creator); break; } } } }
int16 RmvTime(uint32 tm) { D(bug("RmvTime %08lx\n", tm)); // Find descriptor int i = find_desc(tm); if (i < 0) { D(bug("WARNING: RmvTime(%08lx): Descriptor not found\n", tm)); return 0; } // Task active? if (ReadMacInt16(tm + qType) & 0x8000) { // Yes, make task inactive and remove it from the Time Manager queue WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) & 0x7fff); dequeue_tm(tm); // Compute remaining time tm_time_t remaining, current; timer_current_time(current); timer_sub_time(remaining, desc[i].wakeup, current); WriteMacInt32(tm + tmCount, timer_host2mac_time(remaining)); } else WriteMacInt32(tm + tmCount, 0); D(bug(" tmCount %ld\n", ReadMacInt32(tm + tmCount))); // Free descriptor free_desc(i); return 0; }
void GetScrap(void **handle, uint32 type, int32 offset) { #if defined(__LP64__) D(bug("GetScrap handle %p, type %08x, offset %d\n", handle, type, offset)); #warning Carbon scrapbook function are not implemented in 64-bit mode #else D(bug("GetScrap handle %p, type %08x, offset %d\n", handle, type, offset)); ScrapRef theScrap; if (GetCurrentScrap(&theScrap) != noErr) { D(bug(" could not open scrap\n")); return; } Size byteCount; if (GetScrapFlavorSize(theScrap, type, &byteCount) == noErr) { // Allocate space for new scrap in MacOS side M68kRegisters r; r.d[0] = byteCount; Execute68kTrap(0xa71e, &r); // NewPtrSysClear() uint32 scrap_area = r.a[0]; // Get the native clipboard data if (scrap_area) { uint8 * const data = Mac2HostAddr(scrap_area); if (GetScrapFlavorData(theScrap, type, &byteCount, data) == noErr) { SwapScrapData(type, data, byteCount, FALSE); // Add new data to clipboard static uint8 proc[] = { 0x59, 0x8f, // subq.l #4,sp 0xa9, 0xfc, // ZeroScrap() 0x2f, 0x3c, 0, 0, 0, 0, // move.l #length,-(sp) 0x2f, 0x3c, 0, 0, 0, 0, // move.l #type,-(sp) 0x2f, 0x3c, 0, 0, 0, 0, // move.l #outbuf,-(sp) 0xa9, 0xfe, // PutScrap() 0x58, 0x8f, // addq.l #4,sp M68K_RTS >> 8, M68K_RTS & 0xff }; r.d[0] = sizeof(proc); Execute68kTrap(0xa71e, &r); // NewPtrSysClear() uint32 proc_area = r.a[0]; if (proc_area) { Host2Mac_memcpy(proc_area, proc, sizeof(proc)); WriteMacInt32(proc_area + 6, byteCount); WriteMacInt32(proc_area + 12, type); WriteMacInt32(proc_area + 18, scrap_area); we_put_this_data = true; Execute68k(proc_area, &r); r.a[0] = proc_area; Execute68kTrap(0xa01f, &r); // DisposePtr } } r.a[0] = scrap_area; Execute68kTrap(0xa01f, &r); // DisposePtr }
static void enqueue_tm(uint32 tm) { #if TM_QUEUE uint32 tm_var = ReadMacInt32(0xb30); WriteMacInt32(tm + qLink, ReadMacInt32(tm_var)); WriteMacInt32(tm_var, tm); #endif }
void *XSERDPort::output_func(void *arg) { XSERDPort *s = (XSERDPort *)arg; while (!s->output_thread_cancel) { // Wait for commands sem_wait(&s->output_signal); if (s->quitting) break; // Execute command void *buf = Mac2HostAddr(ReadMacInt32(s->output_pb + ioBuffer)); uint32 length = ReadMacInt32(s->output_pb + ioReqCount); D(bug("output_func transmitting %ld bytes of data...\n", length)); #if MONITOR bug("Sending serial data:\n"); uint8 *adr = (uint8 *)buf; for (int i=0; i<length; i++) { bug("%02x ", adr[i]); } bug("\n"); #endif int32 actual = write(s->fd, buf, length); D(bug(" %ld bytes transmitted\n", actual)); // KillIO called? Then simply return if (s->io_killed) { WriteMacInt16(s->output_pb + ioResult, uint16(abortErr)); WriteMacInt32(s->output_pb + ioActCount, 0); s->write_pending = s->write_done = false; } else { // Set error code if (actual >= 0) { WriteMacInt32(s->output_pb + ioActCount, actual); WriteMacInt32(s->output_dt + serdtResult, noErr); } else { WriteMacInt32(s->output_pb + ioActCount, 0); WriteMacInt32(s->output_dt + serdtResult, uint16(writErr)); } // Trigger serial interrupt D(bug(" triggering serial interrupt\n")); s->write_done = true; SetInterruptFlag(INTFLAG_SERIAL); TriggerInterrupt(); } } return NULL; }
void Enqueue(uint32 elem, uint32 list) { WriteMacInt32(elem + qLink, 0); if (!ReadMacInt32(list + qTail)) { WriteMacInt32(list + qHead, elem); WriteMacInt32(list + qTail, elem); } else { WriteMacInt32(ReadMacInt32(list + qTail) + qLink, elem); WriteMacInt32(list + qTail, elem); } }
void get_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir) { // Set default finder info Mac_memset(finfo, 0, SIZEOF_FInfo); if (fxinfo) Mac_memset(fxinfo, 0, SIZEOF_FXInfo); WriteMacInt16(finfo + fdFlags, DEFAULT_FINDER_FLAGS); WriteMacInt32(finfo + fdLocation, (uint32)-1); // Open file int fd = open(path, O_RDONLY); if (fd < 0) return; if (!is_dir) { // Read BeOS MIME type ssize_t actual = fs_read_attr(fd, "BEOS:TYPE", B_MIME_STRING_TYPE, 0, tmp_buf, 256); tmp_buf[255] = 0; if (actual > 0) { // Translate MIME type to MacOS type/creator uint8 mactype[4]; if (sscanf((char *)tmp_buf, "application/x-MacOS-%c%c%c%c", mactype, mactype+1, mactype+2, mactype+3) == 4) { // MacOS style type WriteMacInt32(finfo + fdType, (mactype[0] << 24) | (mactype[1] << 16) | (mactype[2] << 8) | mactype[3]); } else { // MIME string, look in table for (int i=0; m2t_translation[i].mime; i++) { if (!strcmp((char *)tmp_buf, m2t_translation[i].mime)) { WriteMacInt32(finfo + fdType, m2t_translation[i].type); WriteMacInt32(finfo + fdCreator, m2t_translation[i].creator); break; } } } } // Override file type with MACOS:CREATOR attribute if (fs_read_attr(fd, "MACOS:CREATOR", B_UINT32_TYPE, 0, tmp_buf, 4) == 4) WriteMacInt32(finfo + fdCreator, (tmp_buf[0] << 24) | (tmp_buf[1] << 16) | (tmp_buf[2] << 8) | tmp_buf[3]); } // Read MACOS:HFS_FLAGS attribute if (fs_read_attr(fd, "MACOS:HFS_FLAGS", B_UINT16_TYPE, 0, tmp_buf, 2) == 2) WriteMacInt16(finfo + fdFlags, (tmp_buf[0] << 8) | tmp_buf[1]); // Close file close(fd); }
int16 ASERDPort::status(uint32 pb, uint32 dce, uint16 code) { D(bug("status(%ld)\n", (uint32)code)); switch (code) { case kSERDInputCount: WriteMacInt32(pb + csParam, 0); if (!is_parallel) { if (!query()) return noErr; D(bug("status(2) successful, returning %08lx\n", control_io->IOSer.io_Actual)); WriteMacInt32(pb + csParam, control_io->IOSer.io_Actual); } return noErr; case kSERDStatus: { uint32 p = pb + csParam; WriteMacInt8(p + staCumErrs, cum_errors); cum_errors = 0; WriteMacInt8(p + staRdPend, read_pending); WriteMacInt8(p + staWrPend, write_pending); if (is_parallel) { WriteMacInt8(p + staXOffSent, 0); WriteMacInt8(p + staXOffHold, 0); WriteMacInt8(p + staCtsHold, 0); WriteMacInt8(p + staDsrHold, 0); WriteMacInt8(p + staModemStatus, dsrEvent | dcdEvent | ctsEvent); } else { query(); WriteMacInt8(p + staXOffSent, (control_io->io_Status & IO_STATF_XOFFREAD ? xOffWasSent : 0) | (control_io->io_Status & (1 << 6) ? dtrNegated : 0)); // RTS WriteMacInt8(p + staXOffHold, control_io->io_Status & IO_STATF_XOFFWRITE); WriteMacInt8(p + staCtsHold, control_io->io_Status & (1 << 4)); // CTS WriteMacInt8(p + staDsrHold, control_io->io_Status & (1 << 3)); // DSR WriteMacInt8(p + staModemStatus, (control_io->io_Status & (1 << 3) ? 0 : dsrEvent) | (control_io->io_Status & (1 << 2) ? riEvent : 0) | (control_io->io_Status & (1 << 5) ? 0 : dcdEvent) | (control_io->io_Status & (1 << 4) ? 0 : ctsEvent) | (control_io->io_Status & IO_STATF_READBREAK ? breakEvent : 0)); } return noErr; } default: printf("WARNING: SerialStatus(): unimplemented status code %d\n", code); return statusErr; } }
static DWORD WINAPI tick_func(void *arg) { int tick_counter = 0; uint64 start = GetTicks_usec(); int64 ticks = 0; uint64 next = GetTicks_usec(); while (!tick_thread_cancel) { // Wait next += 16625; int64 delay = next - GetTicks_usec(); if (delay > 0) Delay_usec(delay); else if (delay < -16625) next = GetTicks_usec(); ticks++; // Pseudo Mac 1Hz interrupt, update local time if (++tick_counter > 60) { tick_counter = 0; WriteMacInt32(0x20c, TimerDateTime()); } // Trigger 60Hz interrupt if (ReadMacInt32(XLM_IRQ_NEST) == 0) { SetInterruptFlag(INTFLAG_VIA); TriggerInterrupt(); } } uint64 end = GetTicks_usec(); D(bug("%lu ticks in %lu usec = %f ticks/sec\n", (unsigned long)ticks, (unsigned long)(end - start), ticks * 1000000.0 / (end - start))); return 0; }
int16 PrimeTime(uint32 tm, int32 time) { D(bug("PrimeTime %08lx, time %ld\n", tm, time)); // Find descriptor int i = find_desc(tm); if (i < 0) { printf("FATAL: PrimeTime(): Descriptor not found\n"); return 0; } // Extended task? if (ReadMacInt16(tm + qType) & 0x4000) { // Convert delay time tm_time_t delay; timer_mac2host_time(delay, time); // Yes, tmWakeUp set? if (ReadMacInt32(tm + tmWakeUp)) { //!! PrimeTime(0) means continue previous delay // (save wakeup time in RmvTime?) if (time == 0) { printf("FATAL: Unsupported PrimeTime(0)\n"); return 0; } // Yes, calculate wakeup time relative to last scheduled time tm_time_t wakeup; timer_add_time(wakeup, desc[i].wakeup, delay); desc[i].wakeup = wakeup; } else { // No, calculate wakeup time relative to current time tm_time_t now; timer_current_time(now); timer_add_time(desc[i].wakeup, now, delay); } // Set tmWakeUp to indicate that task was scheduled WriteMacInt32(tm + tmWakeUp, 0x12345678); } else { // Not extended task, calculate wakeup time relative to current time tm_time_t delay; timer_mac2host_time(delay, time); timer_current_time(desc[i].wakeup); timer_add_time(desc[i].wakeup, desc[i].wakeup, delay); } // Make task active and enqueue it in the Time Manager queue WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) | 0x8000); enqueue_tm(tm); return 0; }
int16 ASERDPort::prime_in(uint32 pb, uint32 dce) { // Send input command to serial process D(bug("primein\n")); read_done = false; read_pending = true; WriteMacInt32(input_dt + serdtDCE, dce); send_to_proc(MSG_PRIME_IN, pb); return 1; // Command in progress }
int16 XSERDPort::prime_in(uint32 pb, uint32 dce) { // Send input command to input_thread read_done = false; read_pending = true; input_pb = pb; WriteMacInt32(input_dt + serdtDCE, dce); sem_post(&input_signal); return 1; // Command in progress }
int16 XSERDPort::prime_out(uint32 pb, uint32 dce) { // Send output command to output_thread write_done = false; write_pending = true; output_pb = pb; WriteMacInt32(output_dt + serdtDCE, dce); sem_post(&output_signal); return 1; // Command in progress }
int16 ASERDPort::prime_out(uint32 pb, uint32 dce) { // Send output command to serial process D(bug("primeout\n")); write_done = false; write_pending = true; WriteMacInt32(output_dt + serdtDCE, dce); send_to_proc(MSG_PRIME_OUT, pb); return 1; // Command in progress }
bool NQD_fillrect_hook(uint32 p) { D(bug("accl_fillrect_hook %08x\n", p)); NQD_set_dirty_area(p); // Check if we can accelerate this fillrect if (ReadMacInt32(p + 0x284) != 0 && ReadMacInt32(p + acclDestPixelSize) >= 8) { const int transfer_mode = ReadMacInt32(p + acclTransferMode); if (transfer_mode == 8) { // Fill WriteMacInt32(p + acclDrawProc, NativeTVECT(NATIVE_NQD_FILLRECT)); return true; } else if (transfer_mode == 10) { // Invert WriteMacInt32(p + acclDrawProc, NativeTVECT(NATIVE_NQD_INVRECT)); return true; } } return false; }
static void dequeue_tm(uint32 tm) { #if TM_QUEUE uint32 p = ReadMacInt32(0xb30); while (p) { uint32 next = ReadMacInt32(p + qLink); if (next == tm) { WriteMacInt32(p + qLink, ReadMacInt32(next + qLink)); return; } } #endif }
// Execute EMUL_OP routine void sheepshaver_cpu::execute_emul_op(uint32 emul_op) { M68kRegisters r68; WriteMacInt32(XLM_68K_R25, gpr(25)); WriteMacInt32(XLM_RUN_MODE, MODE_EMUL_OP); for (int i = 0; i < 8; i++) r68.d[i] = gpr(8 + i); for (int i = 0; i < 7; i++) r68.a[i] = gpr(16 + i); r68.a[7] = gpr(1); uint32 saved_cr = get_cr() & 0xff9fffff; // mask_operand::compute(11, 8) uint32 saved_xer = get_xer(); EmulOp(&r68, gpr(24), emul_op); set_cr(saved_cr); set_xer(saved_xer); for (int i = 0; i < 8; i++) gpr(8 + i) = r68.d[i]; for (int i = 0; i < 7; i++) gpr(16 + i) = r68.a[i]; gpr(1) = r68.a[7]; WriteMacInt32(XLM_RUN_MODE, MODE_68K); }
int16 EtherOpen(uint32 pb, uint32 dce) { D(bug("EtherOpen\n")); // Allocate driver data M68kRegisters r; r.d[0] = SIZEOF_etherdata; Execute68kTrap(0xa71e, &r); // NewPtrSysClear() if (r.a[0] == 0) return openErr; ether_data = r.a[0]; D(bug(" data %08lx\n", ether_data)); WriteMacInt16(ether_data + ed_DeferredTask + qType, dtQType); WriteMacInt32(ether_data + ed_DeferredTask + dtAddr, ether_data + ed_Code); WriteMacInt32(ether_data + ed_DeferredTask + dtParam, ether_data + ed_Result); // Deferred function for signalling that packet write is complete (pointer to mydtResult in a1) WriteMacInt16(ether_data + ed_Code, 0x2019); // move.l (a1)+,d0 (result) WriteMacInt16(ether_data + ed_Code + 2, 0x2251); // move.l (a1),a1 (dce) WriteMacInt32(ether_data + ed_Code + 4, 0x207808fc); // move.l JIODone,a0 WriteMacInt16(ether_data + ed_Code + 8, 0x4ed0); // jmp (a0) WriteMacInt32(ether_data + ed_DCE, dce); // ReadPacket/ReadRest routines WriteMacInt16(ether_data + ed_ReadPacket, 0x6010); // bra 2 WriteMacInt16(ether_data + ed_ReadPacket + 2, 0x3003); // move.w d3,d0 WriteMacInt16(ether_data + ed_ReadPacket + 4, 0x9041); // sub.w d1,d0 WriteMacInt16(ether_data + ed_ReadPacket + 6, 0x4a43); // tst.w d3 WriteMacInt16(ether_data + ed_ReadPacket + 8, 0x6702); // beq 1 WriteMacInt16(ether_data + ed_ReadPacket + 10, M68K_EMUL_OP_ETHER_READ_PACKET); WriteMacInt16(ether_data + ed_ReadPacket + 12, 0x3600); //1 move.w d0,d3 WriteMacInt16(ether_data + ed_ReadPacket + 14, 0x7000); // moveq #0,d0 WriteMacInt16(ether_data + ed_ReadPacket + 16, 0x4e75); // rts WriteMacInt16(ether_data + ed_ReadPacket + 18, M68K_EMUL_OP_ETHER_READ_PACKET); //2 WriteMacInt16(ether_data + ed_ReadPacket + 20, 0x4a43); // tst.w d3 WriteMacInt16(ether_data + ed_ReadPacket + 22, 0x4e75); // rts return 0; }
void VideoInstallAccel(void) { // Install acceleration hooks if (PrefsFindBool("gfxaccel")) { D(bug("Video: Installing acceleration hooks\n")); uint32 base; SheepVar bitblt_hook_info(sizeof(accl_hook_info)); base = bitblt_hook_info.addr(); WriteMacInt32(base + 0, NativeTVECT(NATIVE_NQD_BITBLT_HOOK)); WriteMacInt32(base + 4, NativeTVECT(NATIVE_NQD_SYNC_HOOK)); WriteMacInt32(base + 8, ACCL_BITBLT); NQDMisc(6, bitblt_hook_info.addr()); SheepVar fillrect_hook_info(sizeof(accl_hook_info)); base = fillrect_hook_info.addr(); WriteMacInt32(base + 0, NativeTVECT(NATIVE_NQD_FILLRECT_HOOK)); WriteMacInt32(base + 4, NativeTVECT(NATIVE_NQD_SYNC_HOOK)); WriteMacInt32(base + 8, ACCL_FILLRECT); NQDMisc(6, fillrect_hook_info.addr()); for (int op = 0; op < 8; op++) { switch (op) { case ACCL_BITBLT: case ACCL_FILLRECT: continue; } SheepVar unknown_hook_info(sizeof(accl_hook_info)); base = unknown_hook_info.addr(); WriteMacInt32(base + 0, NativeTVECT(NATIVE_NQD_UNKNOWN_HOOK)); WriteMacInt32(base + 4, NativeTVECT(NATIVE_NQD_SYNC_HOOK)); WriteMacInt32(base + 8, op); NQDMisc(6, unknown_hook_info.addr()); } } }
void ASERDPort::conv_error(struct IOExtSer *io, uint32 dt) { int16 oserr; uint8 cum; BYTE err = io->IOSer.io_Error; if (err == 0 || err == IOERR_NOCMD) { oserr = 0; cum = 0; } else { if (is_parallel) { oserr = (err_mask & framingErr) ? rcvrErr : 0; cum = framingErr; } else { switch (io->IOSer.io_Error) { case SerErr_DetectedBreak: oserr = breakRecd; cum = breakErr; break; case SerErr_ParityErr: oserr = (err_mask & parityErr) ? rcvrErr : 0; cum = parityErr; break; case SerErr_BufOverflow: oserr = (err_mask & swOverrunErr) ? rcvrErr : 0; cum = swOverrunErr; break; case SerErr_LineErr: oserr = (err_mask & hwOverrunErr) ? rcvrErr : 0; cum = hwOverrunErr; break; default: oserr = (err_mask & framingErr) ? rcvrErr : 0; cum = framingErr; break; } } } WriteMacInt32(dt + serdtResult, oserr); cum_errors |= cum; }
bool NQD_bitblt_hook(uint32 p) { D(bug("accl_draw_hook %08x\n", p)); NQD_set_dirty_area(p); // Check if we can accelerate this bitblt if (ReadMacInt32(p + 0x018) + ReadMacInt32(p + 0x128) == 0 && ReadMacInt32(p + 0x130) == 0 && ReadMacInt32(p + acclSrcPixelSize) >= 8 && ReadMacInt32(p + acclSrcPixelSize) == ReadMacInt32(p + acclDestPixelSize) && (int32)(ReadMacInt32(p + acclSrcRowBytes) ^ ReadMacInt32(p + acclDestRowBytes)) >= 0 && // same sign? ReadMacInt32(p + acclTransferMode) == 0 && // srcCopy? (int32)ReadMacInt32(p + 0x15c) > 0) { // Yes, set function pointer WriteMacInt32(p + acclDrawProc, NativeTVECT(NATIVE_NQD_BITBLT)); return true; } return false; }
int16 XSERDPort::status(uint32 pb, uint32 dce, uint16 code) { switch (code) { case kSERDInputCount: { int num; ioctl(fd, FIONREAD, &num); WriteMacInt32(pb + csParam, num); return noErr; } case kSERDStatus: { uint32 p = pb + csParam; WriteMacInt8(p + staCumErrs, cum_errors); cum_errors = 0; WriteMacInt8(p + staXOffSent, 0); WriteMacInt8(p + staXOffHold, 0); WriteMacInt8(p + staRdPend, read_pending); WriteMacInt8(p + staWrPend, write_pending); if (protocol != serial) { WriteMacInt8(p + staCtsHold, 0); WriteMacInt8(p + staDsrHold, 0); WriteMacInt8(p + staModemStatus, dsrEvent | dcdEvent | ctsEvent); } else { unsigned int status; ioctl(fd, TIOCMGET, &status); WriteMacInt8(p + staCtsHold, status & TIOCM_CTS ? 0 : 1); WriteMacInt8(p + staDsrHold, status & TIOCM_DTR ? 0 : 1); WriteMacInt8(p + staModemStatus, (status & TIOCM_DSR ? dsrEvent : 0) | (status & TIOCM_RI ? riEvent : 0) | (status & TIOCM_CD ? dcdEvent : 0) | (status & TIOCM_CTS ? ctsEvent : 0)); } return noErr; } default: printf("WARNING: SerialStatus(): unimplemented status code %d\n", code); return statusErr; } }
__saveds void ASERDPort::serial_func(void) { struct ASERDPort *obj = (ASERDPort *)proc_arg; struct MsgPort *proc_port = NULL, *io_port = NULL, *control_port = NULL; struct IOExtSer *read_io = NULL, *write_io = NULL, *control_io = NULL; uint8 orig_params[sizeof(struct IOExtSer)]; bool opened = false; ULONG io_mask = 0, proc_port_mask = 0; // Default: error occured obj->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 serial.device I/O io_port = CreateMsgPort(); if (io_port == NULL) goto quit; io_mask = 1 << io_port->mp_SigBit; control_port = CreateMsgPort(); if (control_port == NULL) goto quit; // Create IORequests read_io = (struct IOExtSer *)CreateIORequest(io_port, sizeof(struct IOExtSer)); write_io = (struct IOExtSer *)CreateIORequest(io_port, sizeof(struct IOExtSer)); control_io = (struct IOExtSer *)CreateIORequest(control_port, sizeof(struct IOExtSer)); if (read_io == NULL || write_io == NULL || control_io == NULL) goto quit; read_io->IOSer.io_Message.mn_Node.ln_Type = 0; // Avoid CheckIO() bug write_io->IOSer.io_Message.mn_Node.ln_Type = 0; control_io->IOSer.io_Message.mn_Node.ln_Type = 0; // Parse device name char dev_name[256]; ULONG dev_unit; if (sscanf(obj->device_name, "%[^/]/%ld", dev_name, &dev_unit) < 2) goto quit; // Open device if (obj->is_parallel) ((IOExtPar *)read_io)->io_ParFlags = PARF_SHARED; else read_io->io_SerFlags = SERF_SHARED | SERF_7WIRE; if (OpenDevice((UBYTE *) dev_name, dev_unit, (struct IORequest *)read_io, 0) || read_io->IOSer.io_Device == NULL) goto quit; opened = true; // Copy IORequests memcpy(write_io, read_io, sizeof(struct IOExtSer)); memcpy(control_io, read_io, sizeof(struct IOExtSer)); // Attach control_io to control_port and set default values control_io->IOSer.io_Message.mn_ReplyPort = control_port; if (!obj->is_parallel) { control_io->io_CtlChar = SER_DEFAULT_CTLCHAR; control_io->io_RBufLen = 64; control_io->io_ExtFlags = 0; control_io->io_Baud = 9600; control_io->io_BrkTime = 250000; control_io->io_ReadLen = control_io->io_WriteLen = 8; control_io->io_StopBits = 1; control_io->io_SerFlags = SERF_SHARED; control_io->IOSer.io_Command = SDCMD_SETPARAMS; DoIO((struct IORequest *)control_io); memcpy(orig_params, &(control_io->io_CtlChar), (uint8 *)&(control_io->io_Status) - (uint8 *)&(control_io->io_CtlChar)); } // Initialization went well, inform main task obj->proc_port = proc_port; obj->control_io = control_io; obj->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 | io_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 SerMessage *msg; while (msg = (SerMessage *)GetMsg(proc_port)) { D(bug("serial_proc received %08lx\n", msg->what)); switch (msg->what) { case MSG_QUERY: control_io->IOSer.io_Command = SDCMD_QUERY; DoIO((struct IORequest *)control_io); D(bug(" query returned %08lx, actual %08lx\n", control_io->IOSer.io_Error, control_io->IOSer.io_Actual)); break; case MSG_SET_PARAMS: // Only send SDCMD_SETPARAMS when configuration has changed if (memcmp(orig_params, &(control_io->io_CtlChar), (uint8 *)&(control_io->io_Status) - (uint8 *)&(control_io->io_CtlChar))) { memcpy(orig_params, &(control_io->io_CtlChar), (uint8 *)&(control_io->io_Status) - (uint8 *)&(control_io->io_CtlChar)); memcpy(&(read_io->io_CtlChar), &(control_io->io_CtlChar), (uint8 *)&(control_io->io_Status) - (uint8 *)&(control_io->io_CtlChar)); memcpy(&(write_io->io_CtlChar), &(control_io->io_CtlChar), (uint8 *)&(control_io->io_Status) - (uint8 *)&(control_io->io_CtlChar)); control_io->IOSer.io_Command = SDCMD_SETPARAMS; D(bug(" params %08lx %08lx %08lx %08lx %08lx %08lx\n", control_io->io_CtlChar, control_io->io_RBufLen, control_io->io_ExtFlags, control_io->io_Baud, control_io->io_BrkTime, *(uint32 *)((uint8 *)control_io + 76))); DoIO((struct IORequest *)control_io); D(bug(" set_parms returned %08lx\n", control_io->IOSer.io_Error)); } break; case MSG_SET_PAR_PARAMS: control_io->IOSer.io_Command = PDCMD_SETPARAMS; DoIO((struct IORequest *)control_io); D(bug(" set_par_parms returned %08lx\n", control_io->IOSer.io_Error)); break; case MSG_BREAK: control_io->IOSer.io_Command = SDCMD_BREAK; DoIO((struct IORequest *)control_io); D(bug(" break returned %08lx\n", control_io->IOSer.io_Error)); break; case MSG_RESET: control_io->IOSer.io_Command = CMD_RESET; DoIO((struct IORequest *)control_io); D(bug(" reset returned %08lx\n", control_io->IOSer.io_Error)); break; case MSG_KILL_IO: AbortIO((struct IORequest *)read_io); AbortIO((struct IORequest *)write_io); WaitIO((struct IORequest *)read_io); WaitIO((struct IORequest *)write_io); obj->read_pending = obj->write_pending = false; obj->read_done = obj->write_done = false; break; case MSG_PRIME_IN: read_io->IOSer.io_Message.mn_Node.ln_Name = (char *)msg->pb; read_io->IOSer.io_Data = Mac2HostAddr(ReadMacInt32(msg->pb + ioBuffer)); read_io->IOSer.io_Length = ReadMacInt32(msg->pb + ioReqCount); read_io->IOSer.io_Actual = 0; read_io->IOSer.io_Command = CMD_READ; D(bug("serial_proc receiving %ld bytes from %08lx\n", read_io->IOSer.io_Length, read_io->IOSer.io_Data)); SendIO((struct IORequest *)read_io); break; case MSG_PRIME_OUT: { write_io->IOSer.io_Message.mn_Node.ln_Name = (char *)msg->pb; write_io->IOSer.io_Data = Mac2HostAddr(ReadMacInt32(msg->pb + ioBuffer)); write_io->IOSer.io_Length = ReadMacInt32(msg->pb + ioReqCount); write_io->IOSer.io_Actual = 0; write_io->IOSer.io_Command = CMD_WRITE; D(bug("serial_proc transmitting %ld bytes from %08lx\n", write_io->IOSer.io_Length, write_io->IOSer.io_Data)); #if MONITOR bug("Sending serial data:\n"); uint8 *adr = Mac2HostAddr(ReadMacInt32(msg->pb + ioBuffer)); for (int i=0; i<len; i++) { bug("%02lx ", adr[i]); } bug("\n"); #endif SendIO((struct IORequest *)write_io); break; } } D(bug(" serial_proc replying\n")); ReplyMsg(msg); } } // I/O operation completed if (sig & io_mask) { struct IOExtSer *io; while (io = (struct IOExtSer *)GetMsg(io_port)) { if (io == read_io) { D(bug("read_io complete, %ld bytes received, error %ld\n", read_io->IOSer.io_Actual, read_io->IOSer.io_Error)); uint32 pb = (uint32)read_io->IOSer.io_Message.mn_Node.ln_Name; #if MONITOR bug("Receiving serial data:\n"); uint8 *adr = Mac2HostAddr(ReadMacInt32(msg->pb + ioBuffer)); for (int i=0; i<read_io->IOSer.io_Actual; i++) { bug("%02lx ", adr[i]); } bug("\n"); #endif WriteMacInt32(pb + ioActCount, read_io->IOSer.io_Actual); obj->conv_error(read_io, obj->input_dt); obj->read_done = true; SetInterruptFlag(INTFLAG_SERIAL); TriggerInterrupt(); } else if (io == write_io) { D(bug("write_io complete, %ld bytes sent, error %ld\n", write_io->IOSer.io_Actual, write_io->IOSer.io_Error)); uint32 pb = (uint32)write_io->IOSer.io_Message.mn_Node.ln_Name; WriteMacInt32(pb + ioActCount, write_io->IOSer.io_Actual); obj->conv_error(write_io, obj->output_dt); obj->write_done = true; SetInterruptFlag(INTFLAG_SERIAL); TriggerInterrupt(); } } } } quit: // Close everything if (opened) { if (CheckIO((struct IORequest *)write_io) == 0) { AbortIO((struct IORequest *)write_io); WaitIO((struct IORequest *)write_io); } if (CheckIO((struct IORequest *)read_io) == 0) { AbortIO((struct IORequest *)read_io); WaitIO((struct IORequest *)read_io); } CloseDevice((struct IORequest *)read_io); } if (control_io) DeleteIORequest(control_io); if (write_io) DeleteIORequest(write_io); if (read_io) DeleteIORequest(read_io); if (control_port) DeleteMsgPort(control_port); if (io_port) DeleteMsgPort(io_port); // Send signal to main task to confirm termination Forbid(); Signal(MainTask, SIGF_SINGLE); }
static void generate_powerpc_thunks(void) { // check_load_invoc() thunk uint32 check_load_invoc_opcode = NativeOpcode(NATIVE_CHECK_LOAD_INVOC); uint32 base; static uint32 get_resource_template[] = { PL(0x7c0802a6), // mflr r0 PL(0x90010008), // stw r0,8(r1) PL(0x9421ffbc), // stwu r1,-68(r1) PL(0x90610038), // stw r3,56(r1) PL(0x9081003c), // stw r4,60(r1) PL(0x00000000), // lwz r0,XLM_GET_RESOURCE(r0) PL(0x80402834), // lwz r2,XLM_RES_LIB_TOC(r0) PL(0x7c0903a6), // mtctr r0 PL(0x4e800421), // bctrl PL(0x90610040), // stw r3,64(r1) PL(0x80610038), // lwz r3,56(r1) PL(0xa881003e), // lha r4,62(r1) PL(0x80a10040), // lwz r5,64(r1) PL(0x00000001), // <check_load_invoc> PL(0x80610040), // lwz r3,64(r1) PL(0x8001004c), // lwz r0,76(r1) PL(0x7c0803a6), // mtlr r0 PL(0x38210044), // addi r1,r1,68 PL(0x4e800020) // blr }; const uint32 get_resource_template_size = sizeof(get_resource_template); int xlm_index = -1, check_load_invoc_index = -1; for (int i = 0; i < get_resource_template_size/4; i++) { uint32 opcode = ntohl(get_resource_template[i]); switch (opcode) { case 0x00000000: xlm_index = i; break; case 0x00000001: check_load_invoc_index = i; break; } } assert(xlm_index != -1 && check_load_invoc_index != -1); // GetResource() get_resource_func = base = SheepMem::Reserve(get_resource_template_size); Host2Mac_memcpy(base, get_resource_template, get_resource_template_size); WriteMacInt32(base + xlm_index * 4, 0x80000000 | XLM_GET_RESOURCE); WriteMacInt32(base + check_load_invoc_index * 4, check_load_invoc_opcode); // Get1Resource() get_1_resource_func = base = SheepMem::Reserve(get_resource_template_size); Host2Mac_memcpy(base, get_resource_template, get_resource_template_size); WriteMacInt32(base + xlm_index * 4, 0x80000000 | XLM_GET_1_RESOURCE); WriteMacInt32(base + check_load_invoc_index * 4, check_load_invoc_opcode); // GetIndResource() get_ind_resource_func = base = SheepMem::Reserve(get_resource_template_size); Host2Mac_memcpy(base, get_resource_template, get_resource_template_size); WriteMacInt32(base + xlm_index * 4, 0x80000000 | XLM_GET_IND_RESOURCE); WriteMacInt32(base + check_load_invoc_index * 4, check_load_invoc_opcode); // Get1IndResource() get_1_ind_resource_func = base = SheepMem::Reserve(get_resource_template_size); Host2Mac_memcpy(base, get_resource_template, get_resource_template_size); WriteMacInt32(base + xlm_index * 4, 0x80000000 | XLM_GET_1_IND_RESOURCE); WriteMacInt32(base + check_load_invoc_index * 4, check_load_invoc_opcode); // RGetResource() r_get_resource_func = base = SheepMem::Reserve(get_resource_template_size); Host2Mac_memcpy(base, get_resource_template, get_resource_template_size); WriteMacInt32(base + xlm_index * 4, 0x80000000 | XLM_R_GET_RESOURCE); WriteMacInt32(base + check_load_invoc_index * 4, check_load_invoc_opcode); // named_check_load_invoc() thunk check_load_invoc_opcode = NativeOpcode(NATIVE_NAMED_CHECK_LOAD_INVOC); static uint32 get_named_resource_template[] = { PL(0x7c0802a6), // mflr r0 PL(0x90010008), // stw r0,8(r1) PL(0x9421ffbc), // stwu r1,-68(r1) PL(0x90610038), // stw r3,56(r1) PL(0x9081003c), // stw r4,60(r1) PL(0x00000000), // lwz r0,XLM_GET_NAMED_RESOURCE(r0) PL(0x80402834), // lwz r2,XLM_RES_LIB_TOC(r0) PL(0x7c0903a6), // mtctr r0 PL(0x4e800421), // bctrl PL(0x90610040), // stw r3,64(r1) PL(0x80610038), // lwz r3,56(r1) PL(0x8081003c), // lwz r4,60(r1) PL(0x80a10040), // lwz r5,64(r1) PL(0x00000001), // <named_check_load_invoc> PL(0x80610040), // lwz r3,64(r1) PL(0x8001004c), // lwz r0,76(r1) PL(0x7c0803a6), // mtlr r0 PL(0x38210044), // addi r1,r1,68 PL(0x4e800020) // blr }; const uint32 get_named_resource_template_size = sizeof(get_named_resource_template); xlm_index = -1, check_load_invoc_index = -1; for (int i = 0; i < get_resource_template_size/4; i++) { uint32 opcode = ntohl(get_resource_template[i]); switch (opcode) { case 0x00000000: xlm_index = i; break; case 0x00000001: check_load_invoc_index = i; break; } } assert(xlm_index != -1 && check_load_invoc_index != -1); // GetNamedResource() get_named_resource_func = base = SheepMem::Reserve(get_named_resource_template_size); Host2Mac_memcpy(base, get_named_resource_template, get_named_resource_template_size); WriteMacInt32(base + xlm_index * 4, 0x80000000 | XLM_GET_NAMED_RESOURCE); WriteMacInt32(base + check_load_invoc_index * 4, check_load_invoc_opcode); // Get1NamedResource() get_1_named_resource_func = base = SheepMem::Reserve(get_named_resource_template_size); Host2Mac_memcpy(base, get_named_resource_template, get_named_resource_template_size); WriteMacInt32(base + xlm_index * 4, 0x80000000 | XLM_GET_1_NAMED_RESOURCE); WriteMacInt32(base + check_load_invoc_index * 4, check_load_invoc_opcode); }
bool ThunksInit(void) { #if EMULATED_PPC for (int i = 0; i < NATIVE_OP_MAX; i++) { uintptr base = SheepMem::Reserve(16); WriteMacInt32(base + 0, base + 8); WriteMacInt32(base + 4, 0); // Fake TVECT WriteMacInt32(base + 8, NativeOpcode(i)); WriteMacInt32(base + 12, POWERPC_BLR); native_op[i].tvect = base; native_op[i].func = base + 8; } #if POWERPC_GET_RESOURCE_THUNKS generate_powerpc_thunks(); native_op[NATIVE_GET_RESOURCE].func = get_resource_func; native_op[NATIVE_GET_1_RESOURCE].func = get_1_resource_func; native_op[NATIVE_GET_IND_RESOURCE].func = get_ind_resource_func; native_op[NATIVE_GET_1_IND_RESOURCE].func = get_1_ind_resource_func; native_op[NATIVE_R_GET_RESOURCE].func = r_get_resource_func; native_op[NATIVE_GET_NAMED_RESOURCE].func = get_named_resource_func; native_op[NATIVE_GET_1_NAMED_RESOURCE].func = get_1_named_resource_func; #endif #else #if defined(__linux__) || defined(__NetBSD__) || (defined(__APPLE__) && defined(__MACH__)) #define DEFINE_NATIVE_OP(ID, FUNC) do { \ uintptr base = SheepMem::Reserve(8); \ WriteMacInt32(base + 0, (uint32)FUNC); \ WriteMacInt32(base + 4, (uint32)TOC); \ native_op[ID].tvect = base; \ native_op[ID].func = (uint32)FUNC; \ } while (0) #elif defined(__BEOS__) #define DEFINE_NATIVE_OP(ID, FUNC) do { \ native_op[ID].tvect = FUNC; \ native_op[ID].func = ((uint32 *)FUNC)[0]; \ } while (0) #else #error "FIXME: define NativeOp for your platform" #endif // FIXME: add GetResource() and friends for completeness DEFINE_NATIVE_OP(NATIVE_PATCH_NAME_REGISTRY, DoPatchNameRegistry); DEFINE_NATIVE_OP(NATIVE_VIDEO_INSTALL_ACCEL, VideoInstallAccel); DEFINE_NATIVE_OP(NATIVE_VIDEO_VBL, VideoVBL); DEFINE_NATIVE_OP(NATIVE_VIDEO_DO_DRIVER_IO, VideoDoDriverIO); DEFINE_NATIVE_OP(NATIVE_ETHER_AO_GET_HWADDR, AO_get_ethernet_address); DEFINE_NATIVE_OP(NATIVE_ETHER_AO_ADD_MULTI, AO_enable_multicast); DEFINE_NATIVE_OP(NATIVE_ETHER_AO_DEL_MULTI, AO_disable_multicast); DEFINE_NATIVE_OP(NATIVE_ETHER_AO_SEND_PACKET, AO_transmit_packet); DEFINE_NATIVE_OP(NATIVE_ETHER_IRQ, EtherIRQ); DEFINE_NATIVE_OP(NATIVE_ETHER_INIT, InitStreamModule); DEFINE_NATIVE_OP(NATIVE_ETHER_TERM, TerminateStreamModule); DEFINE_NATIVE_OP(NATIVE_ETHER_OPEN, ether_open); DEFINE_NATIVE_OP(NATIVE_ETHER_CLOSE, ether_close); DEFINE_NATIVE_OP(NATIVE_ETHER_WPUT, ether_wput); DEFINE_NATIVE_OP(NATIVE_ETHER_RSRV, ether_rsrv); DEFINE_NATIVE_OP(NATIVE_SERIAL_NOTHING, SerialNothing); DEFINE_NATIVE_OP(NATIVE_SERIAL_OPEN, SerialOpen); DEFINE_NATIVE_OP(NATIVE_SERIAL_PRIME_IN, SerialPrimeIn); DEFINE_NATIVE_OP(NATIVE_SERIAL_PRIME_OUT, SerialPrimeOut); DEFINE_NATIVE_OP(NATIVE_SERIAL_CONTROL, SerialControl); DEFINE_NATIVE_OP(NATIVE_SERIAL_STATUS, SerialStatus); DEFINE_NATIVE_OP(NATIVE_SERIAL_CLOSE, SerialClose); DEFINE_NATIVE_OP(NATIVE_MAKE_EXECUTABLE, MakeExecutable); DEFINE_NATIVE_OP(NATIVE_NQD_SYNC_HOOK, NQD_sync_hook); DEFINE_NATIVE_OP(NATIVE_NQD_BITBLT_HOOK, NQD_bitblt_hook); DEFINE_NATIVE_OP(NATIVE_NQD_FILLRECT_HOOK, NQD_fillrect_hook); DEFINE_NATIVE_OP(NATIVE_NQD_UNKNOWN_HOOK, NQD_unknown_hook); DEFINE_NATIVE_OP(NATIVE_NQD_BITBLT, NQD_bitblt); DEFINE_NATIVE_OP(NATIVE_NQD_INVRECT, NQD_invrect); DEFINE_NATIVE_OP(NATIVE_NQD_FILLRECT, NQD_fillrect); #undef DEFINE_NATIVE_OP #endif // Initialize routine descriptors (if TVECT exists) for (int i = 0; i < NATIVE_OP_MAX; i++) { uint32 tvect = native_op[i].tvect; if (tvect) native_op[i].desc = new SheepRoutineDescriptor(0, tvect); } return true; }
void EnableInterrupt(void) { WriteMacInt32(XLM_IRQ_NEST, int32(ReadMacInt32(XLM_IRQ_NEST)) - 1); }
void DisableInterrupt(void) { WriteMacInt32(XLM_IRQ_NEST, int32(ReadMacInt32(XLM_IRQ_NEST)) + 1); }
int16 PrimeTime(uint32 tm, int32 time) { D(bug("PrimeTime %08lx, time %ld\n", tm, time)); // Find descriptor TMDesc *desc = find_desc(tm); if (!desc) { printf("FATAL: PrimeTime(%08lx): Descriptor not found\n", (long unsigned int)tm); return 0; } // Convert delay time tm_time_t delay; timer_mac2host_time(delay, time); // Extended task? if (ReadMacInt16(tm + qType) & 0x4000) { // Yes, tmWakeUp set? if (ReadMacInt32(tm + tmWakeUp)) { // PrimeTime(0) can either mean (a) "the task runs as soon as interrupts are enabled" // or (b) "continue previous delay" if an expired task was stopped via RmvTime() and // then re-installed using InsXTime(). Since tmWakeUp was set, this is case (b). // The remaining time was saved in tmCount by RmvTime(). if (time == 0) { timer_mac2host_time(delay, ReadMacInt16(tm + tmCount)); } // Yes, calculate wakeup time relative to last scheduled time tm_time_t wakeup; timer_add_time(wakeup, desc->wakeup, delay); desc->wakeup = wakeup; } else { // No, calculate wakeup time relative to current time tm_time_t now; timer_current_time(now); timer_add_time(desc->wakeup, now, delay); } // Set tmWakeUp to indicate that task was scheduled WriteMacInt32(tm + tmWakeUp, 0x12345678); } else { // Not extended task, calculate wakeup time relative to current time tm_time_t now; timer_current_time(now); timer_add_time(desc->wakeup, now, delay); } // Make task active and enqueue it in the Time Manager queue #if PRECISE_TIMING_BEOS while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ; suspend_thread(timer_thread); #endif #ifdef PRECISE_TIMING_MACH semaphore_wait(wakeup_time_sem); thread_suspend(timer_thread); #endif #if PRECISE_TIMING_POSIX timer_thread_suspend(); pthread_mutex_lock(&wakeup_time_lock); #endif WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) | 0x8000); enqueue_tm(tm); #if PRECISE_TIMING // Look for next task to be called and set wakeup_time wakeup_time = wakeup_time_max; for (TMDesc *d = tmDescList; d; d = d->next) if ((ReadMacInt16(d->task + qType) & 0x8000)) if (timer_cmp_time(d->wakeup, wakeup_time) < 0) wakeup_time = d->wakeup; #ifdef PRECISE_TIMING_BEOS release_sem(wakeup_time_sem); thread_info info; do { resume_thread(timer_thread); // This will unblock the thread get_thread_info(timer_thread, &info); } while (info.state == B_THREAD_SUSPENDED); // Sometimes, resume_thread() doesn't work (BeOS bug?) #endif #ifdef PRECISE_TIMING_MACH semaphore_signal(wakeup_time_sem); thread_abort(timer_thread); thread_resume(timer_thread); #endif #ifdef PRECISE_TIMING_POSIX pthread_mutex_unlock(&wakeup_time_lock); timer_thread_resume(); assert(suspend_count == 0); #endif #endif return 0; }
int16 RmvTime(uint32 tm) { D(bug("RmvTime %08lx\n", tm)); // Find descriptor TMDesc *desc = find_desc(tm); if (!desc) { printf("WARNING: RmvTime(%08lx): Descriptor not found\n", (long unsigned int)tm); return 0; } // Task active? #if PRECISE_TIMING_BEOS while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ; suspend_thread(timer_thread); #endif #ifdef PRECISE_TIMING_MACH semaphore_wait(wakeup_time_sem); thread_suspend(timer_thread); #endif #if PRECISE_TIMING_POSIX timer_thread_suspend(); pthread_mutex_lock(&wakeup_time_lock); #endif if (ReadMacInt16(tm + qType) & 0x8000) { // Yes, make task inactive and remove it from the Time Manager queue WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) & 0x7fff); dequeue_tm(tm); #if PRECISE_TIMING // Look for next task to be called and set wakeup_time wakeup_time = wakeup_time_max; for (TMDesc *d = tmDescList; d; d = d->next) if ((ReadMacInt16(d->task + qType) & 0x8000)) if (timer_cmp_time(d->wakeup, wakeup_time) < 0) wakeup_time = d->wakeup; #endif // Compute remaining time tm_time_t remaining, current; timer_current_time(current); timer_sub_time(remaining, desc->wakeup, current); WriteMacInt32(tm + tmCount, timer_host2mac_time(remaining)); } else WriteMacInt32(tm + tmCount, 0); D(bug(" tmCount %ld\n", ReadMacInt32(tm + tmCount))); #if PRECISE_TIMING_BEOS release_sem(wakeup_time_sem); thread_info info; do { resume_thread(timer_thread); // This will unblock the thread get_thread_info(timer_thread, &info); } while (info.state == B_THREAD_SUSPENDED); // Sometimes, resume_thread() doesn't work (BeOS bug?) #endif #ifdef PRECISE_TIMING_MACH semaphore_signal(wakeup_time_sem); thread_abort(timer_thread); thread_resume(timer_thread); #endif #if PRECISE_TIMING_POSIX pthread_mutex_unlock(&wakeup_time_lock); timer_thread_resume(); assert(suspend_count == 0); #endif // Free descriptor free_desc(desc); return 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); }