|
|
1.1 root 1: /* Previous - kms.c
2:
3: This file is distributed under the GNU Public License, version 2 or at
4: your option any later version. Read the file gpl.txt for details.
5:
6: Keyboard, Mouse and Sound logic Emulation.
7:
8: In real hardware this logic is located in the NeXT Megapixel Display
9: or Soundbox
10:
11: */
12:
13: #include "ioMem.h"
14: #include "ioMemTables.h"
15: #include "m68000.h"
16: #include "kms.h"
17: #include "sysReg.h"
18: #include "dma.h"
19: #include "rtcnvram.h"
20: #include "snd.h"
21: #include "video.h"
22:
23: #define LOG_KMS_LEVEL LOG_WARN
24: #define IO_SEG_MASK 0x1FFFF
25:
26:
27: struct {
28: struct {
29: Uint8 snd_dma;
30: Uint8 km;
31: Uint8 transmit;
32: Uint8 cmd;
33: } status;
34:
35: Uint32 data;
36: Uint32 km_data;
37: } kms;
38:
39:
40: /* KMS control and status register (0x0200E000)
41: *
42: * x--- ---- ---- ---- ---- ---- ---- ---- sound out enable (r/w)
43: * -x-- ---- ---- ---- ---- ---- ---- ---- sound output request (r)
44: * --x- ---- ---- ---- ---- ---- ---- ---- sound output underrun detected (r/w)
45: * ---- x--- ---- ---- ---- ---- ---- ---- sound in enable (r/w)
46: * ---- -x-- ---- ---- ---- ---- ---- ---- sound input request (r)
47: * ---- --x- ---- ---- ---- ---- ---- ---- sound input overrun detected (r/w)
48: *
49: * ---- ---- x--- ---- ---- ---- ---- ---- keyboard interrupt (r)
50: * ---- ---- -x-- ---- ---- ---- ---- ---- keyboard data received (r)
51: * ---- ---- --x- ---- ---- ---- ---- ---- keyboard data overrun detected (r/w)
52: * ---- ---- ---x ---- ---- ---- ---- ---- non-maskable interrupt received (tilde and left or right cmd key) (r/w)
53: * ---- ---- ---- x--- ---- ---- ---- ---- kms interrupt (r)
54: * ---- ---- ---- -x-- ---- ---- ---- ---- kms data received (r)
55: * ---- ---- ---- --x- ---- ---- ---- ---- kms data overrun detected (r/w)
56: *
57: * ---- ---- ---- ---- x--- ---- ---- ---- dma sound out transmit pending (r)
58: * ---- ---- ---- ---- -x-- ---- ---- ---- dma sound out transmit in progress (r)
59: * ---- ---- ---- ---- --x- ---- ---- ---- cpu data transmit pending (r)
60: * ---- ---- ---- ---- ---x ---- ---- ---- cpu data transmit in progress (r)
61: * ---- ---- ---- ---- ---- x--- ---- ---- rtx_pend ???
62: * ---- ---- ---- ---- ---- -x-- ---- ---- rtx ???
63: * ---- ---- ---- ---- ---- --x- ---- ---- kms enable (return from reset state) (r/w)
64: * ---- ---- ---- ---- ---- ---x ---- ---- loop back transmitter data (r/w)
65: *
66: * ---- ---- ---- ---- ---- ---- xxxx xxxx command to append on kms data (r/w)
67: *
68: * ---x ---x ---- ---x ---- ---- ---- ---- zero bits
69: */
70:
71:
72: #define SNDOUT_DMA_ENABLE 0x80
73: #define SNDOUT_DMA_REQUEST 0x40
74: #define SNDOUT_DMA_UNDERRUN 0x20
75: #define SNDIN_DMA_ENABLE 0x08
76: #define SNDIN_DMA_REQUEST 0x04
77: #define SNDIN_DMA_OVERRUN 0x02
78:
79: #define KBD_INT 0x80
80: #define KBD_RECEIVED 0x40
81: #define KBD_OVERRUN 0x20
82: #define NMI_RECEIVED 0x10
83: #define KMS_INT 0x08
84: #define KMS_RECEIVED 0x04
85: #define KMS_OVERRUN 0x02
86:
87: #define TX_DMA_PENDING 0x80
88: #define TX_DMA 0x40
89: #define TX_CPU_PENDING 0x20
90: #define TX_CPU 0x10
91: #define RTX_PEND 0x08
92: #define RTX 0x04
93: #define KMS_ENABLE 0x02
94: #define TX_LOOP 0x01
95:
96:
97: /* KMS commands */
98:
99: /* Host commands */
100: #define KMSCMD_RESET 0xFF
101: #define KMSCMD_ASNDOUT 0xC7 /* analog sound out */
102: #define KMSCMD_KMREG 0xC5 /* access keyboard or mouse register */
103: #define KMSCMD_CTRLOUT 0xC4 /* access volume control logic */
104: #define KMSCMD_VOLCTRL 0xC2 /* simplified access to volume control */
105:
106: #define KMSCMD_SND_IN 0x03 /* sound in */
107: #define KMSCMD_SND_OUT 0x07 /* sound out */
108: #define KMSCMD_SIO_MASK 0xC7 /* mask for sound in/out */
109:
110: #define SIO_ENABLE 0x08 /* 1=enable, 0=disable sound */
111: #define SIO_DBL_SMPL 0x10 /* 1=double sample, 0=normal */
112: #define SIO_ZERO 0x20 /* double sample by 1=zero filling, 0=repetition */
113:
114: /* Commands from KMS board */
115: #define KMSCMD_CODEC_IN 0xC7 /* CODEC sound in */
116: #define KMSCMD_KBD_RECV 0xC6 /* receive data from keyboard/mouse */
117: #define KMSCMD_SO_REQ 0x07 /* sound out request */
118: #define KMSCMD_SO_UNDR 0x0F /* sound out underrun */
119:
120: void KMS_command(Uint8 command, Uint32 data);
121:
122:
123: /* Keyboard Registers */
124: #define KM_REG_MASK 0xE0
125: #define KM_READ 0x10
126: #define KM_RESET 0x0F
127: #define KM_SET_ADDR 0xEF
128: #define KM_ADDR_MASK 0x0E
129: #define KM_ADDR_MOUSE 0x01
130:
131:
132: /* Device mask
133: *
134: * xxxx xxxx xxxx xxxx xxxx xxxx xxxx ---- polled devices (7 device addresses, 4 bit each)
135: * ---- ---- ---- ---- ---- ---- ---- xxxx poll speed
136: */
137:
138: Uint32 km_address = 0;
139: Uint32 km_dev_msk = 0;
140:
141: void access_km_reg(Uint32 data) {
142: Uint8 reg_addr = (data>>24)&0xFF;
143: Uint8 reg_data = (data>>16)&0xFF;
144:
145: if (reg_addr==KM_RESET) {
146: Log_Printf(LOG_KMS_LEVEL, "Keyboard/Mouse: Reset");
147: kms_response();
148: return;
149: }
150: if (reg_addr==KM_SET_ADDR) {
151: Log_Printf(LOG_KMS_LEVEL, "Keyboard/Mouse: Set address to %i",(reg_data&KM_ADDR_MASK)>>1);
152: km_address = reg_data&KM_ADDR_MASK;
153: kms_response();
154: return;
155: }
156:
157: bool device_kbd = (reg_addr&KM_ADDR_MOUSE) ? false : true;
158: int device_addr = (reg_addr&KM_ADDR_MASK)>>1;
159: int device_reg = (reg_addr&KM_REG_MASK)>>5;
160: bool read_reg = (reg_addr&KM_READ) ? true : false;
161:
162: Log_Printf(LOG_KMS_LEVEL, "%s %s %i, register %i",read_reg?"Reading":"Writing",
163: device_kbd?"keyboard":"mouse",device_addr,device_reg);
164:
165: if (reg_addr&KM_READ) {
166: switch (device_reg) {
167: case 0:
168: Log_Printf(LOG_KMS_LEVEL, "Poll device");
169: break;
170: case 7:
171: Log_Printf(LOG_KMS_LEVEL, "Request device revision");
172: break;
173: default:
174: Log_Printf(LOG_WARN, "Unknown device register");
175: break;
176: }
177: } else { // device write
178: switch (device_reg) {
179: case 0:
180: if (device_kbd) {
181: Log_Printf(LOG_KMS_LEVEL, "Turn %s keyboard LED1",(reg_data&1)?"on":"off");
182: Log_Printf(LOG_KMS_LEVEL, "Turn %s keyboard LED2",(reg_data&2)?"on":"off");
183: break;
184: }
185: default:
186: Log_Printf(LOG_WARN, "Unknown device register");
187: break;
188: }
189: }
190: kms_response();
191: }
192:
193: void KMS_command(Uint8 command, Uint32 data) {
194: switch (command) {
195: case KMSCMD_KBD_RECV: // keyboard poll
196: km_dev_msk=data;
197: return;
198:
199: case KMSCMD_RESET:
200: Log_Printf(LOG_KMS_LEVEL, "[KMS] Reset");
201: Log_Printf(LOG_KMS_LEVEL, "[KMS] Data = %08X",data);
202: break;
203: case KMSCMD_ASNDOUT:
204: Log_Printf(LOG_KMS_LEVEL, "[KMS] Analog sound out");
205: Log_Printf(LOG_KMS_LEVEL, "[KMS] Data = %08X",data);
206: break;
207: case KMSCMD_KMREG:
208: Log_Printf(LOG_KMS_LEVEL, "[KMS] Access keyboard/mouse register");
209: Log_Printf(LOG_KMS_LEVEL, "[KMS] Data = %08X",data);
210: access_km_reg(data);
211: break;
212: case KMSCMD_CTRLOUT:
213: Log_Printf(LOG_KMS_LEVEL, "[KMS] Access volume control logic");
214: Log_Printf(LOG_KMS_LEVEL, "[KMS] Data = %08X",data);
215: snd_gpo_access(data>>24);
216: break;
217: case KMSCMD_VOLCTRL:
218: Log_Printf(LOG_KMS_LEVEL, "[KMS] Access volume control (simple)");
219: Log_Printf(LOG_KMS_LEVEL, "[KMS] Data = %08X",data);
220: break;
221:
222: default: // commands without data
223: if ((command&KMSCMD_SIO_MASK)==KMSCMD_SND_OUT) {
224: Log_Printf(LOG_KMS_LEVEL, "[KMS] Sound out command:");
225:
226: if (command&SIO_ENABLE) {
227: Log_Printf(LOG_KMS_LEVEL, "[KMS] Sound out enable.");
228: if (command&SIO_DBL_SMPL) {
229: Log_Printf(LOG_KMS_LEVEL, "[KMS] Sound out double sample.");
230: if (command&SIO_ZERO) {
231: Log_Printf(LOG_KMS_LEVEL, "[KMS] Sound out double sample by zero filling.");
232: } else {
233: Log_Printf(LOG_KMS_LEVEL, "[KMS] Sound out double sample by repetition.");
234: }
235: } else {
236: Log_Printf(LOG_KMS_LEVEL, "[KMS] Sound out normal sample.");
237: }
238: snd_start_output(command&(SIO_DBL_SMPL|SIO_ZERO));
239: } else {
240: Log_Printf(LOG_KMS_LEVEL, "[KMS] Sound out disable.");
241: snd_stop_output();
242: }
243: } else if ((command&KMSCMD_SIO_MASK)==KMSCMD_SND_IN) {
244: Log_Printf(LOG_KMS_LEVEL, "[KMS] Sound in command");
245:
246: if (command&SIO_ENABLE) {
247: Log_Printf(LOG_KMS_LEVEL, "[KMS] Sound in enable.");
248: } else {
249: Log_Printf(LOG_KMS_LEVEL, "[KMS] Sound in disable.");
250: }
251: } else {
252: Log_Printf(LOG_WARN, "[KMS] Unknown command!");
253: }
254: return;
255: }
256: }
257:
258:
259: void KMS_Ctrl_Snd_Write(void) {
260: Uint8 val = IoMem[IoAccessCurrentAddress&IO_SEG_MASK];
261:
262: kms.status.snd_dma &= ~(SNDOUT_DMA_ENABLE|SNDIN_DMA_ENABLE);
263: kms.status.snd_dma |= (val&(SNDOUT_DMA_ENABLE|SNDIN_DMA_ENABLE));
264:
265: if (val&SNDOUT_DMA_UNDERRUN) {
266: kms.status.snd_dma &= ~(SNDOUT_DMA_UNDERRUN|SNDOUT_DMA_REQUEST);
267: set_interrupt(INT_SOUND_OVRUN, RELEASE_INT);
268: }
269: if (val&SNDIN_DMA_OVERRUN) {
270: kms.status.snd_dma &= ~(SNDIN_DMA_OVERRUN|SNDIN_DMA_REQUEST);
271: set_interrupt(INT_SOUND_OVRUN, RELEASE_INT);
272: }
273: }
274:
275: void KMS_Stat_Snd_Read(void) {
276: IoMem[IoAccessCurrentAddress&IO_SEG_MASK] = kms.status.snd_dma;
277: }
278:
279: void KMS_Ctrl_KM_Write(void) {
280: Uint8 val = IoMem[IoAccessCurrentAddress&IO_SEG_MASK];
281:
282: if (val&KBD_OVERRUN) {
283: kms.status.km &= ~(KBD_RECEIVED|KBD_OVERRUN|KBD_INT);
284: set_interrupt(INT_KEYMOUSE, RELEASE_INT);
285: }
286: if (val&NMI_RECEIVED) {
287: kms.status.km &= ~NMI_RECEIVED;
288: set_interrupt(INT_NMI, RELEASE_INT);
289: }
290: if (val&KMS_OVERRUN) {
291: kms.status.km &= ~(KMS_RECEIVED|KMS_OVERRUN|KMS_INT);
292: set_interrupt(INT_MONITOR, RELEASE_INT);
293: }
294: }
295:
296: void KMS_Stat_KM_Read(void) {
297: IoMem[IoAccessCurrentAddress&IO_SEG_MASK] = kms.status.km;
298: }
299:
300: void KMS_Ctrl_TX_Write(void) {
301: Uint8 val = IoMem[IoAccessCurrentAddress&IO_SEG_MASK];
302:
303: kms.status.transmit &= ~(KMS_ENABLE|TX_LOOP);
304: kms.status.transmit |= (val&(KMS_ENABLE|TX_LOOP));
305: }
306:
307: void KMS_Stat_TX_Read(void) {
308: IoMem[IoAccessCurrentAddress&IO_SEG_MASK] = kms.status.transmit;
309: }
310:
311: void KMS_Ctrl_Cmd_Write(void) {
312: kms.status.cmd = IoMem[IoAccessCurrentAddress&IO_SEG_MASK];
313: }
314:
315: void KMS_Stat_Cmd_Read(void) {
316: IoMem[IoAccessCurrentAddress&IO_SEG_MASK] = kms.status.cmd;
317: }
318:
319:
320: /* KMS data register (0x0200E004) */
321:
322: void KMS_Data_Write(void) {
323: kms.data = IoMem_ReadLong(IoAccessCurrentAddress&IO_SEG_MASK);
324: KMS_command(kms.status.cmd, kms.data);
325: }
326:
327: void KMS_Data_Read(void) {
328: IoMem_WriteLong(IoAccessCurrentAddress&IO_SEG_MASK, kms.data);
329: }
330:
331:
332: /* KMS keyboard and mouse data register (0x0200E008) *
333: *
334: * x--- ---- ---- ---- ---- ---- ---- ---- always 0
335: * -x-- ---- ---- ---- ---- ---- ---- ---- 1 = no response error, 0 = normal event
336: * --x- ---- ---- ---- ---- ---- ---- ---- 1 = user poll, 0 = internal poll
337: * ---x ---- ---- ---- ---- ---- ---- ---- 1 = invalid/master, 0 = valid/slave (user/internal)
338: * ---- xxxx ---- ---- ---- ---- ---- ---- device address (lowest bit 1 = mouse, 0 = keyboard)
339: * ---- ---- xxxx xxxx ---- ---- ---- ---- chip revision: 0 = old, 1 = new, 2 = digital
340: *
341: * Mouse data:
342: * ---- ---- ---- ---- xxxx xxx- ---- ---- mouse y
343: * ---- ---- ---- ---- ---- ---x ---- ---- right button up (1) or down (0)
344: * ---- ---- ---- ---- ---- ---- xxxx xxx- mouse x
345: * ---- ---- ---- ---- ---- ---- ---- ---x left button up (1) or down (0)
346: *
347: * Keyboard data:
348: * ---- ---- ---- ---- x--- ---- ---- ---- valid (1) or invalid (0)
349: * ---- ---- ---- ---- -x-- ---- ---- ---- right alt
350: * ---- ---- ---- ---- --x- ---- ---- ---- left alt
351: * ---- ---- ---- ---- ---x ---- ---- ---- right command
352: * ---- ---- ---- ---- ---- x--- ---- ---- left command
353: * ---- ---- ---- ---- ---- -x-- ---- ---- right shift
354: * ---- ---- ---- ---- ---- --x- ---- ---- left shift
355: * ---- ---- ---- ---- ---- ---x ---- ---- control
356: * ---- ---- ---- ---- ---- ---- x--- ---- key up (1) or down (0)
357: * ---- ---- ---- ---- ---- ---- -xxx xxxx keycode
358: */
359:
360: #define NO_RESPONSE_ERR 0x40000000
361: #define USER_POLL 0x20000000
362: #define DEVICE_INVALID 0x10000000
363: #define DEVICE_MASTER 0x10000000
364:
365: #define DEVICE_ADDR_MSK 0x0E000000
366: #define DEVICE_MOUSE 0x01000000
367:
368: #define MOUSE_Y 0x0000FE00
369: #define MOUSE_RIGHT_UP 0x00000100
370: #define MOUSE_X 0x000000FE
371: #define MOUSE_LEFT_UP 0x00000001
372:
373: #define KBD_KEY_VALID 0x00008000
374: #define KBD_MOD_MASK 0x00007F00
375: #define KBD_KEY_UP 0x00000080
376: #define KBD_KEY_MASK 0x0000007F
377:
378:
379: bool m_button_right = false;
380: bool m_button_left = false;
381: bool m_move_left = false;
382: bool m_move_up = false;
383: Uint8 m_move_x = 0;
384: Uint8 m_move_y = 0;
385:
386: Uint8 m_move_steps = 0;
387: void kms_mouse_move_step(void);
388:
389:
390: void KMS_KM_Data_Read(void) {
391: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, kms.km_data);
392:
393: kms.status.km &= ~(KBD_RECEIVED|KBD_INT);
394: set_interrupt(INT_KEYMOUSE, RELEASE_INT);
395: }
396:
397: void kms_interrupt(void) {
398: kms.status.cmd = KMSCMD_KBD_RECV;
399:
400: if (kms.status.km&KBD_RECEIVED) {
401: kms.status.km |= KBD_OVERRUN;
402: }
403: kms.status.km |= (KBD_RECEIVED|KBD_INT);
404: set_interrupt(INT_KEYMOUSE, SET_INT);
405: }
406:
407: bool kms_device_enabled(int dev_addr) {
408: int i,mask;
409:
410: for (i=28; i>4; i-=4) {
411: mask=(km_dev_msk>>i)&0xF;
412: if(mask==dev_addr && mask!=0xF)
413: return true;
414: }
415: Log_Printf(LOG_WARN, "[KMS] Device %i disabled (mask: %08X)",dev_addr,km_dev_msk);
416: return false;
417: }
418:
419: void kms_keydown(Uint8 modkeys, Uint8 keycode) {
420: if ((keycode==0x26)&&(modkeys&0x18)) { /* backquote and one or both command keys */
421: Log_Printf(LOG_WARN, "Keyboard initiated NMI!");
422: set_interrupt(INT_NMI, SET_INT);
423: return;
424: }
425:
426: if ((keycode==0x25)&&((modkeys&0x28)==0x28)) { /* asterisk and left alt and left command key */
427: Log_Printf(LOG_WARN, "Keyboard initiated CPU reset!");
428: M68000_Reset(false);
429: return;
430: }
431:
432: if (keycode==0x58) { /* Power key */
433: rtc_request_power_down();
434: return;
435: }
436:
437: if (kms_device_enabled(km_address)) {
438: kms.km_data = (km_address<<24)|DEVICE_MASTER; /* keyboard */
439:
440: kms.km_data |= (modkeys<<8)|keycode|KBD_KEY_VALID;
441:
442: kms_interrupt();
443: }
444: }
445:
446: void kms_keyup(Uint8 modkeys, Uint8 keycode) {
447: if (keycode==0x58) {
448: rtc_stop_pdown_request();
449: return;
450: }
451:
452: if (kms_device_enabled(km_address)) {
453: kms.km_data = (km_address<<24)|DEVICE_MASTER; /* keyboard */
454:
455: kms.km_data |= (modkeys<<8)|keycode|KBD_KEY_VALID|KBD_KEY_UP;
456:
457: kms_interrupt();
458: }
459: }
460:
461: void kms_mouse_button(bool left, bool down) {
462: if (left) {
463: m_button_left = down;
464: } else {
465: m_button_right = down;
466: }
467:
468: if (kms_device_enabled(km_address|KM_ADDR_MOUSE)) {
469: kms.km_data = (km_address|KM_ADDR_MOUSE)<<24; /* mouse */
470:
471: kms.km_data |= m_button_left?0:MOUSE_LEFT_UP;
472: kms.km_data |= m_button_right?0:MOUSE_RIGHT_UP;
473:
474: kms_interrupt();
475: }
476: }
477:
478: void kms_mouse_move(int x, bool left, int y, bool up) {
479:
480: if (x<0 || y<0) {
481: abort();
482: }
483:
484: if (x>0x40)
485: x=0x40;
486: if (y>0x40)
487: y=0x40;
488:
489: m_move_left = left;
490: m_move_up = up;
491:
492: m_move_x = x;
493: m_move_y = y;
494:
495: m_move_steps = 8;
496:
497: CycInt_AddRelativeInterrupt(CYCLES_PER_FRAME/10, INT_CPU_CYCLE, INTERRUPT_MOUSE);
498: }
499:
500: void kms_mouse_move_step(void) {
501: int x = 0;
502: int y = 0;
503:
504: if (m_move_x>0) {
505: x = m_move_x/m_move_steps;
506: m_move_x -= x;
507: }
508: if (m_move_y>0) {
509: y = m_move_y/m_move_steps;
510: m_move_y -= y;
511: }
512:
513: m_move_steps--;
514:
515: if (!m_move_left && x>0) /* right */
516: x=(0x40-x)|0x40;
517: if (!m_move_up && y>0) /* down */
518: y=(0x40-y)|0x40;
519:
520: if (kms_device_enabled(km_address|KM_ADDR_MOUSE)) {
521: kms.km_data = (km_address|KM_ADDR_MOUSE)<<24; /* mouse */
522:
523: kms.km_data |= (x<<1)&MOUSE_X;
524: kms.km_data |= (y<<9)&MOUSE_Y;
525:
526: kms.km_data |= m_button_left?0:MOUSE_LEFT_UP;
527: kms.km_data |= m_button_right?0:MOUSE_RIGHT_UP;
528:
529: kms_interrupt();
530: }
531: }
532:
533: void kms_response(void) {
534: kms.km_data = km_address<<24; /* keyboard */
535: kms.km_data |= USER_POLL;
536: kms.km_data |= (NO_RESPONSE_ERR|DEVICE_INVALID); /* checked on real hardware */
537:
538: kms_interrupt();
539: }
540:
541: void Mouse_Handler(void) {
542: CycInt_AcknowledgeInterrupt();
543:
544: if (m_move_steps>0 && (m_move_x>0 || m_move_y>0)) {
545: kms_mouse_move_step();
546:
547: CycInt_AddRelativeInterrupt(CYCLES_PER_FRAME/10, INT_CPU_CYCLE, INTERRUPT_MOUSE);
548: }
549: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.