void set_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir) { // Open file int fd = open(path, O_WRONLY); if (fd < 0) return; if (!is_dir) { // Set BEOS:TYPE attribute uint32 type = ReadMacInt32(finfo + fdType); if (type) { for (int i=0; m2t_translation[i].mime; i++) { if (m2t_translation[i].type == type && m2t_translation[i].reversible) { fs_write_attr(fd, "BEOS:TYPE", B_MIME_STRING_TYPE, 0, m2t_translation[i].mime, strlen(m2t_translation[i].mime) + 1); break; } } } // Set MACOS:CREATOR attribute uint32 creator = ReadMacInt32(finfo + fdCreator); if (creator) { tmp_buf[0] = creator >> 24; tmp_buf[1] = creator >> 16; tmp_buf[2] = creator >> 8; tmp_buf[3] = creator; fs_write_attr(fd, "MACOS:CREATOR", B_UINT32_TYPE, 0, tmp_buf, 4); } }
static __saveds __regargs LONG copy_from_buff(uint8 *to /*a0*/, char *wds /*a1*/, uint32 packet_len /*d0*/) { D(bug("CopyFromBuff to %08lx, wds %08lx, size %08lx\n", to, wds, packet_len)); #if MONITOR bug("Sending Ethernet packet:\n"); #endif for (;;) { int len = ReadMacInt16((uint32)wds); if (len == 0) break; #if MONITOR uint8 *adr = Mac2HostAddr(ReadMacInt32((uint32)wds + 2)); for (int i=0; i<len; i++) { bug("%02lx ", adr[i]); } #endif CopyMem(Mac2HostAddr(ReadMacInt32((uint32)wds + 2)), to, len); to += len; wds += 6; } #if MONITOR bug("\n"); #endif return 1; }
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 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 *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; }
static bool is_drive_number_free(int num) { uint32 e = ReadMacInt32(0x308 + qHead); while (e) { uint32 d = e - dsQLink; if ((int)ReadMacInt16(d + dsQDrive) == num) return false; e = ReadMacInt32(e + qLink); } return true; }
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 }
int16 ether_write(uint32 wds) { // Set source address uint32 hdr = ReadMacInt32(wds + 2); memcpy(Mac2HostAddr(hdr + 6), ether_addr, 6); return noErr; }
void TimerInterrupt(void) { // Look for active TMTasks that have expired tm_time_t now; timer_current_time(now); for (int i=0; i<NUM_DESCS; i++) if (desc[i].in_use) { uint32 tm = desc[i].task; if ((ReadMacInt16(tm + qType) & 0x8000) && timer_cmp_time(desc[i].wakeup, now) < 0) { // Found one, mark as inactive and remove it from the Time Manager queue WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) & 0x7fff); dequeue_tm(tm); // Call timer function uint32 addr = ReadMacInt32(tm + tmAddr); if (addr) { D(bug("Calling TimeTask %08lx, addr %08lx\n", tm, addr)); M68kRegisters r; r.a[0] = addr; r.a[1] = tm; Execute68k(addr, &r); } } } }
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; }
// Dispatch packet to protocol handler static void ether_dispatch_packet(uint32 packet, uint32 length) { // Get packet type uint16 type = ReadMacInt16(packet + 12); // Look for protocol NetProtocol *prot = find_protocol(type); if (prot == NULL) return; // No default handler if (prot->handler == 0) return; // Copy header to RHA Mac2Mac_memcpy(ether_data + ed_RHA, packet, 14); D(bug(" header %08lx%04lx %08lx%04lx %04lx\n", ReadMacInt32(ether_data + ed_RHA), ReadMacInt16(ether_data + ed_RHA + 4), ReadMacInt32(ether_data + ed_RHA + 6), ReadMacInt16(ether_data + ed_RHA + 10), ReadMacInt16(ether_data + ed_RHA + 12))); // Call protocol handler M68kRegisters r; r.d[0] = type; // Packet type r.d[1] = length - 14; // Remaining packet length (without header, for ReadPacket) r.a[0] = packet + 14; // Pointer to packet (Mac address, for ReadPacket) r.a[3] = ether_data + ed_RHA + 14; // Pointer behind header in RHA r.a[4] = ether_data + ed_ReadPacket; // Pointer to ReadPacket/ReadRest routines D(bug(" calling protocol handler %08lx, type %08lx, length %08lx, data %08lx, rha %08lx, read_packet %08lx\n", prot->handler, r.d[0], r.d[1], r.a[0], r.a[3], r.a[4])); Execute68k(prot->handler, &r); }
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; }
// Pass-through dirty areas to redraw functions static inline void NQD_set_dirty_area(uint32 p) { if (ReadMacInt32(p + acclDestBaseAddr) == screen_base) { int16 x = (int16)ReadMacInt16(p + acclDestRect + 2) - (int16)ReadMacInt16(p + acclDestBoundsRect + 2); int16 y = (int16)ReadMacInt16(p + acclDestRect + 0) - (int16)ReadMacInt16(p + acclDestBoundsRect + 0); int16 w = (int16)ReadMacInt16(p + acclDestRect + 6) - (int16)ReadMacInt16(p + acclDestRect + 2); int16 h = (int16)ReadMacInt16(p + acclDestRect + 4) - (int16)ReadMacInt16(p + acclDestRect + 0); video_set_dirty_area(x, y, w, h); } }
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; }
void set_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir) { struct utimbuf times; times.actime = MacTimeToTime(ReadMacInt32(finfo - ioFlFndrInfo + ioFlCrDat)); times.modtime = MacTimeToTime(ReadMacInt32(finfo - ioFlFndrInfo + ioFlMdDat)); if (utime(path, ×) < 0) { D(bug("utime failed on %s\n", path)); } // Open Finder info file int fd = open_finf(path, O_RDWR); if (fd < 0) return; // Write file write(fd, Mac2HostAddr(finfo), SIZEOF_FInfo); if (fxinfo) write(fd, Mac2HostAddr(fxinfo), SIZEOF_FXInfo); close(fd); }
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; }
void NQD_invrect(uint32 p) { D(bug("accl_invrect %08x\n", p)); // Get inversion parameters int16 dest_X = (int16)ReadMacInt16(p + acclDestRect + 2) - (int16)ReadMacInt16(p + acclDestBoundsRect + 2); int16 dest_Y = (int16)ReadMacInt16(p + acclDestRect + 0) - (int16)ReadMacInt16(p + acclDestBoundsRect + 0); int16 width = (int16)ReadMacInt16(p + acclDestRect + 6) - (int16)ReadMacInt16(p + acclDestRect + 2); int16 height = (int16)ReadMacInt16(p + acclDestRect + 4) - (int16)ReadMacInt16(p + acclDestRect + 0); D(bug(" dest X %d, dest Y %d\n", dest_X, dest_Y)); D(bug(" width %d, height %d, bytes_per_row %d\n", width, height, (int32)ReadMacInt32(p + acclDestRowBytes))); //!!?? pen_mode == 14 // And perform the inversion const int bpp = bytes_per_pixel(ReadMacInt32(p + acclDestPixelSize)); const int dest_row_bytes = (int32)ReadMacInt32(p + acclDestRowBytes); uint8 *dest = Mac2HostAddr(ReadMacInt32(p + acclDestBaseAddr) + (dest_Y * dest_row_bytes) + (dest_X * bpp)); width *= bpp; switch (bpp) { case 1: for (int i = 0; i < height; i++) { do_invrect<8>(dest, width); dest += dest_row_bytes; } break; case 2: for (int i = 0; i < height; i++) { do_invrect<16>(dest, width); dest += dest_row_bytes; } break; case 4: for (int i = 0; i < height; i++) { do_invrect<32>(dest, width); dest += dest_row_bytes; } break; } }
void EtherInterrupt(void) { D(bug("EtherIRQ\n")); // Packet write done, enqueue DT to call IODone if (write_done) { EnqueueMac(ether_data + ed_DeferredTask, 0xd92); write_done = false; } // Call protocol handler for received packets IOSana2Req *io; while (io = (struct IOSana2Req *)GetMsg(read_port)) { // Get pointer to NetProtocol (hidden in node name) NetProtocol *p = (NetProtocol *)io->ios2_Req.io_Message.mn_Node.ln_Name; // No default handler if (p->handler == 0) continue; // Copy header to RHA Host2Mac_memcpy(ether_data + ed_RHA, io->ios2_Data, 14); D(bug(" header %08lx%04lx %08lx%04lx %04lx\n", ReadMacInt32(ether_data + ed_RHA), ReadMacInt16(ether_data + ed_RHA + 4), ReadMacInt32(ether_data + ed_RHA + 6), ReadMacInt16(ether_data + ed_RHA + 10), ReadMacInt16(ether_data + ed_RHA + 12))); // Call protocol handler M68kRegisters r; r.d[0] = *(uint16 *)((uint32)io->ios2_Data + 12); // Packet type r.d[1] = io->ios2_DataLength - 18; // Remaining packet length (without header, for ReadPacket) (-18 because the CRC is also included) r.a[0] = (uint32)io->ios2_Data + 14; // Pointer to packet (host address, for ReadPacket) r.a[3] = ether_data + ed_RHA + 14; // Pointer behind header in RHA r.a[4] = ether_data + ed_ReadPacket; // Pointer to ReadPacket/ReadRest routines D(bug(" calling protocol handler %08lx, type %08lx, length %08lx, data %08lx, rha %08lx, read_packet %08lx\n", p->handler, r.d[0], r.d[1], r.a[0], r.a[3], r.a[4])); Execute68k(p->handler, &r); // Resend IORequest io->ios2_Req.io_Flags = SANA2IOF_RAW; BeginIO((struct IORequest *)io); } D(bug(" EtherIRQ done\n")); }
void NQD_fillrect(uint32 p) { D(bug("accl_fillrect %08x\n", p)); // Get filling parameters int16 dest_X = (int16)ReadMacInt16(p + acclDestRect + 2) - (int16)ReadMacInt16(p + acclDestBoundsRect + 2); int16 dest_Y = (int16)ReadMacInt16(p + acclDestRect + 0) - (int16)ReadMacInt16(p + acclDestBoundsRect + 0); int16 width = (int16)ReadMacInt16(p + acclDestRect + 6) - (int16)ReadMacInt16(p + acclDestRect + 2); int16 height = (int16)ReadMacInt16(p + acclDestRect + 4) - (int16)ReadMacInt16(p + acclDestRect + 0); uint32 color = htonl(ReadMacInt32(p + acclPenMode) == 8 ? ReadMacInt32(p + acclForePen) : ReadMacInt32(p + acclBackPen)); D(bug(" dest X %d, dest Y %d\n", dest_X, dest_Y)); D(bug(" width %d, height %d\n", width, height)); D(bug(" bytes_per_row %d color %08x\n", (int32)ReadMacInt32(p + acclDestRowBytes), color)); // And perform the fill const int bpp = bytes_per_pixel(ReadMacInt32(p + acclDestPixelSize)); const int dest_row_bytes = (int32)ReadMacInt32(p + acclDestRowBytes); uint8 *dest = Mac2HostAddr(ReadMacInt32(p + acclDestBaseAddr) + (dest_Y * dest_row_bytes) + (dest_X * bpp)); width *= bpp; switch (bpp) { case 1: for (int i = 0; i < height; i++) { memset(dest, color, width); dest += dest_row_bytes; } break; case 2: for (int i = 0; i < height; i++) { do_fillrect<16>(dest, color, width); dest += dest_row_bytes; } break; case 4: for (int i = 0; i < height; i++) { do_fillrect<32>(dest, color, width); dest += dest_row_bytes; } break; } }
void TimerInterrupt(void) { // D(bug("TimerIRQ\n")); // Look for active TMTasks that have expired tm_time_t now; timer_current_time(now); TMDesc *desc = tmDescList; while (desc) { TMDesc *next = desc->next; uint32 tm = desc->task; if ((ReadMacInt16(tm + qType) & 0x8000) && timer_cmp_time(desc->wakeup, now) <= 0) { // Found one, mark as inactive and remove it from the Time Manager queue WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) & 0x7fff); dequeue_tm(tm); // Call timer function uint32 addr = ReadMacInt32(tm + tmAddr); if (addr) { D(bug("Calling TimeTask %08lx, addr %08lx\n", tm, addr)); M68kRegisters r; r.a[0] = addr; r.a[1] = tm; Execute68k(r.a[0], &r); D(bug(" returned from TimeTask\n")); } } desc = next; } #if PRECISE_TIMING // Look for next task to be called and set wakeup_time #if PRECISE_TIMING_BEOS while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ; suspend_thread(timer_thread); #endif #if 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 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; #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 #if 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 #endif }
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; }
int16 EtherControl(uint32 pb, uint32 dce) { uint16 code = ReadMacInt16(pb + csCode); D(bug("EtherControl %d\n", code)); switch (code) { case 1: // KillIO return -1; case kENetAddMulti: // Add multicast address D(bug("AddMulti %08lx%04x\n", ReadMacInt32(pb + eMultiAddr), ReadMacInt16(pb + eMultiAddr + 4))); if (net_open) return ether_add_multicast(pb); else return noErr; case kENetDelMulti: // Delete multicast address D(bug("DelMulti %08lx%04x\n", ReadMacInt32(pb + eMultiAddr), ReadMacInt16(pb + eMultiAddr + 4))); if (net_open) return ether_del_multicast(pb); else return noErr; case kENetAttachPH: // Attach protocol handler D(bug("AttachPH prot %04x, handler %08lx\n", ReadMacInt16(pb + eProtType), ReadMacInt32(pb + ePointer))); if (net_open) return ether_attach_ph(ReadMacInt16(pb + eProtType), ReadMacInt32(pb + ePointer)); else return noErr; case kENetDetachPH: // Detach protocol handler D(bug("DetachPH prot %04x\n", ReadMacInt16(pb + eProtType))); if (net_open) return ether_detach_ph(ReadMacInt16(pb + eProtType)); else return noErr; case kENetWrite: // Transmit raw Ethernet packet D(bug("EtherWrite\n")); if (ReadMacInt16(ReadMacInt32(pb + ePointer)) < 14) return eLenErr; // Header incomplete if (net_open) return ether_write(ReadMacInt32(pb + ePointer)); else return noErr; case kENetGetInfo: { // Get device information/statistics D(bug("GetInfo buf %08lx, size %d\n", ReadMacInt32(pb + ePointer), ReadMacInt16(pb + eBuffSize))); // Collect info (only ethernet address) uint8 buf[18]; memset(buf, 0, 18); memcpy(buf, ether_addr, 6); // Transfer info to supplied buffer int16 size = ReadMacInt16(pb + eBuffSize); if (size > 18) size = 18; WriteMacInt16(pb + eDataSize, size); // Number of bytes actually written Host2Mac_memcpy(ReadMacInt32(pb + ePointer), buf, size); return noErr; } case kENetSetGeneral: // Set general mode (always in general mode) D(bug("SetGeneral\n")); return noErr; default: printf("WARNING: Unknown EtherControl(%d)\n", code); return controlErr; } }
void NQD_bitblt(uint32 p) { D(bug("accl_bitblt %08x\n", p)); // Get blitting parameters int16 src_X = (int16)ReadMacInt16(p + acclSrcRect + 2) - (int16)ReadMacInt16(p + acclSrcBoundsRect + 2); int16 src_Y = (int16)ReadMacInt16(p + acclSrcRect + 0) - (int16)ReadMacInt16(p + acclSrcBoundsRect + 0); int16 dest_X = (int16)ReadMacInt16(p + acclDestRect + 2) - (int16)ReadMacInt16(p + acclDestBoundsRect + 2); int16 dest_Y = (int16)ReadMacInt16(p + acclDestRect + 0) - (int16)ReadMacInt16(p + acclDestBoundsRect + 0); int16 width = (int16)ReadMacInt16(p + acclDestRect + 6) - (int16)ReadMacInt16(p + acclDestRect + 2); int16 height = (int16)ReadMacInt16(p + acclDestRect + 4) - (int16)ReadMacInt16(p + acclDestRect + 0); D(bug(" src addr %08x, dest addr %08x\n", ReadMacInt32(p + acclSrcBaseAddr), ReadMacInt32(p + acclDestBaseAddr))); D(bug(" src X %d, src Y %d, dest X %d, dest Y %d\n", src_X, src_Y, dest_X, dest_Y)); D(bug(" width %d, height %d\n", width, height)); // And perform the blit const int bpp = bytes_per_pixel(ReadMacInt32(p + acclSrcPixelSize)); width *= bpp; if ((int32)ReadMacInt32(p + acclSrcRowBytes) > 0) { const int src_row_bytes = (int32)ReadMacInt32(p + acclSrcRowBytes); const int dst_row_bytes = (int32)ReadMacInt32(p + acclDestRowBytes); uint8 *src = Mac2HostAddr(ReadMacInt32(p + acclSrcBaseAddr) + (src_Y * src_row_bytes) + (src_X * bpp)); uint8 *dst = Mac2HostAddr(ReadMacInt32(p + acclDestBaseAddr) + (dest_Y * dst_row_bytes) + (dest_X * bpp)); for (int i = 0; i < height; i++) { memmove(dst, src, width); src += src_row_bytes; dst += dst_row_bytes; } } else { const int src_row_bytes = -(int32)ReadMacInt32(p + acclSrcRowBytes); const int dst_row_bytes = -(int32)ReadMacInt32(p + acclDestRowBytes); uint8 *src = Mac2HostAddr(ReadMacInt32(p + acclSrcBaseAddr) + ((src_Y + height - 1) * src_row_bytes) + (src_X * bpp)); uint8 *dst = Mac2HostAddr(ReadMacInt32(p + acclDestBaseAddr) + ((dest_Y + height - 1) * dst_row_bytes) + (dest_X * bpp)); for (int i = height - 1; i >= 0; i--) { memmove(dst, src, width); src -= src_row_bytes; dst -= dst_row_bytes; } } }
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); }
uint32 FindLibSymbol(const char *lib_str, const char *sym_str) { SheepVar32 conn_id = 0; SheepVar32 main_addr = 0; SheepArray<256> err; WriteMacInt8(err.addr(), 0); SheepVar32 sym_addr = 0; SheepVar32 sym_class = 0; SheepString lib(lib_str); SheepString sym(sym_str); D(bug("FindLibSymbol %s in %s...\n", sym.value()+1, lib.value()+1)); if (ReadMacInt32(XLM_RUN_MODE) == MODE_EMUL_OP) { M68kRegisters r; // Find shared library static const uint8 proc1_template[] = { 0x55, 0x8f, // subq.l #2,a7 0x2f, 0x08, // move.l a0,-(a7) 0x2f, 0x3c, 0x70, 0x77, 0x70, 0x63, // move.l #'pwpc',-(a7) 0x2f, 0x3c, 0x00, 0x00, 0x00, 0x01, // move.l #kReferenceCFrag,-(a7) 0x2f, 0x09, // move.l a1,-(a7) 0x2f, 0x0a, // move.l a2,-(a7) 0x2f, 0x0b, // move.l a3,-(a7) 0x3f, 0x3c, 0x00, 0x01, // (GetSharedLibrary) 0xaa, 0x5a, // CFMDispatch 0x30, 0x1f, // move.w (a7)+,d0 M68K_RTS >> 8, M68K_RTS & 0xff }; BUILD_SHEEPSHAVER_PROCEDURE(proc1); r.a[0] = lib.addr(); r.a[1] = conn_id.addr(); r.a[2] = main_addr.addr(); r.a[3] = err.addr(); Execute68k(proc1, &r); D(bug(" GetSharedLibrary: ret %d, connection ID %ld, main %p\n", (int16)r.d[0], conn_id.value(), main_addr.value())); if (r.d[0]) return 0; // Find symbol static const uint8 proc2_template[] = { 0x55, 0x8f, // subq.l #2,a7 0x2f, 0x00, // move.l d0,-(a7) 0x2f, 0x08, // move.l a0,-(a7) 0x2f, 0x09, // move.l a1,-(a7) 0x2f, 0x0a, // move.l a2,-(a7) 0x3f, 0x3c, 0x00, 0x05, // (FindSymbol) 0xaa, 0x5a, // CFMDispatch 0x30, 0x1f, // move.w (a7)+,d0 M68K_RTS >> 8, M68K_RTS & 0xff }; BUILD_SHEEPSHAVER_PROCEDURE(proc2); r.d[0] = conn_id.value(); r.a[0] = sym.addr(); r.a[1] = sym_addr.addr(); r.a[2] = sym_class.addr(); Execute68k(proc2, &r); D(bug(" FindSymbol1: ret %d, sym_addr %p, sym_class %ld\n", (int16)r.d[0], sym_addr.value(), sym_class.value())); //!! CloseConnection()? if (r.d[0]) return 0; else return sym_addr.value(); } else {
__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 __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); }