void ethernet_trigger (struct netdriverdata *ndd, void *vsd) { if (!ndd) return; switch (ndd->type) { case UAENET_SLIRP: case UAENET_SLIRP_INBOUND: { struct ethernet_data *ed = (struct ethernet_data*)vsd; if (slirp_data) { uae_u8 pkt[4000]; int len = sizeof pkt; int v; uae_sem_wait (&slirp_sem1); v = slirp_data->getfunc(ed->userdata, pkt, &len); uae_sem_post (&slirp_sem1); if (v) { uae_sem_wait (&slirp_sem2); slirp_input(pkt, len); uae_sem_post (&slirp_sem2); } } } return; #ifdef WITH_UAENET_PCAP case UAENET_PCAP: uaenet_trigger (vsd); return; #endif } }
static int fetch_geometry (struct dev_info_ioctl *ciw, int unitnum, struct device_info *di) { DISK_GEOMETRY geom; DWORD len; int cnt = 3; if (!open_createfile (ciw, 0)) return 0; uae_sem_wait (&ciw->sub_sem); seterrormode (ciw); while (cnt-- > 0) { if (!DeviceIoControl (ciw->h, IOCTL_CDROM_GET_DRIVE_GEOMETRY, NULL, 0, &geom, sizeof (geom), &len, NULL)) { DWORD err = GetLastError (); if (err == ERROR_WRONG_DISK) { if (win32_error (ciw, unitnum, _T("IOCTL_CDROM_GET_DRIVE_GEOMETRY")) < 0) continue; } reseterrormode (ciw); uae_sem_post (&ciw->sub_sem); return 0; } break; } reseterrormode (ciw); uae_sem_post (&ciw->sub_sem); if (di) { di->cylinders = geom.Cylinders.LowPart; di->sectorspertrack = geom.SectorsPerTrack; di->trackspercylinder = geom.TracksPerCylinder; di->bytespersector = geom.BytesPerSector; } return 1; }
static int32_t release_async_request (struct devstruct *dev, uaecptr request) { struct asyncreq *ar, *prevar; uae_sem_wait (&async_sem); ar = dev->ar; prevar = NULL; while (ar) { if (ar->request == request) { if (prevar == NULL) dev->ar = ar->next; else prevar->next = ar->next; uae_sem_post (&async_sem); xfree (ar); if (log_uaeserial) write_log (_T("%s:%d async request %x removed\n"), getdevname(), dev->unit, request); return 1; } prevar = ar; ar = ar->next; } uae_sem_post (&async_sem); write_log (_T("%s:%d async request %x not found for removal!\n"), getdevname(), dev->unit, request); return 0; }
static void *dev_thread (void *devs) { struct devstruct *dev = (struct devstruct*)devs; uae_set_thread_priority (2); dev->thread_running = 1; uae_sem_post (&dev->sync_sem); for (;;) { uaecptr request = (uaecptr)read_comm_pipe_u32_blocking (&dev->requests); uae_sem_wait (&change_sem); if (!request) { dev->thread_running = 0; uae_sem_post (&dev->sync_sem); uae_sem_post (&change_sem); return 0; } else if (get_async_request (dev, request, 1)) { uae_ReplyMsg (request); release_async_request (dev, request); } else if (dev_do_io (dev, request, 0) == 0) { uae_ReplyMsg (request); } else { add_async_request (dev, request); uaeser_trigger (dev->sysdata); } uae_sem_post (&change_sem); } return 0; }
static void *dev_thread (void *devs) { struct s2devstruct *dev = (struct s2devstruct*)devs; uae_set_thread_priority (NULL, 1); dev->thread_running = 1; uae_sem_post (&dev->sync_sem); for (;;) { uaecptr request = (uaecptr)read_comm_pipe_u32_blocking (&dev->requests); uae_sem_wait (&change_sem); if (!request) { dev->thread_running = 0; uae_sem_post (&dev->sync_sem); uae_sem_post (&change_sem); write_log (_T("%s: dev_thread killed\n"), getdevname ()); return 0; } else if (get_async_request (dev, request, 1)) { uae_ReplyMsg (request); release_async_request (dev, request); rem_async_packet (dev, request); } else if (dev_do_io (dev, request, 0) == 0) { uae_ReplyMsg (request); rem_async_packet (dev, request); } else { add_async_request (dev, request); ethernet_trigger (dev->sysdata); } uae_sem_post (&change_sem); } return 0; }
static void *uaenet_trap_threadr (void *arg) { struct uaenetdatawin32 *sd = (struct uaenetdatawin32*)arg; struct pcap_pkthdr *header; const u_char *pkt_data; uae_set_thread_priority (NULL, 1); sd->threadactiver = 1; uae_sem_post (&sd->sync_semr); while (sd->threadactiver == 1) { int r; r = pcap_next_ex (sd->fp, &header, &pkt_data); if (r == 1) { uae_sem_wait (&sd->change_sem); sd->gotfunc ((struct s2devstruct*)sd->user, pkt_data, header->len); uae_sem_post (&sd->change_sem); } if (r < 0) { write_log (L"pcap_next_ex failed, err=%d\n", r); break; } } sd->threadactiver = 0; uae_sem_post (&sd->sync_semr); return 0; }
/* * Call m68k function from an extended trap handler * * This function is to be called from the trap context. */ static uae_u32 trap_Call68k (TrapContext *context, uaecptr func_addr) { /* Enter critical section - only one trap at a time, please! */ uae_sem_wait (&trap_mutex); current_context = context; /* Don't allow an interrupt and thus potentially another * trap to be invoked while we hold the above mutex. * This is probably just being paranoid. */ regs.intmask = 7; /* Set up function call address. */ context->call68k_func_addr = func_addr; /* Set PC to address of 68k call trap, so that it will be * executed when emulator context resumes. */ m68k_setpc (m68k_call_trapaddr); fill_prefetch (); /* Switch to emulator context. */ uae_sem_post (&context->switch_to_emu_sem); /* Wait for 68k call return handler to switch back to us. */ uae_sem_wait (&context->switch_to_trap_sem); /* End critical section. */ uae_sem_post (&trap_mutex); /* Get return value from 68k function called. */ return context->call68k_retval; }
static void *dev_thread (void *devs) { struct devstruct *dev = devs; uae_set_thread_priority (2); dev->thread_running = 1; sys_command_open_thread (DF_SCSI, dev->unitnum); sys_command_open_thread (DF_IOCTL, dev->unitnum); uae_sem_post (&dev->sync_sem); for (;;) { uaecptr request = (uaecptr)read_comm_pipe_u32_blocking (&dev->requests); uae_sem_wait (&change_sem); if (!request) { dev->thread_running = 0; uae_sem_post (&dev->sync_sem); uae_sem_post (&change_sem); break; } else if (dev_do_io (dev, request) == 0) { put_byte (request + 30, get_byte (request + 30) & ~1); release_async_request (dev, request); uae_ReplyMsg (request); } else { if (log_scsi) write_log ("async request %08.8X\n", request); } uae_sem_post (&change_sem); } sys_command_close_thread (DF_SCSI, dev->unitnum); sys_command_close_thread (DF_IOCTL, dev->unitnum); return 0; }
static void *uaenet_trap_threadw (void *arg) { struct uaenetdatawin32 *sd = (struct uaenetdatawin32*)arg; uae_set_thread_priority (NULL, 1); sd->threadactivew = 1; uae_sem_post (&sd->sync_semw); while (sd->threadactivew == 1) { int donotwait = 0; int towrite = sd->mtu; uae_sem_wait (&sd->change_sem); if (sd->getfunc ((struct s2devstruct*)sd->user, sd->writebuffer, &towrite)) { if (log_ethernet & 1) { TCHAR out[1600 * 2], *p; p = out; for (int i = 0; i < towrite && i < 1600; i++) { _stprintf(p, _T("%02x"), sd->writebuffer[i]); p += 2; *p = 0; } write_log(_T("OUT %4d: %s\n"), towrite, out); } ppcap_sendpacket(sd->fp, sd->writebuffer, towrite); donotwait = 1; } uae_sem_post (&sd->change_sem); if (!donotwait) WaitForSingleObject (sd->evttw, INFINITE); } sd->threadactivew = 0; uae_sem_post (&sd->sync_semw); return 0; }
static void *sound_thread (void *dummy) { for (;;) { int cmd = read_comm_pipe_int_blocking(&to_sound_pipe); switch(cmd) { case 0: open_sound(); uae_sem_post(&sound_init_sem); break; case 1: uae_sem_post(&sound_init_sem); return 0; } } }
static void subfunc(uae_u8 *data, int cnt) { uae_u8 out[SUB_CHANNEL_SIZE]; sub_to_deinterleaved(data, out); setsubchannel(out); uae_sem_wait(&sub_sem); if (subcodebufferinuse[subcodebufferoffsetw]) { memset (subcodebufferinuse, 0,sizeof (subcodebufferinuse)); subcodebufferoffsetw = subcodebufferoffset = 0; } else { int offset = subcodebufferoffsetw; while (cnt > 0) { if (subcodebufferinuse[offset]) { write_log (_T("CD32: subcode buffer overflow 2\n")); break; } subcodebufferinuse[offset] = 1; memcpy (&subcodebuffer[offset * SUB_CHANNEL_SIZE], data, SUB_CHANNEL_SIZE); data += SUB_CHANNEL_SIZE; offset++; if (offset >= MAX_SUBCODEBUFFER) offset = 0; cnt--; } subcodebufferoffsetw = offset; } uae_sem_post(&sub_sem); }
static int execscsicmd (struct dev_info_spti *di, int unitnum, uae_u8 *data, int len, uae_u8 *inbuf, int inlen) { SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb; DWORD status; int err, dolen; uae_sem_wait (&scgp_sem); memset (&swb, 0, sizeof (swb)); swb.spt.Length = sizeof (SCSI_PASS_THROUGH); swb.spt.CdbLength = len; if (inbuf) { swb.spt.DataIn = SCSI_IOCTL_DATA_IN; swb.spt.DataTransferLength = inlen; swb.spt.DataBuffer = inbuf; memset (inbuf, 0, inlen); } else { swb.spt.DataIn = SCSI_IOCTL_DATA_OUT; } swb.spt.TimeOutValue = 80 * 60; swb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf); swb.spt.SenseInfoLength = 32; memcpy (swb.spt.Cdb, data, len); status = doscsi (di, unitnum, &swb, &err); uae_sem_post (&scgp_sem); dolen = swb.spt.DataTransferLength; if (!status) return -1; return dolen; }
/* * Handles the emulator's side of a 68k call (from an extended trap) */ static uae_u32 REGPARAM3 m68k_call_handler (TrapContext *dummy_ctx) { TrapContext *context = current_context; uae_u32 sp; sp = m68k_areg (regs, 7); /* Push address of trap context on 68k stack. This is * so the return trap can find this context. */ sp -= sizeof (void *); put_pointer (sp, context); /* Push addr to return handler trap on 68k stack. * When the called m68k function does an RTS, the CPU will pull this * address off the stack and so call the return handler. */ sp -= 4; put_long (sp, m68k_return_trapaddr); m68k_areg (regs, 7) = sp; /* Set PC to address of 68k function to call. */ m68k_setpc (context->call68k_func_addr); fill_prefetch (); /* End critical section: allow other traps run. */ uae_sem_post (&trap_mutex); /* Restore interrupts. */ regs.intmask = context->saved_regs.intmask; /* Dummy return value. */ return 0; }
/* * Set up extended trap context and call handler function */ static void trap_HandleExtendedTrap (TrapHandler handler_func, int has_retval) { struct TrapContext *context = xcalloc (TrapContext, 1); if (context) { uae_sem_init (&context->switch_to_trap_sem, 0, 0); uae_sem_init (&context->switch_to_emu_sem, 0, 0); context->trap_handler = handler_func; context->trap_has_retval = has_retval; context->saved_regs = regs; /* Copy of regs to be restored when trap is done */ /* Start thread to handle new trap context. */ uae_start_thread ("Trap", trap_thread, (void *)context, &context->thread); /* Switch to trap context to begin execution of * trap handler function. */ uae_sem_post (&context->switch_to_trap_sem); /* Wait for trap context to switch back to us. * * It'll do this when the trap handler is done - or when * the handler wants to call 68k code. */ uae_sem_wait (&context->switch_to_emu_sem); } }
/* * Handles the return from a 68k call at the emulator's side. */ static uae_u32 REGPARAM3 m68k_return_handler (TrapContext *dummy_ctx) { TrapContext *context; uae_u32 sp; /* One trap returning at a time, please! */ uae_sem_wait (&trap_mutex); /* Get trap context from 68k stack. */ sp = m68k_areg (regs, 7); context = (TrapContext *)get_pointer (sp); sp += sizeof (void *); m68k_areg (regs, 7) = sp; /* Get return value from the 68k call. */ context->call68k_retval = m68k_dreg (regs, 0); /* Switch back to trap context. */ uae_sem_post (&context->switch_to_trap_sem); /* Wait for trap context to switch back to us. * * It'll do this when the trap handler is done - or when * the handler wants to call another 68k function. */ uae_sem_wait (&context->switch_to_emu_sem); /* Dummy return value. */ return 0; }
/* * Handles completion of an extended trap and passes * return value from trap function to 68k space. */ static uae_u32 REGPARAM3 exit_trap_handler (TrapContext *dummy_ctx) { TrapContext *context = current_context; /* Wait for trap context thread to exit. */ uae_wait_thread (context->thread); /* Restore 68k state saved at trap entry. */ regs = context->saved_regs; /* If trap is supposed to return a value, then store * return value in D0. */ if (context->trap_has_retval) m68k_dreg (regs, 0) = context->trap_retval; uae_sem_destroy (&context->switch_to_trap_sem); uae_sem_destroy (&context->switch_to_emu_sem); xfree (context); /* End critical section */ uae_sem_post (&trap_mutex); /* Dummy return value. */ return 0; }
static void cdtvcr_4510_reset(uae_u8 v) { cdtvcr_4510_ram[CDTVCR_ID + 0] = 'C'; cdtvcr_4510_ram[CDTVCR_ID + 1] = 'D'; cdtvcr_4510_ram[CDTVCR_ID + 2] = 'T'; cdtvcr_4510_ram[CDTVCR_ID + 3] = 'V'; write_log(_T("4510 reset %d\n"), v); if (v == 3) { sys_command_cd_pause (unitnum, 0); sys_command_cd_stop (unitnum); cdtvcr_4510_ram[CDTVCR_CD_PLAYING] = 0; cdtvcr_4510_ram[CDTVCR_CD_STATE] = 0; return; } else if (v == 2 || v == 1) { cdtvcr_4510_ram[CDTVCR_INTENA] = 0; cdtvcr_4510_ram[CDTVCR_INTREQ] = 0; if (v == 1) { memset(cdtvcr_4510_ram, 0, 4096); } cdtvcr_4510_ram[CDTVCR_INTDISABLE] = 1; cdtvcr_4510_ram[CDTVCR_CD_STATE] = 1; } cdtvcr_4510_ram[CDTVCR_PLAYLIST_TIME_MODE] = 2; uae_sem_wait (&sub_sem); memset (subcodebufferinuse, 0, sizeof subcodebufferinuse); subcodebufferoffsetw = subcodebufferoffset = 0; uae_sem_post (&sub_sem); if (ismedia()) get_toc(); }
/* * Set up extended trap context and call handler function */ static void trap_HandleExtendedTrap (TrapHandler handler_func, int has_retval) { struct ExtendedTrapContext *context = (struct ExtendedTrapContext *) calloc (1, sizeof (ExtendedTrapContext)); if (context) { uae_sem_init (&context->switch_to_trap_sem, 0, 0); uae_sem_init (&context->switch_to_emu_sem, 0, 0); context->trap_handler = handler_func; context->trap_has_retval = has_retval; context->regs = regs; /* Working copy of regs */ context->saved_regs = regs; /* Copy of regs to be restored when trap is done */ /* Start thread to handle new trap context. */ uae_start_thread_fast (trap_thread, (void *)context, &context->thread); /* Switch to trap context to begin execution of * trap handler function. */ uae_sem_post (&context->switch_to_trap_sem); /* Wait for trap context to switch back to us. * * It'll do this when the trap handler is done - or when * the handler wants to call 68k code. */ uae_sem_wait (&context->switch_to_emu_sem); /* Use trap's modified 68k state. This will reset the PC, so that * execution will resume at either the m68k call handler or the * the exit handler. */ regs = context->regs; } }
void uae_ReplyMsg (uaecptr msg) { uae_sem_wait (&n2asem); write_comm_pipe_int (&native2amiga_pending, 2, 0); write_comm_pipe_u32 (&native2amiga_pending, msg, 1); do_uae_int_requested (); uae_sem_post (&n2asem); }
void uae_Cause (uaecptr interrupt) { uae_sem_wait (&n2asem); write_comm_pipe_int (&native2amiga_pending, 3, 0); write_comm_pipe_u32 (&native2amiga_pending, interrupt, 1); do_uae_int_requested (); uae_sem_post (&n2asem); }
void slirp_output (const uint8 *pkt, int pkt_len) { if (!slirp_data) return; uae_sem_wait (&slirp_sem1); slirp_data->gotfunc (slirp_data->userdata, pkt, pkt_len); uae_sem_post (&slirp_sem1); }
static uae_u32 REGPARAM2 dev_beginio (TrapContext *context) { uae_u32 request = m68k_areg (regs, 1); uae_u8 flags = get_byte (request + 30); int command = get_word (request + 28); struct priv_s2devstruct *pdev = getps2devstruct (request); struct s2devstruct *dev; put_byte (request + 8, NT_MESSAGE); if (!pdev) { write_log (_T("%s unknown iorequest (1) %08x\n"), getdevname (), request); put_byte (request + 31, 32); return get_byte (request + 31); } dev = gets2devstruct (pdev->unit); if (!dev) { write_log (_T("%s unknown iorequest (2) %08x\n"), getdevname (), request); put_byte (request + 31, 32); return get_byte (request + 31); } put_byte (request + 31, 0); if ((flags & 1) && dev_canquick (dev, request)) { if (dev_do_io (dev, request, 1)) write_log (_T("%s: command %d bug with IO_QUICK\n"), SANA2NAME, command); return get_byte (request + 31); } else { if (command == CMD_WRITE || command == S2_BROADCAST || command == S2_MULTICAST) { struct s2packet *s2p; if (!pdev->copyfrombuff || !pdev->copytobuff) { put_long (request + 32, S2ERR_BAD_ARGUMENT); put_byte (request + 31, S2WERR_BUFF_ERROR); } else { if (command == S2_BROADCAST) { uaecptr dstaddr = request + 32 + 4 + 4 + SANA2_MAX_ADDR_BYTES; put_byte (dstaddr + 0, 0xff); put_byte (dstaddr + 1, 0xff); put_byte (dstaddr + 2, 0xff); put_byte (dstaddr + 3, 0xff); put_byte (dstaddr + 4, 0xff); put_byte (dstaddr + 5, 0xff); } s2p = createwritepacket (context, request); if (s2p) { uae_sem_wait (&async_sem); add_async_packet (dev, s2p, request); uae_sem_post (&async_sem); } if (!s2p) { put_long (request + 32, S2WERR_BUFF_ERROR); put_byte (request + 31, S2ERR_NO_RESOURCES); } } } put_byte (request + 30, get_byte (request + 30) & ~1); write_comm_pipe_u32 (&dev->requests, request, 1); return 0; } }
void uae_Signal (uaecptr task, uae_u32 mask) { uae_sem_wait (&n2asem); write_comm_pipe_int (&native2amiga_pending, 0, 0); write_comm_pipe_u32 (&native2amiga_pending, task, 0); write_comm_pipe_int (&native2amiga_pending, mask, 1); do_uae_int_requested (); uae_sem_post (&n2asem); }
static void *uaenet_trap_threadw (void *arg) { struct uaenetdata *sd = (struct uaenetdata*)arg; uae_set_thread_priority (1); sd->threadactivew = 1; uae_sem_post (&sd->sync_semw); while (sd->threadactivew == 1) { int32_t towrite = sd->mtu; uae_sem_wait (&sd->change_sem); if (sd->getfunc (sd->user, sd->writebuffer, &towrite)) { pcap_sendpacket (sd->fp, sd->writebuffer, towrite); } uae_sem_post (&sd->change_sem); } sd->threadactivew = 0; uae_sem_post (&sd->sync_semw); return 0; }
void uae_NotificationHack (uaecptr port, uaecptr nr) { uae_sem_wait (&n2asem); write_comm_pipe_int (&native2amiga_pending, 4, 0); write_comm_pipe_int (&native2amiga_pending, port, 0); write_comm_pipe_int (&native2amiga_pending, nr, 1); do_uae_int_requested (); uae_sem_post (&n2asem); }
void vsync_callback(unsigned int a, void* b) { //vsync_timing=SDL_GetTicks(); //vsync_frequency = vsync_timing - old_time; //old_time = vsync_timing; //need_frameskip = ( vsync_frequency > 31 ) ? (need_frameskip+1) : need_frameskip; //printf("d: %i", vsync_frequency ); uae_sem_post (&vsync_wait_sem); }
static void *slirp_receive_func(void *arg) { slirp_thread_active = 1; while (slirp_thread_active) { // Wait for packets to arrive fd_set rfds, wfds, xfds; int nfds; int ret, timeout; // ... in the output queue nfds = -1; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&xfds); uae_sem_wait (&slirp_sem2); timeout = slirp_select_fill(&nfds, &rfds, &wfds, &xfds); uae_sem_post (&slirp_sem2); if (nfds < 0) { /* Windows does not honour the timeout if there is not descriptor to wait for */ sleep_millis (timeout / 1000); ret = 0; } else { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = timeout; ret = select(0, &rfds, &wfds, &xfds, &tv); if (ret == SOCKET_ERROR) { write_log(_T("SLIRP socket ERR=%d\n"), WSAGetLastError()); } } if (ret >= 0) { uae_sem_wait (&slirp_sem2); slirp_select_poll(&rfds, &wfds, &xfds); uae_sem_post (&slirp_sem2); } } slirp_thread_active = -1; return 0; }
static void sound_callback (void *userdata, Uint8 *stream, int len) { if (closing_sound) return; in_callback = 1; /* Wait for data to finish. */ uae_sem_wait (&data_available_sem); if (! closing_sound) { memcpy (stream, sndbuffer, sndbufsize); /* Notify writer that we're done. */ uae_sem_post (&callback_done_sem); } in_callback = 0; }
void uaenet_gotdata (struct s2devstruct *dev, const uae_u8 *d, int len) { uae_u16 type; struct mcast *mc; struct s2packet *s2p; if (!dev->online) return; /* drop if bogus size */ if (len < 20 || len >= dev->td->mtu + ETH_HEADER_SIZE + 2) return; /* drop if dst == broadcast and src == me */ if (isbroadcast (d) && !memcmp (d + 6, dev->td->mac, ADDR_SIZE)) return; /* drop if not promiscuous and dst != broadcast and dst != me */ if (!dev->promiscuous && !isbroadcast (d) && memcmp (d, dev->td->mac, ADDR_SIZE)) return; /* drop if multicast with unknown address */ if (ismulticast (d)) { uae_u64 mac64 = addrto64 (d); /* multicast */ mc = dev->mc; while (mc) { if (mac64 >= mc->start && mac64 <= mc->end) break; mc = mc->next; } if (!mc) return; } type = (d[12] << 8) | d[13]; s2p = createreadpacket (dev, d, len); if (log_net) write_log (_T("<-DST:%02X.%02X.%02X.%02X.%02X.%02X SRC:%02X.%02X.%02X.%02X.%02X.%02X E=%04X L=%d P=%p\n"), d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], type, len, s2p); uae_sem_wait (&async_sem); if (!dev->readqueue) { dev->readqueue = s2p; } else { struct s2packet *s2p2 = dev->readqueue; while (s2p2->next) s2p2 = s2p2->next; s2p2->next = s2p; } uaenet_int_requested = 1; uae_sem_post (&async_sem); }
static void *uaenet_trap_threadw (void *arg) { struct uaenetdatawin32 *sd = (struct uaenetdatawin32*)arg; uae_set_thread_priority (NULL, 1); sd->threadactivew = 1; uae_sem_post (&sd->sync_semw); while (sd->threadactivew == 1) { int donotwait = 0; int towrite = sd->mtu; uae_sem_wait (&sd->change_sem); if (sd->getfunc ((struct s2devstruct*)sd->user, sd->writebuffer, &towrite)) { pcap_sendpacket (sd->fp, sd->writebuffer, towrite); donotwait = 1; } uae_sem_post (&sd->change_sem); if (!donotwait) WaitForSingleObject (sd->evttw, INFINITE); } sd->threadactivew = 0; uae_sem_post (&sd->sync_semw); return 0; }