mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-09 01:28:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
8
arch/m68k/atari/Makefile
Normal file
8
arch/m68k/atari/Makefile
Normal file
|
@ -0,0 +1,8 @@
|
|||
#
|
||||
# Makefile for Linux arch/m68k/atari source directory
|
||||
#
|
||||
|
||||
obj-y := config.o time.o debug.o ataints.o stdma.o \
|
||||
atasound.o stram.o
|
||||
|
||||
obj-$(CONFIG_ATARI_KBD_CORE) += atakeyb.o
|
391
arch/m68k/atari/ataints.c
Normal file
391
arch/m68k/atari/ataints.c
Normal file
|
@ -0,0 +1,391 @@
|
|||
/*
|
||||
* arch/m68k/atari/ataints.c -- Atari Linux interrupt handling code
|
||||
*
|
||||
* 5/2/94 Roman Hodek:
|
||||
* Added support for TT interrupts; setup for TT SCU (may someone has
|
||||
* twiddled there and we won't get the right interrupts :-()
|
||||
*
|
||||
* Major change: The device-independent code in m68k/ints.c didn't know
|
||||
* about non-autovec ints yet. It hardcoded the number of possible ints to
|
||||
* 7 (IRQ1...IRQ7). But the Atari has lots of non-autovec ints! I made the
|
||||
* number of possible ints a constant defined in interrupt.h, which is
|
||||
* 47 for the Atari. So we can call request_irq() for all Atari interrupts
|
||||
* just the normal way. Additionally, all vectors >= 48 are initialized to
|
||||
* call trap() instead of inthandler(). This must be changed here, too.
|
||||
*
|
||||
* 1995-07-16 Lars Brinkhoff <f93labr@dd.chalmers.se>:
|
||||
* Corrected a bug in atari_add_isr() which rejected all SCC
|
||||
* interrupt sources if there were no TT MFP!
|
||||
*
|
||||
* 12/13/95: New interface functions atari_level_triggered_int() and
|
||||
* atari_register_vme_int() as support for level triggered VME interrupts.
|
||||
*
|
||||
* 02/12/96: (Roman)
|
||||
* Total rewrite of Atari interrupt handling, for new scheme see comments
|
||||
* below.
|
||||
*
|
||||
* 1996-09-03 lars brinkhoff <f93labr@dd.chalmers.se>:
|
||||
* Added new function atari_unregister_vme_int(), and
|
||||
* modified atari_register_vme_int() as well as IS_VALID_INTNO()
|
||||
* to work with it.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
#include <asm/traps.h>
|
||||
|
||||
#include <asm/atarihw.h>
|
||||
#include <asm/atariints.h>
|
||||
#include <asm/atari_stdma.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/entry.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
|
||||
/*
|
||||
* Atari interrupt handling scheme:
|
||||
* --------------------------------
|
||||
*
|
||||
* All interrupt source have an internal number (defined in
|
||||
* <asm/atariints.h>): Autovector interrupts are 1..7, then follow ST-MFP,
|
||||
* TT-MFP, SCC, and finally VME interrupts. Vector numbers for the latter can
|
||||
* be allocated by atari_register_vme_int().
|
||||
*/
|
||||
|
||||
/*
|
||||
* Bitmap for free interrupt vector numbers
|
||||
* (new vectors starting from 0x70 can be allocated by
|
||||
* atari_register_vme_int())
|
||||
*/
|
||||
static int free_vme_vec_bitmap;
|
||||
|
||||
/* GK:
|
||||
* HBL IRQ handler for Falcon. Nobody needs it :-)
|
||||
* ++andreas: raise ipl to disable further HBLANK interrupts.
|
||||
*/
|
||||
asmlinkage void falcon_hblhandler(void);
|
||||
asm(".text\n"
|
||||
__ALIGN_STR "\n\t"
|
||||
"falcon_hblhandler:\n\t"
|
||||
"orw #0x200,%sp@\n\t" /* set saved ipl to 2 */
|
||||
"rte");
|
||||
|
||||
extern void atari_microwire_cmd(int cmd);
|
||||
|
||||
static unsigned int atari_irq_startup(struct irq_data *data)
|
||||
{
|
||||
unsigned int irq = data->irq;
|
||||
|
||||
m68k_irq_startup(data);
|
||||
atari_turnon_irq(irq);
|
||||
atari_enable_irq(irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void atari_irq_shutdown(struct irq_data *data)
|
||||
{
|
||||
unsigned int irq = data->irq;
|
||||
|
||||
atari_disable_irq(irq);
|
||||
atari_turnoff_irq(irq);
|
||||
m68k_irq_shutdown(data);
|
||||
|
||||
if (irq == IRQ_AUTO_4)
|
||||
vectors[VEC_INT4] = falcon_hblhandler;
|
||||
}
|
||||
|
||||
static void atari_irq_enable(struct irq_data *data)
|
||||
{
|
||||
atari_enable_irq(data->irq);
|
||||
}
|
||||
|
||||
static void atari_irq_disable(struct irq_data *data)
|
||||
{
|
||||
atari_disable_irq(data->irq);
|
||||
}
|
||||
|
||||
static struct irq_chip atari_irq_chip = {
|
||||
.name = "atari",
|
||||
.irq_startup = atari_irq_startup,
|
||||
.irq_shutdown = atari_irq_shutdown,
|
||||
.irq_enable = atari_irq_enable,
|
||||
.irq_disable = atari_irq_disable,
|
||||
};
|
||||
|
||||
/*
|
||||
* ST-MFP timer D chained interrupts - each driver gets its own timer
|
||||
* interrupt instance.
|
||||
*/
|
||||
|
||||
struct mfptimerbase {
|
||||
volatile struct MFP *mfp;
|
||||
unsigned char mfp_mask, mfp_data;
|
||||
unsigned short int_mask;
|
||||
int handler_irq, mfptimer_irq, server_irq;
|
||||
char *name;
|
||||
} stmfp_base = {
|
||||
.mfp = &st_mfp,
|
||||
.int_mask = 0x0,
|
||||
.handler_irq = IRQ_MFP_TIMD,
|
||||
.mfptimer_irq = IRQ_MFP_TIMER1,
|
||||
.name = "MFP Timer D"
|
||||
};
|
||||
|
||||
static irqreturn_t mfptimer_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct mfptimerbase *base = dev_id;
|
||||
int mach_irq;
|
||||
unsigned char ints;
|
||||
|
||||
mach_irq = base->mfptimer_irq;
|
||||
ints = base->int_mask;
|
||||
for (; ints; mach_irq++, ints >>= 1) {
|
||||
if (ints & 1)
|
||||
generic_handle_irq(mach_irq);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
static void atari_mfptimer_enable(struct irq_data *data)
|
||||
{
|
||||
int mfp_num = data->irq - IRQ_MFP_TIMER1;
|
||||
stmfp_base.int_mask |= 1 << mfp_num;
|
||||
atari_enable_irq(IRQ_MFP_TIMD);
|
||||
}
|
||||
|
||||
static void atari_mfptimer_disable(struct irq_data *data)
|
||||
{
|
||||
int mfp_num = data->irq - IRQ_MFP_TIMER1;
|
||||
stmfp_base.int_mask &= ~(1 << mfp_num);
|
||||
if (!stmfp_base.int_mask)
|
||||
atari_disable_irq(IRQ_MFP_TIMD);
|
||||
}
|
||||
|
||||
static struct irq_chip atari_mfptimer_chip = {
|
||||
.name = "timer_d",
|
||||
.irq_enable = atari_mfptimer_enable,
|
||||
.irq_disable = atari_mfptimer_disable,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* EtherNAT CPLD interrupt handling
|
||||
* CPLD interrupt register is at phys. 0x80000023
|
||||
* Need this mapped in at interrupt startup time
|
||||
* Possibly need this mapped on demand anyway -
|
||||
* EtherNAT USB driver needs to disable IRQ before
|
||||
* startup!
|
||||
*/
|
||||
|
||||
static unsigned char *enat_cpld;
|
||||
|
||||
static unsigned int atari_ethernat_startup(struct irq_data *data)
|
||||
{
|
||||
int enat_num = 140 - data->irq + 1;
|
||||
|
||||
m68k_irq_startup(data);
|
||||
/*
|
||||
* map CPLD interrupt register
|
||||
*/
|
||||
if (!enat_cpld)
|
||||
enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2);
|
||||
/*
|
||||
* do _not_ enable the USB chip interrupt here - causes interrupt storm
|
||||
* and triggers dead interrupt watchdog
|
||||
* Need to reset the USB chip to a sane state in early startup before
|
||||
* removing this hack
|
||||
*/
|
||||
if (enat_num == 1)
|
||||
*enat_cpld |= 1 << enat_num;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void atari_ethernat_enable(struct irq_data *data)
|
||||
{
|
||||
int enat_num = 140 - data->irq + 1;
|
||||
/*
|
||||
* map CPLD interrupt register
|
||||
*/
|
||||
if (!enat_cpld)
|
||||
enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2);
|
||||
*enat_cpld |= 1 << enat_num;
|
||||
}
|
||||
|
||||
static void atari_ethernat_disable(struct irq_data *data)
|
||||
{
|
||||
int enat_num = 140 - data->irq + 1;
|
||||
/*
|
||||
* map CPLD interrupt register
|
||||
*/
|
||||
if (!enat_cpld)
|
||||
enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2);
|
||||
*enat_cpld &= ~(1 << enat_num);
|
||||
}
|
||||
|
||||
static void atari_ethernat_shutdown(struct irq_data *data)
|
||||
{
|
||||
int enat_num = 140 - data->irq + 1;
|
||||
if (enat_cpld) {
|
||||
*enat_cpld &= ~(1 << enat_num);
|
||||
iounmap(enat_cpld);
|
||||
enat_cpld = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static struct irq_chip atari_ethernat_chip = {
|
||||
.name = "ethernat",
|
||||
.irq_startup = atari_ethernat_startup,
|
||||
.irq_shutdown = atari_ethernat_shutdown,
|
||||
.irq_enable = atari_ethernat_enable,
|
||||
.irq_disable = atari_ethernat_disable,
|
||||
};
|
||||
|
||||
/*
|
||||
* void atari_init_IRQ (void)
|
||||
*
|
||||
* Parameters: None
|
||||
*
|
||||
* Returns: Nothing
|
||||
*
|
||||
* This function should be called during kernel startup to initialize
|
||||
* the atari IRQ handling routines.
|
||||
*/
|
||||
|
||||
void __init atari_init_IRQ(void)
|
||||
{
|
||||
m68k_setup_user_interrupt(VEC_USER, NUM_ATARI_SOURCES - IRQ_USER);
|
||||
m68k_setup_irq_controller(&atari_irq_chip, handle_simple_irq, 1,
|
||||
NUM_ATARI_SOURCES - 1);
|
||||
|
||||
/* Initialize the MFP(s) */
|
||||
|
||||
#ifdef ATARI_USE_SOFTWARE_EOI
|
||||
st_mfp.vec_adr = 0x48; /* Software EOI-Mode */
|
||||
#else
|
||||
st_mfp.vec_adr = 0x40; /* Automatic EOI-Mode */
|
||||
#endif
|
||||
st_mfp.int_en_a = 0x00; /* turn off MFP-Ints */
|
||||
st_mfp.int_en_b = 0x00;
|
||||
st_mfp.int_mk_a = 0xff; /* no Masking */
|
||||
st_mfp.int_mk_b = 0xff;
|
||||
|
||||
if (ATARIHW_PRESENT(TT_MFP)) {
|
||||
#ifdef ATARI_USE_SOFTWARE_EOI
|
||||
tt_mfp.vec_adr = 0x58; /* Software EOI-Mode */
|
||||
#else
|
||||
tt_mfp.vec_adr = 0x50; /* Automatic EOI-Mode */
|
||||
#endif
|
||||
tt_mfp.int_en_a = 0x00; /* turn off MFP-Ints */
|
||||
tt_mfp.int_en_b = 0x00;
|
||||
tt_mfp.int_mk_a = 0xff; /* no Masking */
|
||||
tt_mfp.int_mk_b = 0xff;
|
||||
}
|
||||
|
||||
if (ATARIHW_PRESENT(SCC) && !atari_SCC_reset_done) {
|
||||
atari_scc.cha_a_ctrl = 9;
|
||||
MFPDELAY();
|
||||
atari_scc.cha_a_ctrl = (char) 0xc0; /* hardware reset */
|
||||
}
|
||||
|
||||
if (ATARIHW_PRESENT(SCU)) {
|
||||
/* init the SCU if present */
|
||||
tt_scu.sys_mask = 0x10; /* enable VBL (for the cursor) and
|
||||
* disable HSYNC interrupts (who
|
||||
* needs them?) MFP and SCC are
|
||||
* enabled in VME mask
|
||||
*/
|
||||
tt_scu.vme_mask = 0x60; /* enable MFP and SCC ints */
|
||||
} else {
|
||||
/* If no SCU and no Hades, the HSYNC interrupt needs to be
|
||||
* disabled this way. (Else _inthandler in kernel/sys_call.S
|
||||
* gets overruns)
|
||||
*/
|
||||
|
||||
vectors[VEC_INT2] = falcon_hblhandler;
|
||||
vectors[VEC_INT4] = falcon_hblhandler;
|
||||
}
|
||||
|
||||
if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) {
|
||||
/* Initialize the LM1992 Sound Controller to enable
|
||||
the PSG sound. This is misplaced here, it should
|
||||
be in an atasound_init(), that doesn't exist yet. */
|
||||
atari_microwire_cmd(MW_LM1992_PSG_HIGH);
|
||||
}
|
||||
|
||||
stdma_init();
|
||||
|
||||
/* Initialize the PSG: all sounds off, both ports output */
|
||||
sound_ym.rd_data_reg_sel = 7;
|
||||
sound_ym.wd_data = 0xff;
|
||||
|
||||
m68k_setup_irq_controller(&atari_mfptimer_chip, handle_simple_irq,
|
||||
IRQ_MFP_TIMER1, 8);
|
||||
|
||||
irq_set_status_flags(IRQ_MFP_TIMER1, IRQ_IS_POLLED);
|
||||
irq_set_status_flags(IRQ_MFP_TIMER2, IRQ_IS_POLLED);
|
||||
|
||||
/* prepare timer D data for use as poll interrupt */
|
||||
/* set Timer D data Register - needs to be > 0 */
|
||||
st_mfp.tim_dt_d = 254; /* < 100 Hz */
|
||||
/* start timer D, div = 1:100 */
|
||||
st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 0xf0) | 0x6;
|
||||
|
||||
/* request timer D dispatch handler */
|
||||
if (request_irq(IRQ_MFP_TIMD, mfptimer_handler, IRQF_SHARED,
|
||||
stmfp_base.name, &stmfp_base))
|
||||
pr_err("Couldn't register %s interrupt\n", stmfp_base.name);
|
||||
|
||||
/*
|
||||
* EtherNAT ethernet / USB interrupt handlers
|
||||
*/
|
||||
|
||||
m68k_setup_irq_controller(&atari_ethernat_chip, handle_simple_irq,
|
||||
139, 2);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* atari_register_vme_int() returns the number of a free interrupt vector for
|
||||
* hardware with a programmable int vector (probably a VME board).
|
||||
*/
|
||||
|
||||
unsigned int atari_register_vme_int(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; i++)
|
||||
if ((free_vme_vec_bitmap & (1 << i)) == 0)
|
||||
break;
|
||||
|
||||
if (i == 16)
|
||||
return 0;
|
||||
|
||||
free_vme_vec_bitmap |= 1 << i;
|
||||
return VME_SOURCE_BASE + i;
|
||||
}
|
||||
EXPORT_SYMBOL(atari_register_vme_int);
|
||||
|
||||
|
||||
void atari_unregister_vme_int(unsigned int irq)
|
||||
{
|
||||
if (irq >= VME_SOURCE_BASE && irq < VME_SOURCE_BASE + VME_MAX_SOURCES) {
|
||||
irq -= VME_SOURCE_BASE;
|
||||
free_vme_vec_bitmap &= ~(1 << irq);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(atari_unregister_vme_int);
|
||||
|
||||
|
638
arch/m68k/atari/atakeyb.c
Normal file
638
arch/m68k/atari/atakeyb.c
Normal file
|
@ -0,0 +1,638 @@
|
|||
/*
|
||||
* Atari Keyboard driver for 680x0 Linux
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Atari support by Robert de Vries
|
||||
* enhanced by Bjoern Brauel and Roman Hodek
|
||||
*
|
||||
* 2.6 and input cleanup (removed autorepeat stuff) for 2.6.21
|
||||
* 06/07 Michael Schmitz
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/keyboard.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/kd.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kbd_kern.h>
|
||||
|
||||
#include <asm/atariints.h>
|
||||
#include <asm/atarihw.h>
|
||||
#include <asm/atarikb.h>
|
||||
#include <asm/atari_joystick.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
|
||||
/* Hook for MIDI serial driver */
|
||||
void (*atari_MIDI_interrupt_hook) (void);
|
||||
/* Hook for keyboard inputdev driver */
|
||||
void (*atari_input_keyboard_interrupt_hook) (unsigned char, char);
|
||||
/* Hook for mouse inputdev driver */
|
||||
void (*atari_input_mouse_interrupt_hook) (char *);
|
||||
EXPORT_SYMBOL(atari_input_keyboard_interrupt_hook);
|
||||
EXPORT_SYMBOL(atari_input_mouse_interrupt_hook);
|
||||
|
||||
/* variables for IKBD self test: */
|
||||
|
||||
/* state: 0: off; >0: in progress; >1: 0xf1 received */
|
||||
static volatile int ikbd_self_test;
|
||||
/* timestamp when last received a char */
|
||||
static volatile unsigned long self_test_last_rcv;
|
||||
/* bitmap of keys reported as broken */
|
||||
static unsigned long broken_keys[128/(sizeof(unsigned long)*8)] = { 0, };
|
||||
|
||||
#define BREAK_MASK (0x80)
|
||||
|
||||
/*
|
||||
* ++roman: The following changes were applied manually:
|
||||
*
|
||||
* - The Alt (= Meta) key works in combination with Shift and
|
||||
* Control, e.g. Alt+Shift+a sends Meta-A (0xc1), Alt+Control+A sends
|
||||
* Meta-Ctrl-A (0x81) ...
|
||||
*
|
||||
* - The parentheses on the keypad send '(' and ')' with all
|
||||
* modifiers (as would do e.g. keypad '+'), but they cannot be used as
|
||||
* application keys (i.e. sending Esc O c).
|
||||
*
|
||||
* - HELP and UNDO are mapped to be F21 and F24, resp, that send the
|
||||
* codes "\E[M" and "\E[P". (This is better than the old mapping to
|
||||
* F11 and F12, because these codes are on Shift+F1/2 anyway.) This
|
||||
* way, applications that allow their own keyboard mappings
|
||||
* (e.g. tcsh, X Windows) can be configured to use them in the way
|
||||
* the label suggests (providing help or undoing).
|
||||
*
|
||||
* - Console switching is done with Alt+Fx (consoles 1..10) and
|
||||
* Shift+Alt+Fx (consoles 11..20).
|
||||
*
|
||||
* - The misc. special function implemented in the kernel are mapped
|
||||
* to the following key combinations:
|
||||
*
|
||||
* ClrHome -> Home/Find
|
||||
* Shift + ClrHome -> End/Select
|
||||
* Shift + Up -> Page Up
|
||||
* Shift + Down -> Page Down
|
||||
* Alt + Help -> show system status
|
||||
* Shift + Help -> show memory info
|
||||
* Ctrl + Help -> show registers
|
||||
* Ctrl + Alt + Del -> Reboot
|
||||
* Alt + Undo -> switch to last console
|
||||
* Shift + Undo -> send interrupt
|
||||
* Alt + Insert -> stop/start output (same as ^S/^Q)
|
||||
* Alt + Up -> Scroll back console (if implemented)
|
||||
* Alt + Down -> Scroll forward console (if implemented)
|
||||
* Alt + CapsLock -> NumLock
|
||||
*
|
||||
* ++Andreas:
|
||||
*
|
||||
* - Help mapped to K_HELP
|
||||
* - Undo mapped to K_UNDO (= K_F246)
|
||||
* - Keypad Left/Right Parenthesis mapped to new K_PPAREN[LR]
|
||||
*/
|
||||
|
||||
typedef enum kb_state_t {
|
||||
KEYBOARD, AMOUSE, RMOUSE, JOYSTICK, CLOCK, RESYNC
|
||||
} KB_STATE_T;
|
||||
|
||||
#define IS_SYNC_CODE(sc) ((sc) >= 0x04 && (sc) <= 0xfb)
|
||||
|
||||
typedef struct keyboard_state {
|
||||
unsigned char buf[6];
|
||||
int len;
|
||||
KB_STATE_T state;
|
||||
} KEYBOARD_STATE;
|
||||
|
||||
KEYBOARD_STATE kb_state;
|
||||
|
||||
/* ++roman: If a keyboard overrun happened, we can't tell in general how much
|
||||
* bytes have been lost and in which state of the packet structure we are now.
|
||||
* This usually causes keyboards bytes to be interpreted as mouse movements
|
||||
* and vice versa, which is very annoying. It seems better to throw away some
|
||||
* bytes (that are usually mouse bytes) than to misinterpret them. Therefore I
|
||||
* introduced the RESYNC state for IKBD data. In this state, the bytes up to
|
||||
* one that really looks like a key event (0x04..0xf2) or the start of a mouse
|
||||
* packet (0xf8..0xfb) are thrown away, but at most 2 bytes. This at least
|
||||
* speeds up the resynchronization of the event structure, even if maybe a
|
||||
* mouse movement is lost. However, nothing is perfect. For bytes 0x01..0x03,
|
||||
* it's really hard to decide whether they're mouse or keyboard bytes. Since
|
||||
* overruns usually occur when moving the Atari mouse rapidly, they're seen as
|
||||
* mouse bytes here. If this is wrong, only a make code of the keyboard gets
|
||||
* lost, which isn't too bad. Losing a break code would be disastrous,
|
||||
* because then the keyboard repeat strikes...
|
||||
*/
|
||||
|
||||
static irqreturn_t atari_keyboard_interrupt(int irq, void *dummy)
|
||||
{
|
||||
u_char acia_stat;
|
||||
int scancode;
|
||||
int break_flag;
|
||||
|
||||
repeat:
|
||||
if (acia.mid_ctrl & ACIA_IRQ)
|
||||
if (atari_MIDI_interrupt_hook)
|
||||
atari_MIDI_interrupt_hook();
|
||||
acia_stat = acia.key_ctrl;
|
||||
/* check out if the interrupt came from this ACIA */
|
||||
if (!((acia_stat | acia.mid_ctrl) & ACIA_IRQ))
|
||||
return IRQ_HANDLED;
|
||||
|
||||
if (acia_stat & ACIA_OVRN) {
|
||||
/* a very fast typist or a slow system, give a warning */
|
||||
/* ...happens often if interrupts were disabled for too long */
|
||||
printk(KERN_DEBUG "Keyboard overrun\n");
|
||||
scancode = acia.key_data;
|
||||
if (ikbd_self_test)
|
||||
/* During self test, don't do resyncing, just process the code */
|
||||
goto interpret_scancode;
|
||||
else if (IS_SYNC_CODE(scancode)) {
|
||||
/* This code seem already to be the start of a new packet or a
|
||||
* single scancode */
|
||||
kb_state.state = KEYBOARD;
|
||||
goto interpret_scancode;
|
||||
} else {
|
||||
/* Go to RESYNC state and skip this byte */
|
||||
kb_state.state = RESYNC;
|
||||
kb_state.len = 1; /* skip max. 1 another byte */
|
||||
goto repeat;
|
||||
}
|
||||
}
|
||||
|
||||
if (acia_stat & ACIA_RDRF) {
|
||||
/* received a character */
|
||||
scancode = acia.key_data; /* get it or reset the ACIA, I'll get it! */
|
||||
tasklet_schedule(&keyboard_tasklet);
|
||||
interpret_scancode:
|
||||
switch (kb_state.state) {
|
||||
case KEYBOARD:
|
||||
switch (scancode) {
|
||||
case 0xF7:
|
||||
kb_state.state = AMOUSE;
|
||||
kb_state.len = 0;
|
||||
break;
|
||||
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
kb_state.state = RMOUSE;
|
||||
kb_state.len = 1;
|
||||
kb_state.buf[0] = scancode;
|
||||
break;
|
||||
|
||||
case 0xFC:
|
||||
kb_state.state = CLOCK;
|
||||
kb_state.len = 0;
|
||||
break;
|
||||
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
kb_state.state = JOYSTICK;
|
||||
kb_state.len = 1;
|
||||
kb_state.buf[0] = scancode;
|
||||
break;
|
||||
|
||||
case 0xF1:
|
||||
/* during self-test, note that 0xf1 received */
|
||||
if (ikbd_self_test) {
|
||||
++ikbd_self_test;
|
||||
self_test_last_rcv = jiffies;
|
||||
break;
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
|
||||
default:
|
||||
break_flag = scancode & BREAK_MASK;
|
||||
scancode &= ~BREAK_MASK;
|
||||
if (ikbd_self_test) {
|
||||
/* Scancodes sent during the self-test stand for broken
|
||||
* keys (keys being down). The code *should* be a break
|
||||
* code, but nevertheless some AT keyboard interfaces send
|
||||
* make codes instead. Therefore, simply ignore
|
||||
* break_flag...
|
||||
*/
|
||||
int keyval, keytyp;
|
||||
|
||||
set_bit(scancode, broken_keys);
|
||||
self_test_last_rcv = jiffies;
|
||||
/* new Linux scancodes; approx. */
|
||||
keyval = scancode;
|
||||
keytyp = KTYP(keyval) - 0xf0;
|
||||
keyval = KVAL(keyval);
|
||||
|
||||
printk(KERN_WARNING "Key with scancode %d ", scancode);
|
||||
if (keytyp == KT_LATIN || keytyp == KT_LETTER) {
|
||||
if (keyval < ' ')
|
||||
printk("('^%c') ", keyval + '@');
|
||||
else
|
||||
printk("('%c') ", keyval);
|
||||
}
|
||||
printk("is broken -- will be ignored.\n");
|
||||
break;
|
||||
} else if (test_bit(scancode, broken_keys))
|
||||
break;
|
||||
|
||||
if (atari_input_keyboard_interrupt_hook)
|
||||
atari_input_keyboard_interrupt_hook((unsigned char)scancode, !break_flag);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case AMOUSE:
|
||||
kb_state.buf[kb_state.len++] = scancode;
|
||||
if (kb_state.len == 5) {
|
||||
kb_state.state = KEYBOARD;
|
||||
/* not yet used */
|
||||
/* wake up someone waiting for this */
|
||||
}
|
||||
break;
|
||||
|
||||
case RMOUSE:
|
||||
kb_state.buf[kb_state.len++] = scancode;
|
||||
if (kb_state.len == 3) {
|
||||
kb_state.state = KEYBOARD;
|
||||
if (atari_input_mouse_interrupt_hook)
|
||||
atari_input_mouse_interrupt_hook(kb_state.buf);
|
||||
}
|
||||
break;
|
||||
|
||||
case JOYSTICK:
|
||||
kb_state.buf[1] = scancode;
|
||||
kb_state.state = KEYBOARD;
|
||||
#ifdef FIXED_ATARI_JOYSTICK
|
||||
atari_joystick_interrupt(kb_state.buf);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case CLOCK:
|
||||
kb_state.buf[kb_state.len++] = scancode;
|
||||
if (kb_state.len == 6) {
|
||||
kb_state.state = KEYBOARD;
|
||||
/* wake up someone waiting for this.
|
||||
But will this ever be used, as Linux keeps its own time.
|
||||
Perhaps for synchronization purposes? */
|
||||
/* wake_up_interruptible(&clock_wait); */
|
||||
}
|
||||
break;
|
||||
|
||||
case RESYNC:
|
||||
if (kb_state.len <= 0 || IS_SYNC_CODE(scancode)) {
|
||||
kb_state.state = KEYBOARD;
|
||||
goto interpret_scancode;
|
||||
}
|
||||
kb_state.len--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (acia_stat & ACIA_CTS)
|
||||
/* cannot happen */;
|
||||
#endif
|
||||
|
||||
if (acia_stat & (ACIA_FE | ACIA_PE)) {
|
||||
printk("Error in keyboard communication\n");
|
||||
}
|
||||
|
||||
/* handle_scancode() can take a lot of time, so check again if
|
||||
* some character arrived
|
||||
*/
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
/*
|
||||
* I write to the keyboard without using interrupts, I poll instead.
|
||||
* This takes for the maximum length string allowed (7) at 7812.5 baud
|
||||
* 8 data 1 start 1 stop bit: 9.0 ms
|
||||
* If this takes too long for normal operation, interrupt driven writing
|
||||
* is the solution. (I made a feeble attempt in that direction but I
|
||||
* kept it simple for now.)
|
||||
*/
|
||||
void ikbd_write(const char *str, int len)
|
||||
{
|
||||
u_char acia_stat;
|
||||
|
||||
if ((len < 1) || (len > 7))
|
||||
panic("ikbd: maximum string length exceeded");
|
||||
while (len) {
|
||||
acia_stat = acia.key_ctrl;
|
||||
if (acia_stat & ACIA_TDRE) {
|
||||
acia.key_data = *str++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset (without touching the clock) */
|
||||
void ikbd_reset(void)
|
||||
{
|
||||
static const char cmd[2] = { 0x80, 0x01 };
|
||||
|
||||
ikbd_write(cmd, 2);
|
||||
|
||||
/*
|
||||
* if all's well code 0xF1 is returned, else the break codes of
|
||||
* all keys making contact
|
||||
*/
|
||||
}
|
||||
|
||||
/* Set mouse button action */
|
||||
void ikbd_mouse_button_action(int mode)
|
||||
{
|
||||
char cmd[2] = { 0x07, mode };
|
||||
|
||||
ikbd_write(cmd, 2);
|
||||
}
|
||||
|
||||
/* Set relative mouse position reporting */
|
||||
void ikbd_mouse_rel_pos(void)
|
||||
{
|
||||
static const char cmd[1] = { 0x08 };
|
||||
|
||||
ikbd_write(cmd, 1);
|
||||
}
|
||||
EXPORT_SYMBOL(ikbd_mouse_rel_pos);
|
||||
|
||||
/* Set absolute mouse position reporting */
|
||||
void ikbd_mouse_abs_pos(int xmax, int ymax)
|
||||
{
|
||||
char cmd[5] = { 0x09, xmax>>8, xmax&0xFF, ymax>>8, ymax&0xFF };
|
||||
|
||||
ikbd_write(cmd, 5);
|
||||
}
|
||||
|
||||
/* Set mouse keycode mode */
|
||||
void ikbd_mouse_kbd_mode(int dx, int dy)
|
||||
{
|
||||
char cmd[3] = { 0x0A, dx, dy };
|
||||
|
||||
ikbd_write(cmd, 3);
|
||||
}
|
||||
|
||||
/* Set mouse threshold */
|
||||
void ikbd_mouse_thresh(int x, int y)
|
||||
{
|
||||
char cmd[3] = { 0x0B, x, y };
|
||||
|
||||
ikbd_write(cmd, 3);
|
||||
}
|
||||
EXPORT_SYMBOL(ikbd_mouse_thresh);
|
||||
|
||||
/* Set mouse scale */
|
||||
void ikbd_mouse_scale(int x, int y)
|
||||
{
|
||||
char cmd[3] = { 0x0C, x, y };
|
||||
|
||||
ikbd_write(cmd, 3);
|
||||
}
|
||||
|
||||
/* Interrogate mouse position */
|
||||
void ikbd_mouse_pos_get(int *x, int *y)
|
||||
{
|
||||
static const char cmd[1] = { 0x0D };
|
||||
|
||||
ikbd_write(cmd, 1);
|
||||
|
||||
/* wait for returning bytes */
|
||||
}
|
||||
|
||||
/* Load mouse position */
|
||||
void ikbd_mouse_pos_set(int x, int y)
|
||||
{
|
||||
char cmd[6] = { 0x0E, 0x00, x>>8, x&0xFF, y>>8, y&0xFF };
|
||||
|
||||
ikbd_write(cmd, 6);
|
||||
}
|
||||
|
||||
/* Set Y=0 at bottom */
|
||||
void ikbd_mouse_y0_bot(void)
|
||||
{
|
||||
static const char cmd[1] = { 0x0F };
|
||||
|
||||
ikbd_write(cmd, 1);
|
||||
}
|
||||
|
||||
/* Set Y=0 at top */
|
||||
void ikbd_mouse_y0_top(void)
|
||||
{
|
||||
static const char cmd[1] = { 0x10 };
|
||||
|
||||
ikbd_write(cmd, 1);
|
||||
}
|
||||
EXPORT_SYMBOL(ikbd_mouse_y0_top);
|
||||
|
||||
/* Resume */
|
||||
void ikbd_resume(void)
|
||||
{
|
||||
static const char cmd[1] = { 0x11 };
|
||||
|
||||
ikbd_write(cmd, 1);
|
||||
}
|
||||
|
||||
/* Disable mouse */
|
||||
void ikbd_mouse_disable(void)
|
||||
{
|
||||
static const char cmd[1] = { 0x12 };
|
||||
|
||||
ikbd_write(cmd, 1);
|
||||
}
|
||||
EXPORT_SYMBOL(ikbd_mouse_disable);
|
||||
|
||||
/* Pause output */
|
||||
void ikbd_pause(void)
|
||||
{
|
||||
static const char cmd[1] = { 0x13 };
|
||||
|
||||
ikbd_write(cmd, 1);
|
||||
}
|
||||
|
||||
/* Set joystick event reporting */
|
||||
void ikbd_joystick_event_on(void)
|
||||
{
|
||||
static const char cmd[1] = { 0x14 };
|
||||
|
||||
ikbd_write(cmd, 1);
|
||||
}
|
||||
|
||||
/* Set joystick interrogation mode */
|
||||
void ikbd_joystick_event_off(void)
|
||||
{
|
||||
static const char cmd[1] = { 0x15 };
|
||||
|
||||
ikbd_write(cmd, 1);
|
||||
}
|
||||
|
||||
/* Joystick interrogation */
|
||||
void ikbd_joystick_get_state(void)
|
||||
{
|
||||
static const char cmd[1] = { 0x16 };
|
||||
|
||||
ikbd_write(cmd, 1);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* This disables all other ikbd activities !!!! */
|
||||
/* Set joystick monitoring */
|
||||
void ikbd_joystick_monitor(int rate)
|
||||
{
|
||||
static const char cmd[2] = { 0x17, rate };
|
||||
|
||||
ikbd_write(cmd, 2);
|
||||
|
||||
kb_state.state = JOYSTICK_MONITOR;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* some joystick routines not in yet (0x18-0x19) */
|
||||
|
||||
/* Disable joysticks */
|
||||
void ikbd_joystick_disable(void)
|
||||
{
|
||||
static const char cmd[1] = { 0x1A };
|
||||
|
||||
ikbd_write(cmd, 1);
|
||||
}
|
||||
|
||||
/* Time-of-day clock set */
|
||||
void ikbd_clock_set(int year, int month, int day, int hour, int minute, int second)
|
||||
{
|
||||
char cmd[7] = { 0x1B, year, month, day, hour, minute, second };
|
||||
|
||||
ikbd_write(cmd, 7);
|
||||
}
|
||||
|
||||
/* Interrogate time-of-day clock */
|
||||
void ikbd_clock_get(int *year, int *month, int *day, int *hour, int *minute, int second)
|
||||
{
|
||||
static const char cmd[1] = { 0x1C };
|
||||
|
||||
ikbd_write(cmd, 1);
|
||||
}
|
||||
|
||||
/* Memory load */
|
||||
void ikbd_mem_write(int address, int size, char *data)
|
||||
{
|
||||
panic("Attempt to write data into keyboard memory");
|
||||
}
|
||||
|
||||
/* Memory read */
|
||||
void ikbd_mem_read(int address, char data[6])
|
||||
{
|
||||
char cmd[3] = { 0x21, address>>8, address&0xFF };
|
||||
|
||||
ikbd_write(cmd, 3);
|
||||
|
||||
/* receive data and put it in data */
|
||||
}
|
||||
|
||||
/* Controller execute */
|
||||
void ikbd_exec(int address)
|
||||
{
|
||||
char cmd[3] = { 0x22, address>>8, address&0xFF };
|
||||
|
||||
ikbd_write(cmd, 3);
|
||||
}
|
||||
|
||||
/* Status inquiries (0x87-0x9A) not yet implemented */
|
||||
|
||||
/* Set the state of the caps lock led. */
|
||||
void atari_kbd_leds(unsigned int leds)
|
||||
{
|
||||
char cmd[6] = {32, 0, 4, 1, 254 + ((leds & 4) != 0), 0};
|
||||
|
||||
ikbd_write(cmd, 6);
|
||||
}
|
||||
|
||||
/*
|
||||
* The original code sometimes left the interrupt line of
|
||||
* the ACIAs low forever. I hope, it is fixed now.
|
||||
*
|
||||
* Martin Rogge, 20 Aug 1995
|
||||
*/
|
||||
|
||||
static int atari_keyb_done = 0;
|
||||
|
||||
int atari_keyb_init(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (atari_keyb_done)
|
||||
return 0;
|
||||
|
||||
kb_state.state = KEYBOARD;
|
||||
kb_state.len = 0;
|
||||
|
||||
error = request_irq(IRQ_MFP_ACIA, atari_keyboard_interrupt,
|
||||
IRQ_TYPE_SLOW, "keyboard,mouse,MIDI",
|
||||
atari_keyboard_interrupt);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
atari_turnoff_irq(IRQ_MFP_ACIA);
|
||||
do {
|
||||
/* reset IKBD ACIA */
|
||||
acia.key_ctrl = ACIA_RESET |
|
||||
((atari_switches & ATARI_SWITCH_IKBD) ?
|
||||
ACIA_RHTID : 0);
|
||||
(void)acia.key_ctrl;
|
||||
(void)acia.key_data;
|
||||
|
||||
/* reset MIDI ACIA */
|
||||
acia.mid_ctrl = ACIA_RESET |
|
||||
((atari_switches & ATARI_SWITCH_MIDI) ?
|
||||
ACIA_RHTID : 0);
|
||||
(void)acia.mid_ctrl;
|
||||
(void)acia.mid_data;
|
||||
|
||||
/* divide 500kHz by 64 gives 7812.5 baud */
|
||||
/* 8 data no parity 1 start 1 stop bit */
|
||||
/* receive interrupt enabled */
|
||||
/* RTS low (except if switch selected), transmit interrupt disabled */
|
||||
acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RIE) |
|
||||
((atari_switches & ATARI_SWITCH_IKBD) ?
|
||||
ACIA_RHTID : ACIA_RLTID);
|
||||
|
||||
acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S |
|
||||
((atari_switches & ATARI_SWITCH_MIDI) ?
|
||||
ACIA_RHTID : 0);
|
||||
|
||||
/* make sure the interrupt line is up */
|
||||
} while ((st_mfp.par_dt_reg & 0x10) == 0);
|
||||
|
||||
/* enable ACIA Interrupts */
|
||||
st_mfp.active_edge &= ~0x10;
|
||||
atari_turnon_irq(IRQ_MFP_ACIA);
|
||||
|
||||
ikbd_self_test = 1;
|
||||
ikbd_reset();
|
||||
/* wait for a period of inactivity (here: 0.25s), then assume the IKBD's
|
||||
* self-test is finished */
|
||||
self_test_last_rcv = jiffies;
|
||||
while (time_before(jiffies, self_test_last_rcv + HZ/4))
|
||||
barrier();
|
||||
/* if not incremented: no 0xf1 received */
|
||||
if (ikbd_self_test == 1)
|
||||
printk(KERN_ERR "WARNING: keyboard self test failed!\n");
|
||||
ikbd_self_test = 0;
|
||||
|
||||
ikbd_mouse_disable();
|
||||
ikbd_joystick_disable();
|
||||
|
||||
#ifdef FIXED_ATARI_JOYSTICK
|
||||
atari_joystick_init();
|
||||
#endif
|
||||
|
||||
// flag init done
|
||||
atari_keyb_done = 1;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(atari_keyb_init);
|
110
arch/m68k/atari/atasound.c
Normal file
110
arch/m68k/atari/atasound.c
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* linux/arch/m68k/atari/atasound.c
|
||||
*
|
||||
* ++Geert: Moved almost all stuff to linux/drivers/sound/
|
||||
*
|
||||
* The author of atari_nosound, atari_mksound and atari_microwire_cmd is
|
||||
* unknown. (++roman: That's me... :-)
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* 1998-05-31 ++andreas: atari_mksound rewritten to always use the envelope,
|
||||
* no timer, atari_nosound removed.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/atarihw.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/atariints.h>
|
||||
|
||||
|
||||
/*
|
||||
* stuff from the old atasound.c
|
||||
*/
|
||||
|
||||
void atari_microwire_cmd (int cmd)
|
||||
{
|
||||
tt_microwire.mask = 0x7ff;
|
||||
tt_microwire.data = MW_LM1992_ADDR | cmd;
|
||||
|
||||
/* Busy wait for data being completely sent :-( */
|
||||
while( tt_microwire.mask != 0x7ff)
|
||||
;
|
||||
}
|
||||
EXPORT_SYMBOL(atari_microwire_cmd);
|
||||
|
||||
|
||||
/* PSG base frequency */
|
||||
#define PSG_FREQ 125000
|
||||
/* PSG envelope base frequency times 10 */
|
||||
#define PSG_ENV_FREQ_10 78125
|
||||
|
||||
void atari_mksound (unsigned int hz, unsigned int ticks)
|
||||
{
|
||||
/* Generates sound of some frequency for some number of clock
|
||||
ticks. */
|
||||
unsigned long flags;
|
||||
unsigned char tmp;
|
||||
int period;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
|
||||
/* Disable generator A in mixer control. */
|
||||
sound_ym.rd_data_reg_sel = 7;
|
||||
tmp = sound_ym.rd_data_reg_sel;
|
||||
tmp |= 011;
|
||||
sound_ym.wd_data = tmp;
|
||||
|
||||
if (hz) {
|
||||
/* Convert from frequency value to PSG period value (base
|
||||
frequency 125 kHz). */
|
||||
|
||||
period = PSG_FREQ / hz;
|
||||
|
||||
if (period > 0xfff) period = 0xfff;
|
||||
|
||||
/* Set generator A frequency to hz. */
|
||||
sound_ym.rd_data_reg_sel = 0;
|
||||
sound_ym.wd_data = period & 0xff;
|
||||
sound_ym.rd_data_reg_sel = 1;
|
||||
sound_ym.wd_data = (period >> 8) & 0xf;
|
||||
if (ticks) {
|
||||
/* Set length of envelope (max 8 sec). */
|
||||
int length = (ticks * PSG_ENV_FREQ_10) / HZ / 10;
|
||||
|
||||
if (length > 0xffff) length = 0xffff;
|
||||
sound_ym.rd_data_reg_sel = 11;
|
||||
sound_ym.wd_data = length & 0xff;
|
||||
sound_ym.rd_data_reg_sel = 12;
|
||||
sound_ym.wd_data = length >> 8;
|
||||
/* Envelope form: max -> min single. */
|
||||
sound_ym.rd_data_reg_sel = 13;
|
||||
sound_ym.wd_data = 0;
|
||||
/* Use envelope for generator A. */
|
||||
sound_ym.rd_data_reg_sel = 8;
|
||||
sound_ym.wd_data = 0x10;
|
||||
} else {
|
||||
/* Set generator A level to maximum, no envelope. */
|
||||
sound_ym.rd_data_reg_sel = 8;
|
||||
sound_ym.wd_data = 15;
|
||||
}
|
||||
/* Turn on generator A in mixer control. */
|
||||
sound_ym.rd_data_reg_sel = 7;
|
||||
tmp &= ~1;
|
||||
sound_ym.wd_data = tmp;
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
}
|
898
arch/m68k/atari/config.c
Normal file
898
arch/m68k/atari/config.c
Normal file
|
@ -0,0 +1,898 @@
|
|||
/*
|
||||
* linux/arch/m68k/atari/config.c
|
||||
*
|
||||
* Copyright (C) 1994 Bjoern Brauel
|
||||
*
|
||||
* 5/2/94 Roman Hodek:
|
||||
* Added setting of time_adj to get a better clock.
|
||||
*
|
||||
* 5/14/94 Roman Hodek:
|
||||
* gettod() for TT
|
||||
*
|
||||
* 5/15/94 Roman Hodek:
|
||||
* hard_reset_now() for Atari (and others?)
|
||||
*
|
||||
* 94/12/30 Andreas Schwab:
|
||||
* atari_sched_init fixed to get precise clock.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Miscellaneous atari stuff
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/usb/isp116x.h>
|
||||
#include <linux/vt_kern.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/bootinfo-atari.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/atarihw.h>
|
||||
#include <asm/atariints.h>
|
||||
#include <asm/atari_stram.h>
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/hwtest.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
u_long atari_mch_cookie;
|
||||
EXPORT_SYMBOL(atari_mch_cookie);
|
||||
|
||||
u_long atari_mch_type;
|
||||
EXPORT_SYMBOL(atari_mch_type);
|
||||
|
||||
struct atari_hw_present atari_hw_present;
|
||||
EXPORT_SYMBOL(atari_hw_present);
|
||||
|
||||
u_long atari_switches;
|
||||
EXPORT_SYMBOL(atari_switches);
|
||||
|
||||
int atari_dont_touch_floppy_select;
|
||||
EXPORT_SYMBOL(atari_dont_touch_floppy_select);
|
||||
|
||||
int atari_rtc_year_offset;
|
||||
|
||||
/* local function prototypes */
|
||||
static void atari_reset(void);
|
||||
static void atari_get_model(char *model);
|
||||
static void atari_get_hardware_list(struct seq_file *m);
|
||||
|
||||
/* atari specific irq functions */
|
||||
extern void atari_init_IRQ (void);
|
||||
extern void atari_mksound(unsigned int count, unsigned int ticks);
|
||||
#ifdef CONFIG_HEARTBEAT
|
||||
static void atari_heartbeat(int on);
|
||||
#endif
|
||||
|
||||
/* atari specific timer functions (in time.c) */
|
||||
extern void atari_sched_init(irq_handler_t);
|
||||
extern u32 atari_gettimeoffset(void);
|
||||
extern int atari_mste_hwclk (int, struct rtc_time *);
|
||||
extern int atari_tt_hwclk (int, struct rtc_time *);
|
||||
extern int atari_mste_set_clock_mmss (unsigned long);
|
||||
extern int atari_tt_set_clock_mmss (unsigned long);
|
||||
|
||||
|
||||
/* ++roman: This is a more elaborate test for an SCC chip, since the plain
|
||||
* Medusa board generates DTACK at the SCC's standard addresses, but a SCC
|
||||
* board in the Medusa is possible. Also, the addresses where the ST_ESCC
|
||||
* resides generate DTACK without the chip, too.
|
||||
* The method is to write values into the interrupt vector register, that
|
||||
* should be readable without trouble (from channel A!).
|
||||
*/
|
||||
|
||||
static int __init scc_test(volatile char *ctla)
|
||||
{
|
||||
if (!hwreg_present(ctla))
|
||||
return 0;
|
||||
MFPDELAY();
|
||||
|
||||
*ctla = 2;
|
||||
MFPDELAY();
|
||||
*ctla = 0x40;
|
||||
MFPDELAY();
|
||||
|
||||
*ctla = 2;
|
||||
MFPDELAY();
|
||||
if (*ctla != 0x40)
|
||||
return 0;
|
||||
MFPDELAY();
|
||||
|
||||
*ctla = 2;
|
||||
MFPDELAY();
|
||||
*ctla = 0x60;
|
||||
MFPDELAY();
|
||||
|
||||
*ctla = 2;
|
||||
MFPDELAY();
|
||||
if (*ctla != 0x60)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parse an Atari-specific record in the bootinfo
|
||||
*/
|
||||
|
||||
int __init atari_parse_bootinfo(const struct bi_record *record)
|
||||
{
|
||||
int unknown = 0;
|
||||
const void *data = record->data;
|
||||
|
||||
switch (be16_to_cpu(record->tag)) {
|
||||
case BI_ATARI_MCH_COOKIE:
|
||||
atari_mch_cookie = be32_to_cpup(data);
|
||||
break;
|
||||
case BI_ATARI_MCH_TYPE:
|
||||
atari_mch_type = be32_to_cpup(data);
|
||||
break;
|
||||
default:
|
||||
unknown = 1;
|
||||
break;
|
||||
}
|
||||
return unknown;
|
||||
}
|
||||
|
||||
|
||||
/* Parse the Atari-specific switches= option. */
|
||||
static int __init atari_switches_setup(char *str)
|
||||
{
|
||||
char switches[strlen(str) + 1];
|
||||
char *p;
|
||||
int ovsc_shift;
|
||||
char *args = switches;
|
||||
|
||||
if (!MACH_IS_ATARI)
|
||||
return 0;
|
||||
|
||||
/* copy string to local array, strsep works destructively... */
|
||||
strcpy(switches, str);
|
||||
atari_switches = 0;
|
||||
|
||||
/* parse the options */
|
||||
while ((p = strsep(&args, ",")) != NULL) {
|
||||
if (!*p)
|
||||
continue;
|
||||
ovsc_shift = 0;
|
||||
if (strncmp(p, "ov_", 3) == 0) {
|
||||
p += 3;
|
||||
ovsc_shift = ATARI_SWITCH_OVSC_SHIFT;
|
||||
}
|
||||
|
||||
if (strcmp(p, "ikbd") == 0) {
|
||||
/* RTS line of IKBD ACIA */
|
||||
atari_switches |= ATARI_SWITCH_IKBD << ovsc_shift;
|
||||
} else if (strcmp(p, "midi") == 0) {
|
||||
/* RTS line of MIDI ACIA */
|
||||
atari_switches |= ATARI_SWITCH_MIDI << ovsc_shift;
|
||||
} else if (strcmp(p, "snd6") == 0) {
|
||||
atari_switches |= ATARI_SWITCH_SND6 << ovsc_shift;
|
||||
} else if (strcmp(p, "snd7") == 0) {
|
||||
atari_switches |= ATARI_SWITCH_SND7 << ovsc_shift;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
early_param("switches", atari_switches_setup);
|
||||
|
||||
|
||||
/*
|
||||
* Setup the Atari configuration info
|
||||
*/
|
||||
|
||||
void __init config_atari(void)
|
||||
{
|
||||
unsigned short tos_version;
|
||||
|
||||
memset(&atari_hw_present, 0, sizeof(atari_hw_present));
|
||||
|
||||
/* Change size of I/O space from 64KB to 4GB. */
|
||||
ioport_resource.end = 0xFFFFFFFF;
|
||||
|
||||
mach_sched_init = atari_sched_init;
|
||||
mach_init_IRQ = atari_init_IRQ;
|
||||
mach_get_model = atari_get_model;
|
||||
mach_get_hardware_list = atari_get_hardware_list;
|
||||
arch_gettimeoffset = atari_gettimeoffset;
|
||||
mach_reset = atari_reset;
|
||||
mach_max_dma_address = 0xffffff;
|
||||
#if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
|
||||
mach_beep = atari_mksound;
|
||||
#endif
|
||||
#ifdef CONFIG_HEARTBEAT
|
||||
mach_heartbeat = atari_heartbeat;
|
||||
#endif
|
||||
|
||||
/* Set switches as requested by the user */
|
||||
if (atari_switches & ATARI_SWITCH_IKBD)
|
||||
acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID;
|
||||
if (atari_switches & ATARI_SWITCH_MIDI)
|
||||
acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID;
|
||||
if (atari_switches & (ATARI_SWITCH_SND6|ATARI_SWITCH_SND7)) {
|
||||
sound_ym.rd_data_reg_sel = 14;
|
||||
sound_ym.wd_data = sound_ym.rd_data_reg_sel |
|
||||
((atari_switches&ATARI_SWITCH_SND6) ? 0x40 : 0) |
|
||||
((atari_switches&ATARI_SWITCH_SND7) ? 0x80 : 0);
|
||||
}
|
||||
|
||||
/* ++bjoern:
|
||||
* Determine hardware present
|
||||
*/
|
||||
|
||||
printk("Atari hardware found: ");
|
||||
if (MACH_IS_MEDUSA) {
|
||||
/* There's no Atari video hardware on the Medusa, but all the
|
||||
* addresses below generate a DTACK so no bus error occurs! */
|
||||
} else if (hwreg_present(f030_xreg)) {
|
||||
ATARIHW_SET(VIDEL_SHIFTER);
|
||||
printk("VIDEL ");
|
||||
/* This is a temporary hack: If there is Falcon video
|
||||
* hardware, we assume that the ST-DMA serves SCSI instead of
|
||||
* ACSI. In the future, there should be a better method for
|
||||
* this...
|
||||
*/
|
||||
ATARIHW_SET(ST_SCSI);
|
||||
printk("STDMA-SCSI ");
|
||||
} else if (hwreg_present(tt_palette)) {
|
||||
ATARIHW_SET(TT_SHIFTER);
|
||||
printk("TT_SHIFTER ");
|
||||
} else if (hwreg_present(&shifter.bas_hi)) {
|
||||
if (hwreg_present(&shifter.bas_lo) &&
|
||||
(shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) {
|
||||
ATARIHW_SET(EXTD_SHIFTER);
|
||||
printk("EXTD_SHIFTER ");
|
||||
} else {
|
||||
ATARIHW_SET(STND_SHIFTER);
|
||||
printk("STND_SHIFTER ");
|
||||
}
|
||||
}
|
||||
if (hwreg_present(&st_mfp.par_dt_reg)) {
|
||||
ATARIHW_SET(ST_MFP);
|
||||
printk("ST_MFP ");
|
||||
}
|
||||
if (hwreg_present(&tt_mfp.par_dt_reg)) {
|
||||
ATARIHW_SET(TT_MFP);
|
||||
printk("TT_MFP ");
|
||||
}
|
||||
if (hwreg_present(&tt_scsi_dma.dma_addr_hi)) {
|
||||
ATARIHW_SET(SCSI_DMA);
|
||||
printk("TT_SCSI_DMA ");
|
||||
}
|
||||
/*
|
||||
* The ST-DMA address registers aren't readable
|
||||
* on all Medusas, so the test below may fail
|
||||
*/
|
||||
if (MACH_IS_MEDUSA ||
|
||||
(hwreg_present(&st_dma.dma_vhi) &&
|
||||
(st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) &&
|
||||
st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa &&
|
||||
(st_dma.dma_vhi = 0xaa) && (st_dma.dma_hi = 0x55) &&
|
||||
st_dma.dma_vhi == 0xaa && st_dma.dma_hi == 0x55)) {
|
||||
ATARIHW_SET(EXTD_DMA);
|
||||
printk("EXTD_DMA ");
|
||||
}
|
||||
if (hwreg_present(&tt_scsi.scsi_data)) {
|
||||
ATARIHW_SET(TT_SCSI);
|
||||
printk("TT_SCSI ");
|
||||
}
|
||||
if (hwreg_present(&sound_ym.rd_data_reg_sel)) {
|
||||
ATARIHW_SET(YM_2149);
|
||||
printk("YM2149 ");
|
||||
}
|
||||
if (!MACH_IS_MEDUSA && hwreg_present(&tt_dmasnd.ctrl)) {
|
||||
ATARIHW_SET(PCM_8BIT);
|
||||
printk("PCM ");
|
||||
}
|
||||
if (hwreg_present(&falcon_codec.unused5)) {
|
||||
ATARIHW_SET(CODEC);
|
||||
printk("CODEC ");
|
||||
}
|
||||
if (hwreg_present(&dsp56k_host_interface.icr)) {
|
||||
ATARIHW_SET(DSP56K);
|
||||
printk("DSP56K ");
|
||||
}
|
||||
if (hwreg_present(&tt_scc_dma.dma_ctrl) &&
|
||||
#if 0
|
||||
/* This test sucks! Who knows some better? */
|
||||
(tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) &&
|
||||
(tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0)
|
||||
#else
|
||||
!MACH_IS_MEDUSA
|
||||
#endif
|
||||
) {
|
||||
ATARIHW_SET(SCC_DMA);
|
||||
printk("SCC_DMA ");
|
||||
}
|
||||
if (scc_test(&atari_scc.cha_a_ctrl)) {
|
||||
ATARIHW_SET(SCC);
|
||||
printk("SCC ");
|
||||
}
|
||||
if (scc_test(&st_escc.cha_b_ctrl)) {
|
||||
ATARIHW_SET(ST_ESCC);
|
||||
printk("ST_ESCC ");
|
||||
}
|
||||
if (hwreg_present(&tt_scu.sys_mask)) {
|
||||
ATARIHW_SET(SCU);
|
||||
/* Assume a VME bus if there's a SCU */
|
||||
ATARIHW_SET(VME);
|
||||
printk("VME SCU ");
|
||||
}
|
||||
if (hwreg_present((void *)(0xffff9210))) {
|
||||
ATARIHW_SET(ANALOG_JOY);
|
||||
printk("ANALOG_JOY ");
|
||||
}
|
||||
if (hwreg_present(blitter.halftone)) {
|
||||
ATARIHW_SET(BLITTER);
|
||||
printk("BLITTER ");
|
||||
}
|
||||
if (hwreg_present((void *)0xfff00039)) {
|
||||
ATARIHW_SET(IDE);
|
||||
printk("IDE ");
|
||||
}
|
||||
#if 1 /* This maybe wrong */
|
||||
if (!MACH_IS_MEDUSA && hwreg_present(&tt_microwire.data) &&
|
||||
hwreg_present(&tt_microwire.mask) &&
|
||||
(tt_microwire.mask = 0x7ff,
|
||||
udelay(1),
|
||||
tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR,
|
||||
udelay(1),
|
||||
tt_microwire.data != 0)) {
|
||||
ATARIHW_SET(MICROWIRE);
|
||||
while (tt_microwire.mask != 0x7ff)
|
||||
;
|
||||
printk("MICROWIRE ");
|
||||
}
|
||||
#endif
|
||||
if (hwreg_present(&tt_rtc.regsel)) {
|
||||
ATARIHW_SET(TT_CLK);
|
||||
printk("TT_CLK ");
|
||||
mach_hwclk = atari_tt_hwclk;
|
||||
mach_set_clock_mmss = atari_tt_set_clock_mmss;
|
||||
}
|
||||
if (hwreg_present(&mste_rtc.sec_ones)) {
|
||||
ATARIHW_SET(MSTE_CLK);
|
||||
printk("MSTE_CLK ");
|
||||
mach_hwclk = atari_mste_hwclk;
|
||||
mach_set_clock_mmss = atari_mste_set_clock_mmss;
|
||||
}
|
||||
if (!MACH_IS_MEDUSA && hwreg_present(&dma_wd.fdc_speed) &&
|
||||
hwreg_write(&dma_wd.fdc_speed, 0)) {
|
||||
ATARIHW_SET(FDCSPEED);
|
||||
printk("FDC_SPEED ");
|
||||
}
|
||||
if (!ATARIHW_PRESENT(ST_SCSI)) {
|
||||
ATARIHW_SET(ACSI);
|
||||
printk("ACSI ");
|
||||
}
|
||||
printk("\n");
|
||||
|
||||
if (CPU_IS_040_OR_060)
|
||||
/* Now it seems to be safe to turn of the tt0 transparent
|
||||
* translation (the one that must not be turned off in
|
||||
* head.S...)
|
||||
*/
|
||||
asm volatile ("\n"
|
||||
" moveq #0,%%d0\n"
|
||||
" .chip 68040\n"
|
||||
" movec %%d0,%%itt0\n"
|
||||
" movec %%d0,%%dtt0\n"
|
||||
" .chip 68k"
|
||||
: /* no outputs */
|
||||
: /* no inputs */
|
||||
: "d0");
|
||||
|
||||
/* allocator for memory that must reside in st-ram */
|
||||
atari_stram_init();
|
||||
|
||||
/* Set up a mapping for the VMEbus address region:
|
||||
*
|
||||
* VME is either at phys. 0xfexxxxxx (TT) or 0xa00000..0xdfffff
|
||||
* (MegaSTE) In both cases, the whole 16 MB chunk is mapped at
|
||||
* 0xfe000000 virt., because this can be done with a single
|
||||
* transparent translation. On the 68040, lots of often unused
|
||||
* page tables would be needed otherwise. On a MegaSTE or similar,
|
||||
* the highest byte is stripped off by hardware due to the 24 bit
|
||||
* design of the bus.
|
||||
*/
|
||||
|
||||
if (CPU_IS_020_OR_030) {
|
||||
unsigned long tt1_val;
|
||||
tt1_val = 0xfe008543; /* Translate 0xfexxxxxx, enable, cache
|
||||
* inhibit, read and write, FDC mask = 3,
|
||||
* FDC val = 4 -> Supervisor only */
|
||||
asm volatile ("\n"
|
||||
" .chip 68030\n"
|
||||
" pmove %0,%/tt1\n"
|
||||
" .chip 68k"
|
||||
: : "m" (tt1_val));
|
||||
} else {
|
||||
asm volatile ("\n"
|
||||
" .chip 68040\n"
|
||||
" movec %0,%%itt1\n"
|
||||
" movec %0,%%dtt1\n"
|
||||
" .chip 68k"
|
||||
:
|
||||
: "d" (0xfe00a040)); /* Translate 0xfexxxxxx, enable,
|
||||
* supervisor only, non-cacheable/
|
||||
* serialized, writable */
|
||||
|
||||
}
|
||||
|
||||
/* Fetch tos version at Physical 2 */
|
||||
/*
|
||||
* We my not be able to access this address if the kernel is
|
||||
* loaded to st ram, since the first page is unmapped. On the
|
||||
* Medusa this is always the case and there is nothing we can do
|
||||
* about this, so we just assume the smaller offset. For the TT
|
||||
* we use the fact that in head.S we have set up a mapping
|
||||
* 0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible
|
||||
* in the last 16MB of the address space.
|
||||
*/
|
||||
tos_version = (MACH_IS_MEDUSA) ?
|
||||
0xfff : *(unsigned short *)0xff000002;
|
||||
atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HEARTBEAT
|
||||
static void atari_heartbeat(int on)
|
||||
{
|
||||
unsigned char tmp;
|
||||
unsigned long flags;
|
||||
|
||||
if (atari_dont_touch_floppy_select)
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */
|
||||
tmp = sound_ym.rd_data_reg_sel;
|
||||
sound_ym.wd_data = on ? (tmp & ~0x02) : (tmp | 0x02);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ++roman:
|
||||
*
|
||||
* This function does a reset on machines that lack the ability to
|
||||
* assert the processor's _RESET signal somehow via hardware. It is
|
||||
* based on the fact that you can find the initial SP and PC values
|
||||
* after a reset at physical addresses 0 and 4. This works pretty well
|
||||
* for Atari machines, since the lowest 8 bytes of physical memory are
|
||||
* really ROM (mapped by hardware). For other 680x0 machines: don't
|
||||
* know if it works...
|
||||
*
|
||||
* To get the values at addresses 0 and 4, the MMU better is turned
|
||||
* off first. After that, we have to jump into physical address space
|
||||
* (the PC before the pmove statement points to the virtual address of
|
||||
* the code). Getting that physical address is not hard, but the code
|
||||
* becomes a bit complex since I've tried to ensure that the jump
|
||||
* statement after the pmove is in the cache already (otherwise the
|
||||
* processor can't fetch it!). For that, the code first jumps to the
|
||||
* jump statement with the (virtual) address of the pmove section in
|
||||
* an address register . The jump statement is surely in the cache
|
||||
* now. After that, that physical address of the reset code is loaded
|
||||
* into the same address register, pmove is done and the same jump
|
||||
* statements goes to the reset code. Since there are not many
|
||||
* statements between the two jumps, I hope it stays in the cache.
|
||||
*
|
||||
* The C code makes heavy use of the GCC features that you can get the
|
||||
* address of a C label. No hope to compile this with another compiler
|
||||
* than GCC!
|
||||
*/
|
||||
|
||||
/* ++andreas: no need for complicated code, just depend on prefetch */
|
||||
|
||||
static void atari_reset(void)
|
||||
{
|
||||
long tc_val = 0;
|
||||
long reset_addr;
|
||||
|
||||
/*
|
||||
* On the Medusa, phys. 0x4 may contain garbage because it's no
|
||||
* ROM. See above for explanation why we cannot use PTOV(4).
|
||||
*/
|
||||
reset_addr = MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 :
|
||||
*(unsigned long *) 0xff000004;
|
||||
|
||||
/* reset ACIA for switch off OverScan, if it's active */
|
||||
if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
|
||||
acia.key_ctrl = ACIA_RESET;
|
||||
if (atari_switches & ATARI_SWITCH_OVSC_MIDI)
|
||||
acia.mid_ctrl = ACIA_RESET;
|
||||
|
||||
/* processor independent: turn off interrupts and reset the VBR;
|
||||
* the caches must be left enabled, else prefetching the final jump
|
||||
* instruction doesn't work.
|
||||
*/
|
||||
local_irq_disable();
|
||||
asm volatile ("movec %0,%%vbr"
|
||||
: : "d" (0));
|
||||
|
||||
if (CPU_IS_040_OR_060) {
|
||||
unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040);
|
||||
if (CPU_IS_060) {
|
||||
/* 68060: clear PCR to turn off superscalar operation */
|
||||
asm volatile ("\n"
|
||||
" .chip 68060\n"
|
||||
" movec %0,%%pcr\n"
|
||||
" .chip 68k"
|
||||
: : "d" (0));
|
||||
}
|
||||
|
||||
asm volatile ("\n"
|
||||
" move.l %0,%%d0\n"
|
||||
" and.l #0xff000000,%%d0\n"
|
||||
" or.w #0xe020,%%d0\n" /* map 16 MB, enable, cacheable */
|
||||
" .chip 68040\n"
|
||||
" movec %%d0,%%itt0\n"
|
||||
" movec %%d0,%%dtt0\n"
|
||||
" .chip 68k\n"
|
||||
" jmp %0@"
|
||||
: : "a" (jmp_addr040)
|
||||
: "d0");
|
||||
jmp_addr_label040:
|
||||
asm volatile ("\n"
|
||||
" moveq #0,%%d0\n"
|
||||
" nop\n"
|
||||
" .chip 68040\n"
|
||||
" cinva %%bc\n"
|
||||
" nop\n"
|
||||
" pflusha\n"
|
||||
" nop\n"
|
||||
" movec %%d0,%%tc\n"
|
||||
" nop\n"
|
||||
/* the following setup of transparent translations is needed on the
|
||||
* Afterburner040 to successfully reboot. Other machines shouldn't
|
||||
* care about a different tt regs setup, they also didn't care in
|
||||
* the past that the regs weren't turned off. */
|
||||
" move.l #0xffc000,%%d0\n" /* whole insn space cacheable */
|
||||
" movec %%d0,%%itt0\n"
|
||||
" movec %%d0,%%itt1\n"
|
||||
" or.w #0x40,%/d0\n" /* whole data space non-cacheable/ser. */
|
||||
" movec %%d0,%%dtt0\n"
|
||||
" movec %%d0,%%dtt1\n"
|
||||
" .chip 68k\n"
|
||||
" jmp %0@"
|
||||
: /* no outputs */
|
||||
: "a" (reset_addr)
|
||||
: "d0");
|
||||
} else
|
||||
asm volatile ("\n"
|
||||
" pmove %0,%%tc\n"
|
||||
" jmp %1@"
|
||||
: /* no outputs */
|
||||
: "m" (tc_val), "a" (reset_addr));
|
||||
}
|
||||
|
||||
|
||||
static void atari_get_model(char *model)
|
||||
{
|
||||
strcpy(model, "Atari ");
|
||||
switch (atari_mch_cookie >> 16) {
|
||||
case ATARI_MCH_ST:
|
||||
if (ATARIHW_PRESENT(MSTE_CLK))
|
||||
strcat(model, "Mega ST");
|
||||
else
|
||||
strcat(model, "ST");
|
||||
break;
|
||||
case ATARI_MCH_STE:
|
||||
if (MACH_IS_MSTE)
|
||||
strcat(model, "Mega STE");
|
||||
else
|
||||
strcat(model, "STE");
|
||||
break;
|
||||
case ATARI_MCH_TT:
|
||||
if (MACH_IS_MEDUSA)
|
||||
/* Medusa has TT _MCH cookie */
|
||||
strcat(model, "Medusa");
|
||||
else
|
||||
strcat(model, "TT");
|
||||
break;
|
||||
case ATARI_MCH_FALCON:
|
||||
strcat(model, "Falcon");
|
||||
if (MACH_IS_AB40)
|
||||
strcat(model, " (with Afterburner040)");
|
||||
break;
|
||||
default:
|
||||
sprintf(model + strlen(model), "(unknown mach cookie 0x%lx)",
|
||||
atari_mch_cookie);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void atari_get_hardware_list(struct seq_file *m)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < m68k_num_memory; i++)
|
||||
seq_printf(m, "\t%3ld MB at 0x%08lx (%s)\n",
|
||||
m68k_memory[i].size >> 20, m68k_memory[i].addr,
|
||||
(m68k_memory[i].addr & 0xff000000 ?
|
||||
"alternate RAM" : "ST-RAM"));
|
||||
|
||||
#define ATARIHW_ANNOUNCE(name, str) \
|
||||
if (ATARIHW_PRESENT(name)) \
|
||||
seq_printf(m, "\t%s\n", str)
|
||||
|
||||
seq_printf(m, "Detected hardware:\n");
|
||||
ATARIHW_ANNOUNCE(STND_SHIFTER, "ST Shifter");
|
||||
ATARIHW_ANNOUNCE(EXTD_SHIFTER, "STe Shifter");
|
||||
ATARIHW_ANNOUNCE(TT_SHIFTER, "TT Shifter");
|
||||
ATARIHW_ANNOUNCE(VIDEL_SHIFTER, "Falcon Shifter");
|
||||
ATARIHW_ANNOUNCE(YM_2149, "Programmable Sound Generator");
|
||||
ATARIHW_ANNOUNCE(PCM_8BIT, "PCM 8 Bit Sound");
|
||||
ATARIHW_ANNOUNCE(CODEC, "CODEC Sound");
|
||||
ATARIHW_ANNOUNCE(TT_SCSI, "SCSI Controller NCR5380 (TT style)");
|
||||
ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon style)");
|
||||
ATARIHW_ANNOUNCE(ACSI, "ACSI Interface");
|
||||
ATARIHW_ANNOUNCE(IDE, "IDE Interface");
|
||||
ATARIHW_ANNOUNCE(FDCSPEED, "8/16 Mhz Switch for FDC");
|
||||
ATARIHW_ANNOUNCE(ST_MFP, "Multi Function Peripheral MFP 68901");
|
||||
ATARIHW_ANNOUNCE(TT_MFP, "Second Multi Function Peripheral MFP 68901");
|
||||
ATARIHW_ANNOUNCE(SCC, "Serial Communications Controller SCC 8530");
|
||||
ATARIHW_ANNOUNCE(ST_ESCC, "Extended Serial Communications Controller SCC 85230");
|
||||
ATARIHW_ANNOUNCE(ANALOG_JOY, "Paddle Interface");
|
||||
ATARIHW_ANNOUNCE(MICROWIRE, "MICROWIRE(tm) Interface");
|
||||
ATARIHW_ANNOUNCE(STND_DMA, "DMA Controller (24 bit)");
|
||||
ATARIHW_ANNOUNCE(EXTD_DMA, "DMA Controller (32 bit)");
|
||||
ATARIHW_ANNOUNCE(SCSI_DMA, "DMA Controller for NCR5380");
|
||||
ATARIHW_ANNOUNCE(SCC_DMA, "DMA Controller for SCC");
|
||||
ATARIHW_ANNOUNCE(TT_CLK, "Clock Chip MC146818A");
|
||||
ATARIHW_ANNOUNCE(MSTE_CLK, "Clock Chip RP5C15");
|
||||
ATARIHW_ANNOUNCE(SCU, "System Control Unit");
|
||||
ATARIHW_ANNOUNCE(BLITTER, "Blitter");
|
||||
ATARIHW_ANNOUNCE(VME, "VME Bus");
|
||||
ATARIHW_ANNOUNCE(DSP56K, "DSP56001 processor");
|
||||
}
|
||||
|
||||
/*
|
||||
* MSch: initial platform device support for Atari,
|
||||
* required for EtherNAT/EtherNEC/NetUSBee drivers
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_ATARI_ETHERNAT) || defined(CONFIG_ATARI_ETHERNEC)
|
||||
static void isp1160_delay(struct device *dev, int delay)
|
||||
{
|
||||
ndelay(delay);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ATARI_ETHERNAT
|
||||
/*
|
||||
* EtherNAT: SMC91C111 Ethernet chipset, handled by smc91x driver
|
||||
*/
|
||||
|
||||
#define ATARI_ETHERNAT_IRQ 140
|
||||
|
||||
static struct resource smc91x_resources[] = {
|
||||
[0] = {
|
||||
.name = "smc91x-regs",
|
||||
.start = ATARI_ETHERNAT_PHYS_ADDR,
|
||||
.end = ATARI_ETHERNAT_PHYS_ADDR + 0xfffff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.name = "smc91x-irq",
|
||||
.start = ATARI_ETHERNAT_IRQ,
|
||||
.end = ATARI_ETHERNAT_IRQ,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device smc91x_device = {
|
||||
.name = "smc91x",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(smc91x_resources),
|
||||
.resource = smc91x_resources,
|
||||
};
|
||||
|
||||
/*
|
||||
* ISP 1160 - using the isp116x-hcd module
|
||||
*/
|
||||
|
||||
#define ATARI_USB_PHYS_ADDR 0x80000012
|
||||
#define ATARI_USB_IRQ 139
|
||||
|
||||
static struct resource isp1160_resources[] = {
|
||||
[0] = {
|
||||
.name = "isp1160-data",
|
||||
.start = ATARI_USB_PHYS_ADDR,
|
||||
.end = ATARI_USB_PHYS_ADDR + 0x1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.name = "isp1160-regs",
|
||||
.start = ATARI_USB_PHYS_ADDR + 0x4,
|
||||
.end = ATARI_USB_PHYS_ADDR + 0x5,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[2] = {
|
||||
.name = "isp1160-irq",
|
||||
.start = ATARI_USB_IRQ,
|
||||
.end = ATARI_USB_IRQ,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
/* (DataBusWidth16|AnalogOCEnable|DREQOutputPolarity|DownstreamPort15KRSel ) */
|
||||
static struct isp116x_platform_data isp1160_platform_data = {
|
||||
/* Enable internal resistors on downstream ports */
|
||||
.sel15Kres = 1,
|
||||
/* On-chip overcurrent protection */
|
||||
.oc_enable = 1,
|
||||
/* INT output polarity */
|
||||
.int_act_high = 1,
|
||||
/* INT edge or level triggered */
|
||||
.int_edge_triggered = 0,
|
||||
|
||||
/* WAKEUP pin connected - NOT SUPPORTED */
|
||||
/* .remote_wakeup_connected = 0, */
|
||||
/* Wakeup by devices on usb bus enabled */
|
||||
.remote_wakeup_enable = 0,
|
||||
.delay = isp1160_delay,
|
||||
};
|
||||
|
||||
static struct platform_device isp1160_device = {
|
||||
.name = "isp116x-hcd",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(isp1160_resources),
|
||||
.resource = isp1160_resources,
|
||||
.dev = {
|
||||
.platform_data = &isp1160_platform_data,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device *atari_ethernat_devices[] __initdata = {
|
||||
&smc91x_device,
|
||||
&isp1160_device
|
||||
};
|
||||
#endif /* CONFIG_ATARI_ETHERNAT */
|
||||
|
||||
#ifdef CONFIG_ATARI_ETHERNEC
|
||||
/*
|
||||
* EtherNEC: RTL8019 (NE2000 compatible) Ethernet chipset,
|
||||
* handled by ne.c driver
|
||||
*/
|
||||
|
||||
#define ATARI_ETHERNEC_PHYS_ADDR 0xfffa0000
|
||||
#define ATARI_ETHERNEC_BASE 0x300
|
||||
#define ATARI_ETHERNEC_IRQ IRQ_MFP_TIMER1
|
||||
|
||||
static struct resource rtl8019_resources[] = {
|
||||
[0] = {
|
||||
.name = "rtl8019-regs",
|
||||
.start = ATARI_ETHERNEC_BASE,
|
||||
.end = ATARI_ETHERNEC_BASE + 0x20 - 1,
|
||||
.flags = IORESOURCE_IO,
|
||||
},
|
||||
[1] = {
|
||||
.name = "rtl8019-irq",
|
||||
.start = ATARI_ETHERNEC_IRQ,
|
||||
.end = ATARI_ETHERNEC_IRQ,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device rtl8019_device = {
|
||||
.name = "ne",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(rtl8019_resources),
|
||||
.resource = rtl8019_resources,
|
||||
};
|
||||
|
||||
/*
|
||||
* NetUSBee: ISP1160 USB host adapter via ROM-port adapter
|
||||
*/
|
||||
|
||||
#define ATARI_NETUSBEE_PHYS_ADDR 0xfffa8000
|
||||
#define ATARI_NETUSBEE_BASE 0x340
|
||||
#define ATARI_NETUSBEE_IRQ IRQ_MFP_TIMER2
|
||||
|
||||
static struct resource netusbee_resources[] = {
|
||||
[0] = {
|
||||
.name = "isp1160-data",
|
||||
.start = ATARI_NETUSBEE_BASE,
|
||||
.end = ATARI_NETUSBEE_BASE + 0x1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.name = "isp1160-regs",
|
||||
.start = ATARI_NETUSBEE_BASE + 0x20,
|
||||
.end = ATARI_NETUSBEE_BASE + 0x21,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[2] = {
|
||||
.name = "isp1160-irq",
|
||||
.start = ATARI_NETUSBEE_IRQ,
|
||||
.end = ATARI_NETUSBEE_IRQ,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
/* (DataBusWidth16|AnalogOCEnable|DREQOutputPolarity|DownstreamPort15KRSel ) */
|
||||
static struct isp116x_platform_data netusbee_platform_data = {
|
||||
/* Enable internal resistors on downstream ports */
|
||||
.sel15Kres = 1,
|
||||
/* On-chip overcurrent protection */
|
||||
.oc_enable = 1,
|
||||
/* INT output polarity */
|
||||
.int_act_high = 1,
|
||||
/* INT edge or level triggered */
|
||||
.int_edge_triggered = 0,
|
||||
|
||||
/* WAKEUP pin connected - NOT SUPPORTED */
|
||||
/* .remote_wakeup_connected = 0, */
|
||||
/* Wakeup by devices on usb bus enabled */
|
||||
.remote_wakeup_enable = 0,
|
||||
.delay = isp1160_delay,
|
||||
};
|
||||
|
||||
static struct platform_device netusbee_device = {
|
||||
.name = "isp116x-hcd",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(netusbee_resources),
|
||||
.resource = netusbee_resources,
|
||||
.dev = {
|
||||
.platform_data = &netusbee_platform_data,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device *atari_netusbee_devices[] __initdata = {
|
||||
&rtl8019_device,
|
||||
&netusbee_device
|
||||
};
|
||||
#endif /* CONFIG_ATARI_ETHERNEC */
|
||||
|
||||
int __init atari_platform_init(void)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
if (!MACH_IS_ATARI)
|
||||
return -ENODEV;
|
||||
|
||||
#ifdef CONFIG_ATARI_ETHERNAT
|
||||
{
|
||||
unsigned char *enatc_virt;
|
||||
enatc_virt = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0xf);
|
||||
if (hwreg_present(enatc_virt)) {
|
||||
rv = platform_add_devices(atari_ethernat_devices,
|
||||
ARRAY_SIZE(atari_ethernat_devices));
|
||||
}
|
||||
iounmap(enatc_virt);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ATARI_ETHERNEC
|
||||
{
|
||||
int error;
|
||||
unsigned char *enec_virt;
|
||||
enec_virt = (unsigned char *)ioremap((ATARI_ETHERNEC_PHYS_ADDR), 0xf);
|
||||
if (hwreg_present(enec_virt)) {
|
||||
error = platform_add_devices(atari_netusbee_devices,
|
||||
ARRAY_SIZE(atari_netusbee_devices));
|
||||
if (error && !rv)
|
||||
rv = error;
|
||||
}
|
||||
iounmap(enec_virt);
|
||||
}
|
||||
#endif
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
arch_initcall(atari_platform_init);
|
329
arch/m68k/atari/debug.c
Normal file
329
arch/m68k/atari/debug.c
Normal file
|
@ -0,0 +1,329 @@
|
|||
/*
|
||||
* linux/arch/m68k/atari/debug.c
|
||||
*
|
||||
* Atari debugging and serial console stuff
|
||||
*
|
||||
* Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/atarihw.h>
|
||||
#include <asm/atariints.h>
|
||||
|
||||
/* Can be set somewhere, if a SCC master reset has already be done and should
|
||||
* not be repeated; used by kgdb */
|
||||
int atari_SCC_reset_done;
|
||||
EXPORT_SYMBOL(atari_SCC_reset_done);
|
||||
|
||||
static struct console atari_console_driver = {
|
||||
.name = "debug",
|
||||
.flags = CON_PRINTBUFFER,
|
||||
.index = -1,
|
||||
};
|
||||
|
||||
|
||||
static inline void ata_mfp_out(char c)
|
||||
{
|
||||
while (!(st_mfp.trn_stat & 0x80)) /* wait for tx buf empty */
|
||||
barrier();
|
||||
st_mfp.usart_dta = c;
|
||||
}
|
||||
|
||||
static void atari_mfp_console_write(struct console *co, const char *str,
|
||||
unsigned int count)
|
||||
{
|
||||
while (count--) {
|
||||
if (*str == '\n')
|
||||
ata_mfp_out('\r');
|
||||
ata_mfp_out(*str++);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ata_scc_out(char c)
|
||||
{
|
||||
do {
|
||||
MFPDELAY();
|
||||
} while (!(atari_scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
|
||||
MFPDELAY();
|
||||
atari_scc.cha_b_data = c;
|
||||
}
|
||||
|
||||
static void atari_scc_console_write(struct console *co, const char *str,
|
||||
unsigned int count)
|
||||
{
|
||||
while (count--) {
|
||||
if (*str == '\n')
|
||||
ata_scc_out('\r');
|
||||
ata_scc_out(*str++);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ata_midi_out(char c)
|
||||
{
|
||||
while (!(acia.mid_ctrl & ACIA_TDRE)) /* wait for tx buf empty */
|
||||
barrier();
|
||||
acia.mid_data = c;
|
||||
}
|
||||
|
||||
static void atari_midi_console_write(struct console *co, const char *str,
|
||||
unsigned int count)
|
||||
{
|
||||
while (count--) {
|
||||
if (*str == '\n')
|
||||
ata_midi_out('\r');
|
||||
ata_midi_out(*str++);
|
||||
}
|
||||
}
|
||||
|
||||
static int ata_par_out(char c)
|
||||
{
|
||||
unsigned char tmp;
|
||||
/* This a some-seconds timeout in case no printer is connected */
|
||||
unsigned long i = loops_per_jiffy > 1 ? loops_per_jiffy : 10000000/HZ;
|
||||
|
||||
while ((st_mfp.par_dt_reg & 1) && --i) /* wait for BUSY == L */
|
||||
;
|
||||
if (!i)
|
||||
return 0;
|
||||
|
||||
sound_ym.rd_data_reg_sel = 15; /* select port B */
|
||||
sound_ym.wd_data = c; /* put char onto port */
|
||||
sound_ym.rd_data_reg_sel = 14; /* select port A */
|
||||
tmp = sound_ym.rd_data_reg_sel;
|
||||
sound_ym.wd_data = tmp & ~0x20; /* set strobe L */
|
||||
MFPDELAY(); /* wait a bit */
|
||||
sound_ym.wd_data = tmp | 0x20; /* set strobe H */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void atari_par_console_write(struct console *co, const char *str,
|
||||
unsigned int count)
|
||||
{
|
||||
static int printer_present = 1;
|
||||
|
||||
if (!printer_present)
|
||||
return;
|
||||
|
||||
while (count--) {
|
||||
if (*str == '\n') {
|
||||
if (!ata_par_out('\r')) {
|
||||
printer_present = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!ata_par_out(*str++)) {
|
||||
printer_present = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
int atari_mfp_console_wait_key(struct console *co)
|
||||
{
|
||||
while (!(st_mfp.rcv_stat & 0x80)) /* wait for rx buf filled */
|
||||
barrier();
|
||||
return st_mfp.usart_dta;
|
||||
}
|
||||
|
||||
int atari_scc_console_wait_key(struct console *co)
|
||||
{
|
||||
do {
|
||||
MFPDELAY();
|
||||
} while (!(atari_scc.cha_b_ctrl & 0x01)); /* wait for rx buf filled */
|
||||
MFPDELAY();
|
||||
return atari_scc.cha_b_data;
|
||||
}
|
||||
|
||||
int atari_midi_console_wait_key(struct console *co)
|
||||
{
|
||||
while (!(acia.mid_ctrl & ACIA_RDRF)) /* wait for rx buf filled */
|
||||
barrier();
|
||||
return acia.mid_data;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The following two functions do a quick'n'dirty initialization of the MFP or
|
||||
* SCC serial ports. They're used by the debugging interface, kgdb, and the
|
||||
* serial console code.
|
||||
*/
|
||||
static void __init atari_init_mfp_port(int cflag)
|
||||
{
|
||||
/*
|
||||
* timer values for 1200...115200 bps; > 38400 select 110, 134, or 150
|
||||
* bps, resp., and work only correct if there's a RSVE or RSSPEED
|
||||
*/
|
||||
static int baud_table[9] = { 16, 11, 8, 4, 2, 1, 175, 143, 128 };
|
||||
int baud = cflag & CBAUD;
|
||||
int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x04 : 0x06) : 0;
|
||||
int csize = ((cflag & CSIZE) == CS7) ? 0x20 : 0x00;
|
||||
|
||||
if (cflag & CBAUDEX)
|
||||
baud += B38400;
|
||||
if (baud < B1200 || baud > B38400+2)
|
||||
baud = B9600; /* use default 9600bps for non-implemented rates */
|
||||
baud -= B1200; /* baud_table[] starts at 1200bps */
|
||||
|
||||
st_mfp.trn_stat &= ~0x01; /* disable TX */
|
||||
st_mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */
|
||||
st_mfp.tim_ct_cd &= 0x70; /* stop timer D */
|
||||
st_mfp.tim_dt_d = baud_table[baud];
|
||||
st_mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */
|
||||
st_mfp.trn_stat |= 0x01; /* enable TX */
|
||||
}
|
||||
|
||||
#define SCC_WRITE(reg, val) \
|
||||
do { \
|
||||
atari_scc.cha_b_ctrl = (reg); \
|
||||
MFPDELAY(); \
|
||||
atari_scc.cha_b_ctrl = (val); \
|
||||
MFPDELAY(); \
|
||||
} while (0)
|
||||
|
||||
/* loops_per_jiffy isn't initialized yet, so we can't use udelay(). This does a
|
||||
* delay of ~ 60us. */
|
||||
#define LONG_DELAY() \
|
||||
do { \
|
||||
int i; \
|
||||
for (i = 100; i > 0; --i) \
|
||||
MFPDELAY(); \
|
||||
} while (0)
|
||||
|
||||
static void __init atari_init_scc_port(int cflag)
|
||||
{
|
||||
static int clksrc_table[9] =
|
||||
/* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */
|
||||
{ 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 };
|
||||
static int brgsrc_table[9] =
|
||||
/* reg 14: 0 = RTxC, 2 = PCLK */
|
||||
{ 2, 2, 2, 2, 2, 2, 0, 2, 2 };
|
||||
static int clkmode_table[9] =
|
||||
/* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */
|
||||
{ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 };
|
||||
static int div_table[9] =
|
||||
/* reg12 (BRG low) */
|
||||
{ 208, 138, 103, 50, 24, 11, 1, 0, 0 };
|
||||
|
||||
int baud = cflag & CBAUD;
|
||||
int clksrc, clkmode, div, reg3, reg5;
|
||||
|
||||
if (cflag & CBAUDEX)
|
||||
baud += B38400;
|
||||
if (baud < B1200 || baud > B38400+2)
|
||||
baud = B9600; /* use default 9600bps for non-implemented rates */
|
||||
baud -= B1200; /* tables starts at 1200bps */
|
||||
|
||||
clksrc = clksrc_table[baud];
|
||||
clkmode = clkmode_table[baud];
|
||||
div = div_table[baud];
|
||||
if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) {
|
||||
/* special treatment for TT, where rates >= 38400 are done via TRxC */
|
||||
clksrc = 0x28; /* TRxC */
|
||||
clkmode = baud == 6 ? 0xc0 :
|
||||
baud == 7 ? 0x80 : /* really 76800bps */
|
||||
0x40; /* really 153600bps */
|
||||
div = 0;
|
||||
}
|
||||
|
||||
reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40;
|
||||
reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */;
|
||||
|
||||
(void)atari_scc.cha_b_ctrl; /* reset reg pointer */
|
||||
SCC_WRITE(9, 0xc0); /* reset */
|
||||
LONG_DELAY(); /* extra delay after WR9 access */
|
||||
SCC_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03)
|
||||
: 0 | 0x04 /* 1 stopbit */ | clkmode);
|
||||
SCC_WRITE(3, reg3);
|
||||
SCC_WRITE(5, reg5);
|
||||
SCC_WRITE(9, 0); /* no interrupts */
|
||||
LONG_DELAY(); /* extra delay after WR9 access */
|
||||
SCC_WRITE(10, 0); /* NRZ mode */
|
||||
SCC_WRITE(11, clksrc); /* main clock source */
|
||||
SCC_WRITE(12, div); /* BRG value */
|
||||
SCC_WRITE(13, 0); /* BRG high byte */
|
||||
SCC_WRITE(14, brgsrc_table[baud]);
|
||||
SCC_WRITE(14, brgsrc_table[baud] | (div ? 1 : 0));
|
||||
SCC_WRITE(3, reg3 | 1);
|
||||
SCC_WRITE(5, reg5 | 8);
|
||||
|
||||
atari_SCC_reset_done = 1;
|
||||
}
|
||||
|
||||
static void __init atari_init_midi_port(int cflag)
|
||||
{
|
||||
int baud = cflag & CBAUD;
|
||||
int csize = ((cflag & CSIZE) == CS8) ? 0x10 : 0x00;
|
||||
/* warning 7N1 isn't possible! (instead 7O2 is used...) */
|
||||
int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x0c : 0x08) : 0x04;
|
||||
int div;
|
||||
|
||||
/* 4800 selects 7812.5, 115200 selects 500000, all other (incl. 9600 as
|
||||
* default) the standard MIDI speed 31250. */
|
||||
if (cflag & CBAUDEX)
|
||||
baud += B38400;
|
||||
if (baud == B4800)
|
||||
div = ACIA_DIV64; /* really 7812.5 bps */
|
||||
else if (baud == B38400+2 /* 115200 */)
|
||||
div = ACIA_DIV1; /* really 500 kbps (does that work??) */
|
||||
else
|
||||
div = ACIA_DIV16; /* 31250 bps, standard for MIDI */
|
||||
|
||||
/* RTS low, ints disabled */
|
||||
acia.mid_ctrl = div | csize | parity |
|
||||
((atari_switches & ATARI_SWITCH_MIDI) ?
|
||||
ACIA_RHTID : ACIA_RLTID);
|
||||
}
|
||||
|
||||
static int __init atari_debug_setup(char *arg)
|
||||
{
|
||||
bool registered;
|
||||
|
||||
if (!MACH_IS_ATARI)
|
||||
return 0;
|
||||
|
||||
if (!strcmp(arg, "ser"))
|
||||
/* defaults to ser2 for a Falcon and ser1 otherwise */
|
||||
arg = MACH_IS_FALCON ? "ser2" : "ser1";
|
||||
|
||||
registered = !!atari_console_driver.write;
|
||||
if (!strcmp(arg, "ser1")) {
|
||||
/* ST-MFP Modem1 serial port */
|
||||
atari_init_mfp_port(B9600|CS8);
|
||||
atari_console_driver.write = atari_mfp_console_write;
|
||||
} else if (!strcmp(arg, "ser2")) {
|
||||
/* SCC Modem2 serial port */
|
||||
atari_init_scc_port(B9600|CS8);
|
||||
atari_console_driver.write = atari_scc_console_write;
|
||||
} else if (!strcmp(arg, "midi")) {
|
||||
/* MIDI port */
|
||||
atari_init_midi_port(B9600|CS8);
|
||||
atari_console_driver.write = atari_midi_console_write;
|
||||
} else if (!strcmp(arg, "par")) {
|
||||
/* parallel printer */
|
||||
atari_turnoff_irq(IRQ_MFP_BUSY); /* avoid ints */
|
||||
sound_ym.rd_data_reg_sel = 7; /* select mixer control */
|
||||
sound_ym.wd_data = 0xff; /* sound off, ports are output */
|
||||
sound_ym.rd_data_reg_sel = 15; /* select port B */
|
||||
sound_ym.wd_data = 0; /* no char */
|
||||
sound_ym.rd_data_reg_sel = 14; /* select port A */
|
||||
sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */
|
||||
atari_console_driver.write = atari_par_console_write;
|
||||
}
|
||||
if (atari_console_driver.write && !registered)
|
||||
register_console(&atari_console_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
early_param("debug", atari_debug_setup);
|
201
arch/m68k/atari/stdma.c
Normal file
201
arch/m68k/atari/stdma.c
Normal file
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* linux/arch/m68k/atari/stmda.c
|
||||
*
|
||||
* Copyright (C) 1994 Roman Hodek
|
||||
*
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
|
||||
/* This file contains some function for controlling the access to the */
|
||||
/* ST-DMA chip that may be shared between devices. Currently we have: */
|
||||
/* TT: Floppy and ACSI bus */
|
||||
/* Falcon: Floppy and SCSI */
|
||||
/* */
|
||||
/* The controlling functions set up a wait queue for access to the */
|
||||
/* ST-DMA chip. Callers to stdma_lock() that cannot granted access are */
|
||||
/* put onto a queue and waked up later if the owner calls */
|
||||
/* stdma_release(). Additionally, the caller gives his interrupt */
|
||||
/* service routine to stdma_lock(). */
|
||||
/* */
|
||||
/* On the Falcon, the IDE bus uses just the ACSI/Floppy interrupt, but */
|
||||
/* not the ST-DMA chip itself. So falhd.c needs not to lock the */
|
||||
/* chip. The interrupt is routed to falhd.c if IDE is configured, the */
|
||||
/* model is a Falcon and the interrupt was caused by the HD controller */
|
||||
/* (can be determined by looking at its status register). */
|
||||
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <linux/genhd.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/atari_stdma.h>
|
||||
#include <asm/atariints.h>
|
||||
#include <asm/atarihw.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
static int stdma_locked; /* the semaphore */
|
||||
/* int func to be called */
|
||||
static irq_handler_t stdma_isr;
|
||||
static void *stdma_isr_data; /* data passed to isr */
|
||||
static DECLARE_WAIT_QUEUE_HEAD(stdma_wait); /* wait queue for ST-DMA */
|
||||
|
||||
|
||||
|
||||
|
||||
/***************************** Prototypes *****************************/
|
||||
|
||||
static irqreturn_t stdma_int (int irq, void *dummy);
|
||||
|
||||
/************************* End of Prototypes **************************/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Function: void stdma_lock( isrfunc isr, void *data )
|
||||
*
|
||||
* Purpose: Tries to get a lock on the ST-DMA chip that is used by more
|
||||
* then one device driver. Waits on stdma_wait until lock is free.
|
||||
* stdma_lock() may not be called from an interrupt! You have to
|
||||
* get the lock in your main routine and release it when your
|
||||
* request is finished.
|
||||
*
|
||||
* Inputs: A interrupt function that is called until the lock is
|
||||
* released.
|
||||
*
|
||||
* Returns: nothing
|
||||
*
|
||||
*/
|
||||
|
||||
void stdma_lock(irq_handler_t handler, void *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags); /* protect lock */
|
||||
|
||||
/* Since the DMA is used for file system purposes, we
|
||||
have to sleep uninterruptible (there may be locked
|
||||
buffers) */
|
||||
wait_event(stdma_wait, !stdma_locked);
|
||||
|
||||
stdma_locked = 1;
|
||||
stdma_isr = handler;
|
||||
stdma_isr_data = data;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
EXPORT_SYMBOL(stdma_lock);
|
||||
|
||||
|
||||
/*
|
||||
* Function: void stdma_release( void )
|
||||
*
|
||||
* Purpose: Releases the lock on the ST-DMA chip.
|
||||
*
|
||||
* Inputs: none
|
||||
*
|
||||
* Returns: nothing
|
||||
*
|
||||
*/
|
||||
|
||||
void stdma_release(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
stdma_locked = 0;
|
||||
stdma_isr = NULL;
|
||||
stdma_isr_data = NULL;
|
||||
wake_up(&stdma_wait);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
EXPORT_SYMBOL(stdma_release);
|
||||
|
||||
|
||||
/*
|
||||
* Function: int stdma_others_waiting( void )
|
||||
*
|
||||
* Purpose: Check if someone waits for the ST-DMA lock.
|
||||
*
|
||||
* Inputs: none
|
||||
*
|
||||
* Returns: 0 if no one is waiting, != 0 otherwise
|
||||
*
|
||||
*/
|
||||
|
||||
int stdma_others_waiting(void)
|
||||
{
|
||||
return waitqueue_active(&stdma_wait);
|
||||
}
|
||||
EXPORT_SYMBOL(stdma_others_waiting);
|
||||
|
||||
|
||||
/*
|
||||
* Function: int stdma_islocked( void )
|
||||
*
|
||||
* Purpose: Check if the ST-DMA is currently locked.
|
||||
* Note: Returned status is only valid if ints are disabled while calling and
|
||||
* as long as they remain disabled.
|
||||
* If called with ints enabled, status can change only from locked to
|
||||
* unlocked, because ints may not lock the ST-DMA.
|
||||
*
|
||||
* Inputs: none
|
||||
*
|
||||
* Returns: != 0 if locked, 0 otherwise
|
||||
*
|
||||
*/
|
||||
|
||||
int stdma_islocked(void)
|
||||
{
|
||||
return stdma_locked;
|
||||
}
|
||||
EXPORT_SYMBOL(stdma_islocked);
|
||||
|
||||
|
||||
/*
|
||||
* Function: void stdma_init( void )
|
||||
*
|
||||
* Purpose: Initialize the ST-DMA chip access controlling.
|
||||
* It sets up the interrupt and its service routine. The int is registered
|
||||
* as slow int, client devices have to live with that (no problem
|
||||
* currently).
|
||||
*
|
||||
* Inputs: none
|
||||
*
|
||||
* Return: nothing
|
||||
*
|
||||
*/
|
||||
|
||||
void __init stdma_init(void)
|
||||
{
|
||||
stdma_isr = NULL;
|
||||
if (request_irq(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW | IRQF_SHARED,
|
||||
"ST-DMA floppy,ACSI,IDE,Falcon-SCSI", stdma_int))
|
||||
pr_err("Couldn't register ST-DMA interrupt\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function: void stdma_int()
|
||||
*
|
||||
* Purpose: The interrupt routine for the ST-DMA. It calls the isr
|
||||
* registered by stdma_lock().
|
||||
*
|
||||
*/
|
||||
|
||||
static irqreturn_t stdma_int(int irq, void *dummy)
|
||||
{
|
||||
if (stdma_isr)
|
||||
(*stdma_isr)(irq, stdma_isr_data);
|
||||
return IRQ_HANDLED;
|
||||
}
|
198
arch/m68k/atari/stram.c
Normal file
198
arch/m68k/atari/stram.c
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* Functions for ST-RAM allocations
|
||||
*
|
||||
* Copyright 1994-97 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ioport.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/atarihw.h>
|
||||
#include <asm/atari_stram.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
|
||||
/*
|
||||
* The ST-RAM allocator allocates memory from a pool of reserved ST-RAM of
|
||||
* configurable size, set aside on ST-RAM init.
|
||||
* As long as this pool is not exhausted, allocation of real ST-RAM can be
|
||||
* guaranteed.
|
||||
*/
|
||||
|
||||
/* set if kernel is in ST-RAM */
|
||||
static int kernel_in_stram;
|
||||
|
||||
static struct resource stram_pool = {
|
||||
.name = "ST-RAM Pool"
|
||||
};
|
||||
|
||||
static unsigned long pool_size = 1024*1024;
|
||||
|
||||
static unsigned long stram_virt_offset;
|
||||
|
||||
static int __init atari_stram_setup(char *arg)
|
||||
{
|
||||
if (!MACH_IS_ATARI)
|
||||
return 0;
|
||||
|
||||
pool_size = memparse(arg, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
early_param("stram_pool", atari_stram_setup);
|
||||
|
||||
|
||||
/*
|
||||
* This init function is called very early by atari/config.c
|
||||
* It initializes some internal variables needed for stram_alloc()
|
||||
*/
|
||||
void __init atari_stram_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* determine whether kernel code resides in ST-RAM
|
||||
* (then ST-RAM is the first memory block at virtual 0x0)
|
||||
*/
|
||||
kernel_in_stram = (m68k_memory[0].addr == 0);
|
||||
|
||||
for (i = 0; i < m68k_num_memory; ++i) {
|
||||
if (m68k_memory[i].addr == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Should never come here! (There is always ST-Ram!) */
|
||||
panic("atari_stram_init: no ST-RAM found!");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called from setup_arch() to reserve the pages needed for
|
||||
* ST-RAM management, if the kernel resides in ST-RAM.
|
||||
*/
|
||||
void __init atari_stram_reserve_pages(void *start_mem)
|
||||
{
|
||||
if (kernel_in_stram) {
|
||||
pr_debug("atari_stram pool: kernel in ST-RAM, using alloc_bootmem!\n");
|
||||
stram_pool.start = (resource_size_t)alloc_bootmem_low_pages(pool_size);
|
||||
stram_pool.end = stram_pool.start + pool_size - 1;
|
||||
request_resource(&iomem_resource, &stram_pool);
|
||||
stram_virt_offset = 0;
|
||||
pr_debug("atari_stram pool: size = %lu bytes, resource = %pR\n",
|
||||
pool_size, &stram_pool);
|
||||
pr_debug("atari_stram pool: stram_virt_offset = %lx\n",
|
||||
stram_virt_offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called as arch initcall to reserve the pages needed for
|
||||
* ST-RAM management, if the kernel does not reside in ST-RAM.
|
||||
*/
|
||||
int __init atari_stram_map_pages(void)
|
||||
{
|
||||
if (!kernel_in_stram) {
|
||||
/*
|
||||
* Skip page 0, as the fhe first 2 KiB are supervisor-only!
|
||||
*/
|
||||
pr_debug("atari_stram pool: kernel not in ST-RAM, using ioremap!\n");
|
||||
stram_pool.start = PAGE_SIZE;
|
||||
stram_pool.end = stram_pool.start + pool_size - 1;
|
||||
request_resource(&iomem_resource, &stram_pool);
|
||||
stram_virt_offset = (unsigned long) ioremap(stram_pool.start,
|
||||
resource_size(&stram_pool)) - stram_pool.start;
|
||||
pr_debug("atari_stram pool: size = %lu bytes, resource = %pR\n",
|
||||
pool_size, &stram_pool);
|
||||
pr_debug("atari_stram pool: stram_virt_offset = %lx\n",
|
||||
stram_virt_offset);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(atari_stram_map_pages);
|
||||
|
||||
|
||||
void *atari_stram_to_virt(unsigned long phys)
|
||||
{
|
||||
return (void *)(phys + stram_virt_offset);
|
||||
}
|
||||
EXPORT_SYMBOL(atari_stram_to_virt);
|
||||
|
||||
|
||||
unsigned long atari_stram_to_phys(void *virt)
|
||||
{
|
||||
return (unsigned long)(virt - stram_virt_offset);
|
||||
}
|
||||
EXPORT_SYMBOL(atari_stram_to_phys);
|
||||
|
||||
|
||||
void *atari_stram_alloc(unsigned long size, const char *owner)
|
||||
{
|
||||
struct resource *res;
|
||||
int error;
|
||||
|
||||
pr_debug("atari_stram_alloc: allocate %lu bytes\n", size);
|
||||
|
||||
/* round up */
|
||||
size = PAGE_ALIGN(size);
|
||||
|
||||
res = kzalloc(sizeof(struct resource), GFP_KERNEL);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
res->name = owner;
|
||||
error = allocate_resource(&stram_pool, res, size, 0, UINT_MAX,
|
||||
PAGE_SIZE, NULL, NULL);
|
||||
if (error < 0) {
|
||||
pr_err("atari_stram_alloc: allocate_resource() failed %d!\n",
|
||||
error);
|
||||
kfree(res);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pr_debug("atari_stram_alloc: returning %pR\n", res);
|
||||
return atari_stram_to_virt(res->start);
|
||||
}
|
||||
EXPORT_SYMBOL(atari_stram_alloc);
|
||||
|
||||
|
||||
void atari_stram_free(void *addr)
|
||||
{
|
||||
unsigned long start = atari_stram_to_phys(addr);
|
||||
struct resource *res;
|
||||
unsigned long size;
|
||||
|
||||
res = lookup_resource(&stram_pool, start);
|
||||
if (!res) {
|
||||
pr_err("atari_stram_free: trying to free nonexistent region "
|
||||
"at %p\n", addr);
|
||||
return;
|
||||
}
|
||||
|
||||
size = resource_size(res);
|
||||
pr_debug("atari_stram_free: free %lu bytes at %p\n", size, addr);
|
||||
release_resource(res);
|
||||
kfree(res);
|
||||
}
|
||||
EXPORT_SYMBOL(atari_stram_free);
|
357
arch/m68k/atari/time.c
Normal file
357
arch/m68k/atari/time.c
Normal file
|
@ -0,0 +1,357 @@
|
|||
/*
|
||||
* linux/arch/m68k/atari/time.c
|
||||
*
|
||||
* Atari time and real time clock stuff
|
||||
*
|
||||
* Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include <asm/atariints.h>
|
||||
|
||||
DEFINE_SPINLOCK(rtc_lock);
|
||||
EXPORT_SYMBOL_GPL(rtc_lock);
|
||||
|
||||
void __init
|
||||
atari_sched_init(irq_handler_t timer_routine)
|
||||
{
|
||||
/* set Timer C data Register */
|
||||
st_mfp.tim_dt_c = INT_TICKS;
|
||||
/* start timer C, div = 1:100 */
|
||||
st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 15) | 0x60;
|
||||
/* install interrupt service routine for MFP Timer C */
|
||||
if (request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW,
|
||||
"timer", timer_routine))
|
||||
pr_err("Couldn't register timer interrupt\n");
|
||||
}
|
||||
|
||||
/* ++andreas: gettimeoffset fixed to check for pending interrupt */
|
||||
|
||||
#define TICK_SIZE 10000
|
||||
|
||||
/* This is always executed with interrupts disabled. */
|
||||
u32 atari_gettimeoffset(void)
|
||||
{
|
||||
u32 ticks, offset = 0;
|
||||
|
||||
/* read MFP timer C current value */
|
||||
ticks = st_mfp.tim_dt_c;
|
||||
/* The probability of underflow is less than 2% */
|
||||
if (ticks > INT_TICKS - INT_TICKS / 50)
|
||||
/* Check for pending timer interrupt */
|
||||
if (st_mfp.int_pn_b & (1 << 5))
|
||||
offset = TICK_SIZE;
|
||||
|
||||
ticks = INT_TICKS - ticks;
|
||||
ticks = ticks * 10000L / INT_TICKS;
|
||||
|
||||
return (ticks + offset) * 1000;
|
||||
}
|
||||
|
||||
|
||||
static void mste_read(struct MSTE_RTC *val)
|
||||
{
|
||||
#define COPY(v) val->v=(mste_rtc.v & 0xf)
|
||||
do {
|
||||
COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
|
||||
COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
|
||||
COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
|
||||
COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
|
||||
COPY(year_tens) ;
|
||||
/* prevent from reading the clock while it changed */
|
||||
} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
|
||||
#undef COPY
|
||||
}
|
||||
|
||||
static void mste_write(struct MSTE_RTC *val)
|
||||
{
|
||||
#define COPY(v) mste_rtc.v=val->v
|
||||
do {
|
||||
COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
|
||||
COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
|
||||
COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
|
||||
COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
|
||||
COPY(year_tens) ;
|
||||
/* prevent from writing the clock while it changed */
|
||||
} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
|
||||
#undef COPY
|
||||
}
|
||||
|
||||
#define RTC_READ(reg) \
|
||||
({ unsigned char __val; \
|
||||
(void) atari_writeb(reg,&tt_rtc.regsel); \
|
||||
__val = tt_rtc.data; \
|
||||
__val; \
|
||||
})
|
||||
|
||||
#define RTC_WRITE(reg,val) \
|
||||
do { \
|
||||
atari_writeb(reg,&tt_rtc.regsel); \
|
||||
tt_rtc.data = (val); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define HWCLK_POLL_INTERVAL 5
|
||||
|
||||
int atari_mste_hwclk( int op, struct rtc_time *t )
|
||||
{
|
||||
int hour, year;
|
||||
int hr24=0;
|
||||
struct MSTE_RTC val;
|
||||
|
||||
mste_rtc.mode=(mste_rtc.mode | 1);
|
||||
hr24=mste_rtc.mon_tens & 1;
|
||||
mste_rtc.mode=(mste_rtc.mode & ~1);
|
||||
|
||||
if (op) {
|
||||
/* write: prepare values */
|
||||
|
||||
val.sec_ones = t->tm_sec % 10;
|
||||
val.sec_tens = t->tm_sec / 10;
|
||||
val.min_ones = t->tm_min % 10;
|
||||
val.min_tens = t->tm_min / 10;
|
||||
hour = t->tm_hour;
|
||||
if (!hr24) {
|
||||
if (hour > 11)
|
||||
hour += 20 - 12;
|
||||
if (hour == 0 || hour == 20)
|
||||
hour += 12;
|
||||
}
|
||||
val.hr_ones = hour % 10;
|
||||
val.hr_tens = hour / 10;
|
||||
val.day_ones = t->tm_mday % 10;
|
||||
val.day_tens = t->tm_mday / 10;
|
||||
val.mon_ones = (t->tm_mon+1) % 10;
|
||||
val.mon_tens = (t->tm_mon+1) / 10;
|
||||
year = t->tm_year - 80;
|
||||
val.year_ones = year % 10;
|
||||
val.year_tens = year / 10;
|
||||
val.weekday = t->tm_wday;
|
||||
mste_write(&val);
|
||||
mste_rtc.mode=(mste_rtc.mode | 1);
|
||||
val.year_ones = (year % 4); /* leap year register */
|
||||
mste_rtc.mode=(mste_rtc.mode & ~1);
|
||||
}
|
||||
else {
|
||||
mste_read(&val);
|
||||
t->tm_sec = val.sec_ones + val.sec_tens * 10;
|
||||
t->tm_min = val.min_ones + val.min_tens * 10;
|
||||
hour = val.hr_ones + val.hr_tens * 10;
|
||||
if (!hr24) {
|
||||
if (hour == 12 || hour == 12 + 20)
|
||||
hour -= 12;
|
||||
if (hour >= 20)
|
||||
hour += 12 - 20;
|
||||
}
|
||||
t->tm_hour = hour;
|
||||
t->tm_mday = val.day_ones + val.day_tens * 10;
|
||||
t->tm_mon = val.mon_ones + val.mon_tens * 10 - 1;
|
||||
t->tm_year = val.year_ones + val.year_tens * 10 + 80;
|
||||
t->tm_wday = val.weekday;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int atari_tt_hwclk( int op, struct rtc_time *t )
|
||||
{
|
||||
int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0;
|
||||
unsigned long flags;
|
||||
unsigned char ctrl;
|
||||
int pm = 0;
|
||||
|
||||
ctrl = RTC_READ(RTC_CONTROL); /* control registers are
|
||||
* independent from the UIP */
|
||||
|
||||
if (op) {
|
||||
/* write: prepare values */
|
||||
|
||||
sec = t->tm_sec;
|
||||
min = t->tm_min;
|
||||
hour = t->tm_hour;
|
||||
day = t->tm_mday;
|
||||
mon = t->tm_mon + 1;
|
||||
year = t->tm_year - atari_rtc_year_offset;
|
||||
wday = t->tm_wday + (t->tm_wday >= 0);
|
||||
|
||||
if (!(ctrl & RTC_24H)) {
|
||||
if (hour > 11) {
|
||||
pm = 0x80;
|
||||
if (hour != 12)
|
||||
hour -= 12;
|
||||
}
|
||||
else if (hour == 0)
|
||||
hour = 12;
|
||||
}
|
||||
|
||||
if (!(ctrl & RTC_DM_BINARY)) {
|
||||
sec = bin2bcd(sec);
|
||||
min = bin2bcd(min);
|
||||
hour = bin2bcd(hour);
|
||||
day = bin2bcd(day);
|
||||
mon = bin2bcd(mon);
|
||||
year = bin2bcd(year);
|
||||
if (wday >= 0)
|
||||
wday = bin2bcd(wday);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reading/writing the clock registers is a bit critical due to
|
||||
* the regular update cycle of the RTC. While an update is in
|
||||
* progress, registers 0..9 shouldn't be touched.
|
||||
* The problem is solved like that: If an update is currently in
|
||||
* progress (the UIP bit is set), the process sleeps for a while
|
||||
* (50ms). This really should be enough, since the update cycle
|
||||
* normally needs 2 ms.
|
||||
* If the UIP bit reads as 0, we have at least 244 usecs until the
|
||||
* update starts. This should be enough... But to be sure,
|
||||
* additionally the RTC_SET bit is set to prevent an update cycle.
|
||||
*/
|
||||
|
||||
while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
|
||||
if (in_atomic() || irqs_disabled())
|
||||
mdelay(1);
|
||||
else
|
||||
schedule_timeout_interruptible(HWCLK_POLL_INTERVAL);
|
||||
}
|
||||
|
||||
local_irq_save(flags);
|
||||
RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
|
||||
if (!op) {
|
||||
sec = RTC_READ( RTC_SECONDS );
|
||||
min = RTC_READ( RTC_MINUTES );
|
||||
hour = RTC_READ( RTC_HOURS );
|
||||
day = RTC_READ( RTC_DAY_OF_MONTH );
|
||||
mon = RTC_READ( RTC_MONTH );
|
||||
year = RTC_READ( RTC_YEAR );
|
||||
wday = RTC_READ( RTC_DAY_OF_WEEK );
|
||||
}
|
||||
else {
|
||||
RTC_WRITE( RTC_SECONDS, sec );
|
||||
RTC_WRITE( RTC_MINUTES, min );
|
||||
RTC_WRITE( RTC_HOURS, hour + pm);
|
||||
RTC_WRITE( RTC_DAY_OF_MONTH, day );
|
||||
RTC_WRITE( RTC_MONTH, mon );
|
||||
RTC_WRITE( RTC_YEAR, year );
|
||||
if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday );
|
||||
}
|
||||
RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET );
|
||||
local_irq_restore(flags);
|
||||
|
||||
if (!op) {
|
||||
/* read: adjust values */
|
||||
|
||||
if (hour & 0x80) {
|
||||
hour &= ~0x80;
|
||||
pm = 1;
|
||||
}
|
||||
|
||||
if (!(ctrl & RTC_DM_BINARY)) {
|
||||
sec = bcd2bin(sec);
|
||||
min = bcd2bin(min);
|
||||
hour = bcd2bin(hour);
|
||||
day = bcd2bin(day);
|
||||
mon = bcd2bin(mon);
|
||||
year = bcd2bin(year);
|
||||
wday = bcd2bin(wday);
|
||||
}
|
||||
|
||||
if (!(ctrl & RTC_24H)) {
|
||||
if (!pm && hour == 12)
|
||||
hour = 0;
|
||||
else if (pm && hour != 12)
|
||||
hour += 12;
|
||||
}
|
||||
|
||||
t->tm_sec = sec;
|
||||
t->tm_min = min;
|
||||
t->tm_hour = hour;
|
||||
t->tm_mday = day;
|
||||
t->tm_mon = mon - 1;
|
||||
t->tm_year = year + atari_rtc_year_offset;
|
||||
t->tm_wday = wday - 1;
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
||||
int atari_mste_set_clock_mmss (unsigned long nowtime)
|
||||
{
|
||||
short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
|
||||
struct MSTE_RTC val;
|
||||
unsigned char rtc_minutes;
|
||||
|
||||
mste_read(&val);
|
||||
rtc_minutes= val.min_ones + val.min_tens * 10;
|
||||
if ((rtc_minutes < real_minutes
|
||||
? real_minutes - rtc_minutes
|
||||
: rtc_minutes - real_minutes) < 30)
|
||||
{
|
||||
val.sec_ones = real_seconds % 10;
|
||||
val.sec_tens = real_seconds / 10;
|
||||
val.min_ones = real_minutes % 10;
|
||||
val.min_tens = real_minutes / 10;
|
||||
mste_write(&val);
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int atari_tt_set_clock_mmss (unsigned long nowtime)
|
||||
{
|
||||
int retval = 0;
|
||||
short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
|
||||
unsigned char save_control, save_freq_select, rtc_minutes;
|
||||
|
||||
save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */
|
||||
RTC_WRITE (RTC_CONTROL, save_control | RTC_SET);
|
||||
|
||||
save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */
|
||||
RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2);
|
||||
|
||||
rtc_minutes = RTC_READ (RTC_MINUTES);
|
||||
if (!(save_control & RTC_DM_BINARY))
|
||||
rtc_minutes = bcd2bin(rtc_minutes);
|
||||
|
||||
/* Since we're only adjusting minutes and seconds, don't interfere
|
||||
with hour overflow. This avoids messing with unknown time zones
|
||||
but requires your RTC not to be off by more than 30 minutes. */
|
||||
if ((rtc_minutes < real_minutes
|
||||
? real_minutes - rtc_minutes
|
||||
: rtc_minutes - real_minutes) < 30)
|
||||
{
|
||||
if (!(save_control & RTC_DM_BINARY))
|
||||
{
|
||||
real_seconds = bin2bcd(real_seconds);
|
||||
real_minutes = bin2bcd(real_minutes);
|
||||
}
|
||||
RTC_WRITE (RTC_SECONDS, real_seconds);
|
||||
RTC_WRITE (RTC_MINUTES, real_minutes);
|
||||
}
|
||||
else
|
||||
retval = -1;
|
||||
|
||||
RTC_WRITE (RTC_FREQ_SELECT, save_freq_select);
|
||||
RTC_WRITE (RTC_CONTROL, save_control);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-indent-level: 4
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
Loading…
Add table
Add a link
Reference in a new issue