shithub: minivmac

ref: 5f3987b8e5f4c1ce992e5f9caff744af822bcba2
dir: /src/KBRDEMDV.c/

View raw version
/*
	KBRDEMDV.c

	Copyright (C) 2006 Philip Cummins, Paul C. Pratt

	You can redistribute this file and/or modify it under the terms
	of version 2 of the GNU General Public License as published by
	the Free Software Foundation.  You should have received a copy
	of the license along with this file; see the file COPYING.

	This file is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	license for more details.
*/

/*
	KeyBoaRD EMulated DeVice

	Emulation of the keyboard in the Mac Plus.

	This code adapted from "Keyboard.c" in vMac by Philip Cummins.
*/

#ifndef AllFiles
#include "SYSDEPNS.h"
#include "MYOSGLUE.h"
#include "EMCONFIG.h"
#include "GLOBGLUE.h"
#endif

#include "KBRDEMDV.h"

#ifdef _VIA_Debug
#include <stdio.h>
#endif

/*
	ReportAbnormalID unused 0x0B03 - 0x0BFF
*/

IMPORTPROC KYBD_ShiftOutData(ui3b v);
IMPORTFUNC ui3b KYBD_ShiftInData(void);

enum {
	kKybdStateIdle,
	kKybdStateRecievingCommand,
	kKybdStateRecievedCommand,
	kKybdStateRecievingEndCommand,

	kKybdStates
};

LOCALVAR int KybdState = kKybdStateIdle;

LOCALVAR blnr HaveKeyBoardResult = falseblnr;
LOCALVAR ui3b KeyBoardResult;

LOCALPROC GotKeyBoardData(ui3b v)
{
	if (KybdState != kKybdStateIdle) {
		HaveKeyBoardResult = trueblnr;
		KeyBoardResult = v;
	} else {
		KYBD_ShiftOutData(v);
		VIA1_iCB2 = 1;
	}
}

LOCALVAR ui3b InstantCommandData = 0x7B;

LOCALFUNC blnr AttemptToFinishInquiry(void)
{
	int i;
	blnr KeyDown;
	ui3b Keyboard_Data;

	if (FindKeyEvent(&i, &KeyDown)) {
		if (i < 64) {
			Keyboard_Data = i << 1;
			if (! KeyDown) {
				Keyboard_Data += 128;
			}
		} else {
			Keyboard_Data = 121;
			InstantCommandData = (i - 64) << 1;
			if (! KeyDown) {
				InstantCommandData += 128;
			}
		}
		GotKeyBoardData(Keyboard_Data);
		return trueblnr;
	} else {
		return falseblnr;
	}
}

#define MaxKeyboardWait 16 /* in 60ths of a second */
	/*
		Code in the mac rom will reset the keyboard if
		it hasn't been heard from in 32/60th of a second.
		So time out and send something before that
		to keep connection.
	*/

LOCALVAR int InquiryCommandTimer = 0;

GLOBALPROC DoKybd_ReceiveCommand(void)
{
	if (KybdState != kKybdStateRecievingCommand) {
		ReportAbnormalID(0x0B01,
			"KybdState != kKybdStateRecievingCommand");
	} else {
		ui3b in = KYBD_ShiftInData();

		KybdState = kKybdStateRecievedCommand;

		switch (in) {
			case 0x10 : /* Inquiry Command */
				if (! AttemptToFinishInquiry()) {
					InquiryCommandTimer = MaxKeyboardWait;
				}
				break;
			case 0x14 : /* Instant Command */
				GotKeyBoardData(InstantCommandData);
				InstantCommandData = 0x7B;
				break;
			case 0x16 : /* Model Command */
				GotKeyBoardData(0x0b /* 0x01 */);
					/* Test value, means Model 0, no extra devices */
				/*
					Fixed by Hoshi Takanori -
						it uses the proper keyboard type now
				*/
				break;
			case 0x36 : /* Test Command */
				GotKeyBoardData(0x7D);
				break;
			case 0x00:
				GotKeyBoardData(0);
				break;
			default :
				/* Debugger(); */
				GotKeyBoardData(0);
				break;
		}
	}
}

GLOBALPROC DoKybd_ReceiveEndCommand(void)
{
	if (KybdState != kKybdStateRecievingEndCommand) {
		ReportAbnormalID(0x0B02,
			"KybdState != kKybdStateRecievingEndCommand");
	} else {
		KybdState = kKybdStateIdle;
#ifdef _VIA_Debug
		fprintf(stderr, "enter DoKybd_ReceiveEndCommand\n");
#endif
		if (HaveKeyBoardResult) {
#ifdef _VIA_Debug
			fprintf(stderr, "HaveKeyBoardResult: %d\n", KeyBoardResult);
#endif
			HaveKeyBoardResult = falseblnr;
			KYBD_ShiftOutData(KeyBoardResult);
			VIA1_iCB2 = 1;
		}
	}
}

GLOBALPROC Kybd_DataLineChngNtfy(void)
{
	switch (KybdState) {
		case kKybdStateIdle:
			if (VIA1_iCB2 == 0) {
				KybdState = kKybdStateRecievingCommand;
#ifdef _VIA_Debug
				fprintf(stderr, "posting kICT_Kybd_ReceiveCommand\n");
#endif
				ICT_add(kICT_Kybd_ReceiveCommand,
					6800UL * kCycleScale / 64 * kMyClockMult);

				if (InquiryCommandTimer != 0) {
					InquiryCommandTimer = 0; /* abort Inquiry */
				}
			}
			break;
		case kKybdStateRecievedCommand:
			if (VIA1_iCB2 == 1) {
				KybdState = kKybdStateRecievingEndCommand;
#ifdef _VIA_Debug
				fprintf(stderr,
					"posting kICT_Kybd_ReceiveEndCommand\n");
#endif
				ICT_add(kICT_Kybd_ReceiveEndCommand,
					6800UL * kCycleScale / 64 * kMyClockMult);
			}
			break;
	}
}

GLOBALPROC KeyBoard_Update(void)
{
	if (InquiryCommandTimer != 0) {
		if (AttemptToFinishInquiry()) {
			InquiryCommandTimer = 0;
		} else {
			--InquiryCommandTimer;
			if (InquiryCommandTimer == 0) {
				GotKeyBoardData(0x7B);
			}
		}
	}
}