static void write_p64(Bitu port,Bitu val,Bitu iolen) { switch (val) { case 0xae: /* Activate keyboard */ keyb.active=true; if (keyb.used && !keyb.scheduled && !keyb.p60changed) { keyb.scheduled=true; PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY); } LOG(LOG_KEYBOARD,LOG_NORMAL)("Activated"); break; case 0xad: /* Deactivate keyboard */ keyb.active=false; LOG(LOG_KEYBOARD,LOG_NORMAL)("De-Activated"); break; case 0xd0: /* Outport on buffer */ KEYBOARD_SetPort60(MEM_A20_Enabled() ? 0x02 : 0); break; case 0xd1: /* Write to outport */ keyb.command=CMD_SETOUTPORT; break; default: LOG(LOG_KEYBOARD,LOG_ERROR)("Port 64 write with val %d",val); break; } }
void Mouse_AddEvent(Bit8u type) { if (mouse.events < QUEUE_SIZE) { if (mouse.events > 0) { if (type == MOUSE_HAS_MOVED) // Skip duplicate events return; /* Always put the newest element in the front as that the events are * handled backwards (prevents doubleclicks while moving) */ for (Bitu i = mouse.events; i; i--) mouse.event_queue[i] = mouse.event_queue[i-1]; } mouse.event_queue[0].type = type; mouse.event_queue[0].buttons = mouse.buttons; mouse.events++; } if (!mouse.timer_in_progress) { mouse.timer_in_progress = true; PIC_AddEvent(MOUSE_Limit_Events, MOUSE_DELAY); PIC_ActivateIRQ(MOUSE_IRQ); } }
static void MPU401_EOIHandlerDispatch(void) { if (mpu.state.send_now) { mpu.state.eoi_scheduled=true; PIC_AddEvent(EOI_HANDLER,1); // Possible a bit longer } else if (!mpu.state.eoi_scheduled) MPU401_EOIHandler(); }
static void cmos_timerevent(Bitu val) { PIC_ActivateIRQ(8); if (cmos.timer.enabled) { PIC_AddEvent(cmos_timerevent,cmos.timer.delay); cmos.regs[0xc] = 0xC0;//Contraption Zack (music) } }
void MPU401_Event(void) { /* SOFTMPU */ Bit8u i; Bitu new_time; if (mpu.mode==M_UART) return; if (mpu.state.irq_pending) goto next_event; for (i=0;i<8;i++) { /* Decrease counters */ if (mpu.state.amask&(1<<i)) { mpu.playbuf[i].counter--; if (mpu.playbuf[i].counter<=0) UpdateTrack(i); } } if (mpu.state.conductor) { mpu.condbuf.counter--; if (mpu.condbuf.counter<=0) UpdateConductor(); } if (mpu.clock.clock_to_host) { mpu.clock.cth_counter++; if (mpu.clock.cth_counter >= mpu.clock.cth_rate) { mpu.clock.cth_counter=0; mpu.state.req_mask|=(1<<13); } } if (!mpu.state.irq_pending && mpu.state.req_mask) MPU401_EOIHandler(); next_event: PIC_RemoveEvents(MPU_EVENT); if ((new_time=mpu.clock.tempo*mpu.clock.timebase)==0) return; PIC_AddEvent(MPU_EVENT,(Bitu)MPU401_TIMECONSTANT/new_time); }
static void cmos_checktimer(void) { PIC_RemoveEvents(cmos_timerevent); if (cmos.timer.div<=2) cmos.timer.div+=7; cmos.timer.delay=(1000.0f/(32768.0f / (1 << (cmos.timer.div - 1)))); if (!cmos.timer.div || !cmos.timer.enabled) return; LOG(LOG_PIT,LOG_NORMAL)("RTC Timer at %.2f hz",1000.0/cmos.timer.delay); PIC_AddEvent(cmos_timerevent,cmos.timer.delay); }
static Bitu read_p60(Bitu port,Bitu iolen) { keyb.p60changed=false; if (!keyb.scheduled && keyb.used) { keyb.scheduled=true; PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY); } return keyb.p60data; }
void MOUSE_Limit_Events(Bitu /*val*/) { mouse.timer_in_progress = false; if (mouse.events) { mouse.timer_in_progress = true; PIC_AddEvent(MOUSE_Limit_Events,MOUSE_DELAY); PIC_ActivateIRQ(MOUSE_IRQ); } }
Bitu MOUSE_UserInt_CB_Handler(void) { mouse.in_UIR = false; if (mouse.events) { if (!mouse.timer_in_progress) { mouse.timer_in_progress = true; PIC_AddEvent(MOUSE_Limit_Events,MOUSE_DELAY); } } return CBRET_NONE; }
static void cmos_checktimer(void) { PIC_RemoveEvents(cmos_timerevent); if (cmos.timer.div<=2) cmos.timer.div+=7; cmos.timer.delay=(1000.0f/(32768.0f / (1 << (cmos.timer.div - 1)))); if (!cmos.timer.div || !cmos.timer.enabled) return; LOG(LOG_PIT,LOG_NORMAL)("RTC Timer at %.2f hz",1000.0/cmos.timer.delay); // PIC_AddEvent(cmos_timerevent,cmos.timer.delay); /* A rtc is always running */ double remd=fmod(PIC_FullIndex(),(double)cmos.timer.delay); PIC_AddEvent(cmos_timerevent,(float)((double)cmos.timer.delay-remd)); //Should be more like a real pc. Check // status reg A reading with this (and with other delays actually) }
static void KEYBOARD_AddBuffer(Bit16u data) { if (keyb.used>=KEYBUFSIZE) { LOG(LOG_KEYBOARD,LOG_NORMAL)("Buffer full, dropping code"); KEYBOARD_ClrBuffer(); return; } Bitu start=keyb.pos+keyb.used; if (start>=KEYBUFSIZE) start-=KEYBUFSIZE; keyb.buffer[start]=data; keyb.used++; /* Start up an event to start the first IRQ */ if (!keyb.scheduled && !keyb.p60changed) { keyb.scheduled=true; PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY); } }
static void KEYBOARD_Add8042Response(Bit8u data) { if(!keyb.enable_aux) return; if (keyb.buf8042_pos >= keyb.buf8042_len) keyb.buf8042_pos = keyb.buf8042_len = 0; else if (keyb.buf8042_len == 0) keyb.buf8042_pos = 0; if (keyb.buf8042_pos >= sizeof(keyb.buf8042)) { LOG(LOG_KEYBOARD,LOG_NORMAL)("8042 Buffer full, dropping code"); KEYBOARD_ClrBuffer(); return; } keyb.buf8042[keyb.buf8042_len++] = data; PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY); }
static void write_p60(Bitu port,Bitu val,Bitu iolen) { switch (keyb.command) { case CMD_NONE: /* None */ if (keyb.reset) return; /* No active command this would normally get sent to the keyboard then */ KEYBOARD_ClrBuffer(); switch (val) { case 0xed: /* Set Leds */ keyb.command=CMD_SETLEDS; KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ break; case 0xee: /* Echo */ KEYBOARD_AddBuffer(0xee); /* JC: The correct response is 0xEE, not 0xFA */ break; case 0xf0: /* set scancode set */ keyb.command=CMD_SETSCANSET; KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ break; case 0xf2: /* Identify keyboard */ KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ KEYBOARD_AddBuffer(0xab); /* ID */ KEYBOARD_AddBuffer(0x83); break; case 0xf3: /* Typematic rate programming */ keyb.command=CMD_SETTYPERATE; KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ break; case 0xf4: /* Enable keyboard,clear buffer, start scanning */ LOG(LOG_KEYBOARD,LOG_NORMAL)("Clear buffer, enable scanning"); KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ keyb.scanning=true; break; case 0xf5: /* Reset keyboard and disable scanning */ LOG(LOG_KEYBOARD,LOG_NORMAL)("Reset, disable scanning"); keyb.scanning=false; KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ break; case 0xf6: /* Reset keyboard and enable scanning */ LOG(LOG_KEYBOARD,LOG_NORMAL)("Reset, enable scanning"); keyb.scanning=true; /* JC: Original DOSBox code was wrong, this command enables scanning */ KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ break; case 0xff: /* keyboard resets take a long time (about 250ms), most keyboards flash the LEDs during reset */ KEYBOARD_Reset(); KEYBOARD_Add8042Response(0xFA); /* ACK */ KEYBOARD_Add8042Response(0xAA); /* SELF TEST OK (TODO: Need delay!) */ keyb.reset=true; KEYBOARD_SetLEDs(7); /* most keyboard I test with tend to flash the LEDs during reset */ PIC_AddEvent(KEYBOARD_ResetDelay,RESETDELAY); break; default: /* Just always acknowledge strange commands */ LOG(LOG_KEYBOARD,LOG_ERROR)("60:Unhandled command %X",(int)val); KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ } return; case CMD_SETSCANSET: keyb.command=CMD_NONE; if (val == 0) { /* just asking */ if (keyb.cb_xlat) { switch (keyb.scanset) { case 1: KEYBOARD_AddBuffer(0x43); break; case 2: KEYBOARD_AddBuffer(0x41); break; case 3: KEYBOARD_AddBuffer(0x3F); break; } } else { KEYBOARD_AddBuffer(keyb.scanset); } KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ } else { KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ KEYBOARD_AddBuffer(0xfa); /* Acknowledge again */ if (val > 3) val = 3; keyb.scanset = val; } break; case CMD_WRITEAUX: keyb.command=CMD_NONE; KEYBOARD_AUX_Write(val); break; case CMD_WRITEOUTPUT: keyb.command=CMD_NONE; KEYBOARD_ClrBuffer(); KEYBOARD_AddBuffer(val); /* and now you return the byte as if it were typed in */ break; case CMD_WRITEAUXOUT: KEYBOARD_AddBuffer(AUX|val); /* stuff into AUX output */ break; case CMD_SETOUTPORT: if (!(val & 1)) { if (allow_keyb_reset) { LOG_MSG("Restart by keyboard controller requested\n"); On_Software_CPU_Reset(); } else { LOG_MSG("WARNING: Keyboard output port written with bit 1 clear. Is the guest OS or application attempting to reset the system?\n"); } } MEM_A20_Enable((val & 2)>0); keyb.command = CMD_NONE; break; case CMD_SETTYPERATE: if (keyb.reset) return; { static const int delay[] = { 250, 500, 750, 1000 }; static const int repeat[] = { 33,37,42,46,50,54,58,63,67,75,83,92,100, 109,118,125,133,149,167,182,200,217,233, 250,270,303,333,370,400,435,476,500 }; keyb.repeat.pause = delay[(val >> 5) & 3]; keyb.repeat.rate = repeat[val & 0x1f]; keyb.command = CMD_NONE; KEYBOARD_ClrBuffer(); KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ } break; case CMD_SETLEDS: if (keyb.reset) return; keyb.command=CMD_NONE; KEYBOARD_ClrBuffer(); KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ KEYBOARD_SetLEDs(val&7); break; case CMD_SETCOMMAND: /* 8042 command, not keyboard */ /* TODO: If biosps2=true and aux=false, disallow the guest OS from changing AUX port parameters including IRQ */ keyb.command=CMD_NONE; keyb.cb_xlat = (val >> 6) & 1; keyb.auxactive = !((val >> 5) & 1); keyb.active = !((val >> 4) & 1); keyb.cb_sys = (val >> 2) & 1; keyb.cb_irq12 = (val >> 1) & 1; keyb.cb_irq1 = (val >> 0) & 1; if (keyb.used && !keyb.scheduled && !keyb.p60changed && keyb.active) { keyb.scheduled=true; PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY); } break; } }
static void DISNEY_CallBack(Bitu len) { if (!len) return; // get the smaller used Bitu real_used; if(disney.stereo) { real_used = disney.da[0].used; if(disney.da[1].used < real_used) real_used = disney.da[1].used; } else real_used = disney.leader->used; if (real_used >= len) { // enough data for now if(disney.stereo) DISNEY_PlayStereo(len, disney.da[0].buffer, disney.da[1].buffer); else disney.chan->AddSamples_m8(len,disney.leader->buffer); // put the rest back to start for(int i = 0; i < 2; i++) { // TODO for mono only one memmove(disney.da[i].buffer,&disney.da[i].buffer[len],DISNEY_SIZE/*real_used*/-len); disney.da[i].used -= len; } // TODO: len > DISNEY } else { // not enough data if(disney.stereo) { Bit8u gapfiller0 = 128; Bit8u gapfiller1 = 128; if(real_used) { gapfiller0 = disney.da[0].buffer[real_used-1]; gapfiller1 = disney.da[1].buffer[real_used-1]; }; memset(disney.da[0].buffer+real_used, gapfiller0,len-real_used); memset(disney.da[1].buffer+real_used, gapfiller1,len-real_used); DISNEY_PlayStereo(len, disney.da[0].buffer, disney.da[1].buffer); len -= real_used; } else { // mono Bit8u gapfiller = 128; //Keep the middle if(real_used) { // fix for some stupid game; it outputs 0 at the end of the stream // causing a click. So if we have at least two bytes availible in the // buffer and the last one is a 0 then ignore that. if(disney.leader->buffer[real_used-1]==0) real_used--; } // do it this way because AddSilence sounds like a gnawing mouse if(real_used) gapfiller = disney.leader->buffer[real_used-1]; //LOG_MSG("gapfiller %x, fill len %d, realused %d",gapfiller,len-real_used,real_used); memset(disney.leader->buffer+real_used, gapfiller, len-real_used); disney.chan->AddSamples_m8(len, disney.leader->buffer); } disney.da[0].used =0; disney.da[1].used =0; //LOG_MSG("disney underflow %d",len - real_used); } if (disney.last_used+100<PIC_Ticks) { // disable sound output PIC_AddEvent(DISNEY_disable,0.0001f); // I think we shouldn't delete the // mixer while we are inside it } }
static void write_p64(Bitu port,Bitu val,Bitu iolen) { if (keyb.reset) return; switch (val) { case 0x20: /* read command byte */ /* TODO: If biosps2=true and aux=false, mask AUX port bits as if AUX isn't there */ KEYBOARD_Add8042Response( (keyb.cb_xlat << 6) | ((!keyb.auxactive) << 5) | ((!keyb.active) << 4) | (keyb.cb_sys << 2) | (keyb.cb_irq12 << 1) | (keyb.cb_irq1?1:0)); break; case 0x60: keyb.command=CMD_SETCOMMAND; break; case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: /* TODO: If bit 0 == 0, trigger system reset */ break; case 0xa7: /* disable aux */ /* TODO: If biosps2=true and aux=false do not respond */ if (keyb.enable_aux) { //keyb.auxactive=false; //LOG(LOG_KEYBOARD,LOG_NORMAL)("AUX De-Activated"); } break; case 0xa8: /* enable aux */ /* TODO: If biosps2=true and aux=false do not respond */ if (keyb.enable_aux) { keyb.auxactive=true; if (keyb.used && !keyb.scheduled && !keyb.p60changed) { keyb.scheduled=true; PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY); } LOG(LOG_KEYBOARD,LOG_NORMAL)("AUX Activated"); } break; case 0xa9: /* mouse interface test */ /* TODO: If biosps2=true and aux=false do not respond */ KEYBOARD_Add8042Response(0x00); /* OK */ break; case 0xaa: /* Self test */ keyb.active=false; /* on real h/w it also seems to disable the keyboard */ KEYBOARD_Add8042Response(0xaa); /* OK */ break; case 0xab: /* interface test */ keyb.active=false; /* on real h/w it also seems to disable the keyboard */ KEYBOARD_Add8042Response(0x00); /* no error */ break; case 0xae: /* Activate keyboard */ keyb.active=true; if (keyb.used && !keyb.scheduled && !keyb.p60changed) { keyb.scheduled=true; PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY); } LOG(LOG_KEYBOARD,LOG_NORMAL)("Activated"); break; case 0xad: /* Deactivate keyboard */ keyb.active=false; LOG(LOG_KEYBOARD,LOG_NORMAL)("De-Activated"); break; case 0xc0: /* read input buffer */ KEYBOARD_Add8042Response(0x40); break; case 0xd0: /* Outport on buffer */ KEYBOARD_SetPort60((MEM_A20_Enabled() ? 0x02 : 0) | 0x01/*some programs read the output port then write it back*/); break; case 0xd1: /* Write to outport */ keyb.command=CMD_SETOUTPORT; break; case 0xd2: /* write output register */ keyb.command=CMD_WRITEOUTPUT; break; case 0xd3: /* write AUX output */ if (keyb.enable_aux) keyb.command=CMD_WRITEAUXOUT; else if (aux_warning++ == 0) LOG(LOG_KEYBOARD,LOG_ERROR)("Program is writing 8042 AUX. If you intend to use PS/2 mouse emulation you may consider adding aux=1 to your dosbox.conf"); break; case 0xd4: /* send byte to AUX */ if (keyb.enable_aux) keyb.command=CMD_WRITEAUX; else if (aux_warning++ == 0) LOG(LOG_KEYBOARD,LOG_ERROR)("Program is writing 8042 AUX. If you intend to use PS/2 mouse emulation you may consider adding aux=1 to your dosbox.conf"); break; case 0xe0: /* read test port */ KEYBOARD_Add8042Response(0x00); break; case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: /* pulse output register */ if (!(val & 1)) { if (allow_keyb_reset) { LOG_MSG("Restart by keyboard controller requested\n"); On_Software_CPU_Reset(); } else { LOG_MSG("WARNING: Keyboard output port written (pulsed) with bit 1 clear. Is the guest OS or application attempting to reset the system?\n"); } } break; default: LOG(LOG_KEYBOARD,LOG_ERROR)("Port 64 write with val %d",(int)val); break; } }
void MPU401_WriteCommand(Bit8u val) { /* SOFTMPU */ Bit8u i; /* SOFTMPU */ if (mpu.state.reset) { if (mpu.state.cmd_pending || (val!=0x3f && val!=0xff)) { mpu.state.cmd_pending=val+1; return; } PIC_RemoveEvents(RESET_DONE); mpu.state.reset=false; } if (val<=0x2f) { switch (val&3) { /* MIDI stop, start, continue */ case 1: {MIDI_RawOutByte(0xfc);break;} case 2: {MIDI_RawOutByte(0xfa);break;} case 3: {MIDI_RawOutByte(0xfb);break;} } /*if (val&0x20) LOG(LOG_MISC,LOG_ERROR)("MPU-401:Unhandled Recording Command %x",val);*/ /* SOFTMPU */ switch (val&0xc) { case 0x4: /* Stop */ PIC_RemoveEvents(MPU_EVENT); mpu.state.playing=false; for (i=0xb0;i<0xbf;i++) { /* All notes off */ MIDI_RawOutByte(i); MIDI_RawOutByte(0x7b); MIDI_RawOutByte(0); } break; case 0x8: /* Play */ /*LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Intelligent mode playback started");*/ /* SOFTMPU */ mpu.state.playing=true; PIC_RemoveEvents(MPU_EVENT); PIC_AddEvent(MPU_EVENT,(Bitu)MPU401_TIMECONSTANT/(mpu.clock.tempo*mpu.clock.timebase)); ClrQueue(); break; } } else if (val>=0xa0 && val<=0xa7) { /* Request play counter */ if (mpu.state.cmask&(1<<(val&7))) QueueByte((Bit8u)mpu.playbuf[val&7].counter); } else if (val>=0xd0 && val<=0xd7) { /* Send data */ mpu.state.old_chan=mpu.state.channel; mpu.state.channel=val&7; mpu.state.wsd=true; mpu.state.wsm=false; mpu.state.wsd_start=true; } else switch (val) { case 0xdf: /* Send system message */ mpu.state.wsd=false; mpu.state.wsm=true; mpu.state.wsd_start=true; break; case 0x8e: /* Conductor */ mpu.state.cond_set=false; break; case 0x8f: mpu.state.cond_set=true; break; case 0x94: /* Clock to host */ mpu.clock.clock_to_host=false; break; case 0x95: mpu.clock.clock_to_host=true; break; case 0xc2: /* Internal timebase */ mpu.clock.timebase=48/(RTCFREQ/1000); /* SOFTMPU */ break; case 0xc3: mpu.clock.timebase=72/(RTCFREQ/1000); /* SOFTMPU */ break; case 0xc4: mpu.clock.timebase=96/(RTCFREQ/1000); /* SOFTMPU */ break; case 0xc5: mpu.clock.timebase=120/(RTCFREQ/1000); /* SOFTMPU */ break; case 0xc6: mpu.clock.timebase=144/(RTCFREQ/1000); /* SOFTMPU */ break; case 0xc7: mpu.clock.timebase=168/(RTCFREQ/1000); /* SOFTMPU */ break; case 0xc8: mpu.clock.timebase=192/(RTCFREQ/1000); /* SOFTMPU */ break; /* Commands with data byte */ case 0xe0: case 0xe1: case 0xe2: case 0xe4: case 0xe6: case 0xe7: case 0xec: case 0xed: case 0xee: case 0xef: mpu.state.command_byte=val; break; /* Commands 0xa# returning data */ case 0xab: /* Request and clear recording counter */ QueueByte(MSG_MPU_ACK); QueueByte(0); return; case 0xac: /* Request version */ if (CONFIG_VERSIONFIX) { /* SOFTMPU: Fix missing music in Gateway by reversing version and ACK */ QueueByte(MPU401_VERSION); QueueByte(MSG_MPU_ACK); } else { QueueByte(MSG_MPU_ACK); QueueByte(MPU401_VERSION); } return; case 0xad: /* Request revision */ QueueByte(MSG_MPU_ACK); QueueByte(MPU401_REVISION); return; case 0xae: /* HardMPU: Request config */ QueueByte(MSG_MPU_ACK); QueueByte(mpu.config); return; case 0xaf: /* Request tempo */ QueueByte(MSG_MPU_ACK); QueueByte(mpu.clock.tempo); return; case 0xb1: /* Reset relative tempo */ mpu.clock.tempo_rel=40; break; case 0xb9: /* Clear play map */ case 0xb8: /* Clear play counters */ for (i=0xb0;i<0xbf;i++) { /* All notes off */ MIDI_RawOutByte((Bit8u)i); MIDI_RawOutByte(0x7b); MIDI_RawOutByte(0); } for (i=0;i<8;i++) { mpu.playbuf[i].counter=0; mpu.playbuf[i].type=T_OVERFLOW; } mpu.condbuf.counter=0; mpu.condbuf.type=T_OVERFLOW; if (!(mpu.state.conductor=mpu.state.cond_set)) mpu.state.cond_req=0; mpu.state.amask=mpu.state.tmask; mpu.state.req_mask=0; mpu.state.irq_pending=true; break; case 0xfe: /* HardMPU: Reset with config byte */ mpu.state.command_byte=val; break; case 0xff: /* Reset MPU-401 */ /*LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Reset %X",val);*/ /* SOFTMPU */ PIC_AddEvent(RESET_DONE,MPU401_RESETBUSY); mpu.state.reset=true; MPU401_Reset(); if (mpu.mode==M_UART) return;//do not send ack in UART mode break; case 0x3f: /* UART mode */ /*LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Set UART mode %X",val);*/ /* SOFTMPU */ mpu.mode=M_UART; break; default: /*LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Unhandled command %X",val);*/ break; } QueueByte(MSG_MPU_ACK); }
void bx_ne2k_c::write_cr(Bit32u value) { BX_DEBUG ("wrote 0x%02x to CR", value); // Validate remote-DMA if ((value & 0x38) == 0x00) { BX_DEBUG("CR write - invalid rDMA value 0"); value |= 0x20; /* dma_cmd == 4 is a safe default */ //value = 0x22; /* dma_cmd == 4 is a safe default */ } // Check for s/w reset if (value & 0x01) { BX_NE2K_THIS s.ISR.reset = 1; BX_NE2K_THIS s.CR.stop = 1; } else { BX_NE2K_THIS s.CR.stop = 0; } BX_NE2K_THIS s.CR.rdma_cmd = (value & 0x38) >> 3; // If start command issued, the RST bit in the ISR // must be cleared if ((value & 0x02) && !BX_NE2K_THIS s.CR.start) { BX_NE2K_THIS s.ISR.reset = 0; } BX_NE2K_THIS s.CR.start = ((value & 0x02) == 0x02); BX_NE2K_THIS s.CR.pgsel = (value & 0xc0) >> 6; // Check for send-packet command if (BX_NE2K_THIS s.CR.rdma_cmd == 3) { // Set up DMA read from receive ring BX_NE2K_THIS s.remote_start = BX_NE2K_THIS s.remote_dma = BX_NE2K_THIS s.bound_ptr * 256; BX_NE2K_THIS s.remote_bytes = *((Bit16u*) & BX_NE2K_THIS s.mem[BX_NE2K_THIS s.bound_ptr * 256 + 2 - BX_NE2K_MEMSTART]); BX_INFO("Sending buffer #x%x length %d", BX_NE2K_THIS s.remote_start, BX_NE2K_THIS s.remote_bytes); } // Check for start-tx if ((value & 0x04) && BX_NE2K_THIS s.TCR.loop_cntl) { // loopback mode if (BX_NE2K_THIS s.TCR.loop_cntl != 1) { BX_INFO("Loop mode %d not supported.", BX_NE2K_THIS s.TCR.loop_cntl); } else { rx_frame (& BX_NE2K_THIS s.mem[BX_NE2K_THIS s.tx_page_start*256 - BX_NE2K_MEMSTART], BX_NE2K_THIS s.tx_bytes); // do a TX interrupt // Generate an interrupt if not masked and not one in progress if (BX_NE2K_THIS s.IMR.tx_inte && !BX_NE2K_THIS s.ISR.pkt_tx) { //LOG_MSG("tx complete interrupt"); PIC_ActivateIRQ(s.base_irq); } BX_NE2K_THIS s.ISR.pkt_tx = 1; } } else if (value & 0x04) { // start-tx and no loopback if (BX_NE2K_THIS s.CR.stop || !BX_NE2K_THIS s.CR.start) BX_PANIC(("CR write - tx start, dev in reset")); if (BX_NE2K_THIS s.tx_bytes == 0) BX_PANIC(("CR write - tx start, tx bytes == 0")); #ifdef notdef // XXX debug stuff printf("packet tx (%d bytes):\t", BX_NE2K_THIS s.tx_bytes); for (int i = 0; i < BX_NE2K_THIS s.tx_bytes; i++) { printf("%02x ", BX_NE2K_THIS s.mem[BX_NE2K_THIS s.tx_page_start*256 - BX_NE2K_MEMSTART + i]); if (i && (((i+1) % 16) == 0)) printf("\t"); } printf(""); #endif // Send the packet to the system driver /* TODO: Transmit packet */ //BX_NE2K_THIS ethdev->sendpkt(& BX_NE2K_THIS s.mem[BX_NE2K_THIS s.tx_page_start*256 - BX_NE2K_MEMSTART], BX_NE2K_THIS s.tx_bytes); NE2000_PrivelegeEscalate(); pcap_sendpacket(adhandle,&s.mem[s.tx_page_start*256 - BX_NE2K_MEMSTART], s.tx_bytes); NE2000_PrivelegeDrop(); // some more debug if (BX_NE2K_THIS s.tx_timer_active) { BX_PANIC(("CR write, tx timer still active")); PIC_RemoveEvents(NE2000_TX_Event); } //LOG_MSG("send packet command"); //s.tx_timer_index = (64 + 96 + 4*8 + BX_NE2K_THIS s.tx_bytes*8)/10; s.tx_timer_active = 1; PIC_AddEvent(NE2000_TX_Event,(float)((64 + 96 + 4*8 + BX_NE2K_THIS s.tx_bytes*8)/10000.0),0); // Schedule a timer to trigger a tx-complete interrupt // The number of microseconds is the bit-time / 10. // The bit-time is the preamble+sfd (64 bits), the // inter-frame gap (96 bits), the CRC (4 bytes), and the // the number of bits in the frame (s.tx_bytes * 8). // /* TODO: Code transmit timer */ /* bx_pc_system.activate_timer(BX_NE2K_THIS s.tx_timer_index, (64 + 96 + 4*8 + BX_NE2K_THIS s.tx_bytes*8)/10, 0); // not continuous */ } // end transmit-start branch // Linux probes for an interrupt by setting up a remote-DMA read // of 0 bytes with remote-DMA completion interrupts enabled. // Detect this here if (BX_NE2K_THIS s.CR.rdma_cmd == 0x01 && BX_NE2K_THIS s.CR.start && BX_NE2K_THIS s.remote_bytes == 0) { BX_NE2K_THIS s.ISR.rdma_done = 1; if (BX_NE2K_THIS s.IMR.rdma_inte) { PIC_ActivateIRQ(s.base_irq); //DEV_pic_raise_irq(BX_NE2K_THIS s.base_irq); } } }