/* $Header: /sys/linux-0.96a/include/linux/system.h,v 0.1.0.3 1992/06/01 01:57:34 root Exp root $
 * include/linux/system.h
 * Some defines for AT motherboard devices for use with Linux. Definitions
 * for devices on the expansion cards belongs in other files.
 * H.H. Bergman 1992.
 */

#ifndef _LINUX_SYSTEM_H
#define _LINUX_SYSTEM_H

#ifndef _SYSTEM_BUS
#include <linux/config.h>
#endif

/* If this file does anything other than just '#define'ing things,
 * you should put '#ifndef __DEFONLY__' / '#endif' around that, because
 * this file is not only used C source, but in assembler source too.
 *
 * Dependencies on ISA/EISA/MCA should be marked with SYSTEM_BUS_x
 * where 'x' is the bus type.
 */

/* 8259A -- Programmable Interrupt Controllers (PIC) */
#define IO_PIC1		0x20	/* master PIC */
#define IO_PIC2		0xA0	/* slave PIC */

/* 8237 DMA controllers */
#define IO_DMA1		0x00	/* 8 bit slave DMA, channels 0..3 */
#define IO_DMA2		0xC0	/* 16 bit master DMA, ch 4(=slave input)..7 */
#define IO_DMA_PAGE	0x80	/* page registers for DMA1 */

#define IO_TIMER1	0x40
#define IO_TIMER2	0x48
#define IO_KBD		0x60	/* 8042 keyboard controller */
#define IO_RTC		0x70	/* real time clock */
#define IO_NMI		IO_RTC	/* NMI control */
#define IO_NPX		0xF0	/* [34]87 FPU */


/* offsets from DMA register base */
#define DMA_CMD		0x08	/* DMA command register */
#define DMA_STAT	0x08	/* DMA status register */
#define DMA_MASK	0x0A	/* mask individual channels */
#define DMA_MODE	0x0B	/* set modes for individual channels */
#define DMA_CLEAR_FF	0x0C	/* Write 0 for LSB, 1 for MSB */
#define DMA_RESET	0x0D	/* Write here to reset DMA controller */


/* PIC commands */
#define PIC_EOI		0x20	/* end-of-interrupt command */


/* DMA channel identifiers [4..7 not supported yet] */
#define DMA0		0x00	/* DRAM resfresh? */
#define DMA1		0x01	/* ``free'' */
#define DMA2		0x02	/* floppy */
#define DMA3		0x03	/* ``free'' */
#if 0
#define DMA_SLAVE	0x04	/* connect slave to master DMA?? */
#define DMA5		0x05
#define DMA6		0x06
#define DMA7		0x07
#endif

/* map DMA channel id to page register number */
#define DMA_NR_TO_PAGEREG(d)	((unsigned) ("\200\203\201\202"[(d)])&0xff)

/* map DMA channel id to DMA controller register base */
#define DMA_NR_TO_REGBASE(d)   ((unsigned) ("\000\000\000\000\300\300\300\300"[(d)])&0xff)


/* For "historic reasons", ATs have their hardware 'IRQ2' signal
 * wired to IRQ9, which is on the slave Programmable Interrupt
 * Controller, which is chained to the master PIC on input #3. 
 * The master PIC has IRQ0..7, Slave has IRQ8..15. IRQ2 on the XT
 * is remapped to IRQ9 on the AT. :-(
 */

/* IRQ mask identifiers */
#define IRQ0_MASK	0x0001
#define IRQ1_MASK	0x0002
#define IRQ_SLAVE_MASK	0x0004
#define IRQ2_MASK	IRQ9_MASK
#define IRQ3_MASK	0x0008
#define IRQ4_MASK	0x0010
#define IRQ5_MASK	0x0020
#define IRQ6_MASK	0x0040
#define IRQ7_MASK	0x0080
#define IRQ8_MASK	0x0100
#define IRQ9_MASK	0x0200
#define IRQ10_MASK	0x0400
#define IRQ11_MASK	0x0800
#define IRQ12_MASK	0x1000
#define IRQ13_MASK	0x2000
#define IRQ14_MASK	0x4000
#define IRQ15_MASK	0x8000

/* IRQ number identifiers */
#define IRQ0		0x00	/* timer 0 ? */
#define IRQ1		0x01	/* keyboard */
#define IRQ_SLAVE	0x02	/* slave PIC */
#define IRQ2		IRQ9
#define IRQ3		0x03	/* serial port */
#define IRQ4		0x04	/* serial port */
#define IRQ5		0x05
#define IRQ6		0x06	/* floppy? */
#define IRQ7		0x07	/* printer */
#define IRQ8		0x08	/* clock/calendar */
#define IRQ9		0x09	/* video/network */
#define IRQ10		0x0A	
#define IRQ11		0x0B
#define IRQ12		0x0C
#define IRQ13		0x0D
#define IRQ14		0x0E
#define IRQ15		0x0F





/* enable/disable a group of interrupts using IRQ*_MASK */
#define ENABLE_IRQ_MASK(m)   if ((m)>>8) \
				outb_p(inb_p(IO_PIC2+1)&~((m)>>8), IO_PIC2+1); \
			     outb_p(inb_p(IO_PIC1+1)&~((m)&0xFF), IO_PIC1+1)

#define DISABLE_IRQ_MASK(m)  if ((m)>>8) \
				outb_p(inb_p(IO_PIC2+1)|((m)>>8), IO_PIC2+1); \
			     outb_p(inb_p(IO_PIC1+1)|((m)&0xFF), IO_PIC1+1)


/* translate IRQ number to an IRQ_MASK: [LSB=master=PIC1, MSB=slave=PIC2] */
#define IRQ_NR_TO_MASK(n)	((unsigned) \
  (("\001\002\004\010\020\040\100\200\004\004\004\004\004\004\004\004"[(n)])&0xff) | \
  (("\000\000\000\000\000\000\000\000\001\002\004\010\020\040\100\200"[(n)])&0xff)<<8)

/* enable/disable a specific interrupt number.
 * Use the IRQnn defines (above) as parameter.
 */
#define ENABLE_IRQ(n)	ENABLE_IRQ_MASK(IRQ_NR_TO_MASK(n))
#define DISABLE_IRQ(n)	DISABLE_IRQ_MASK(IRQ_NR_TO_MASK(n))


/* NOTE about DMA transfers: The DMA controller cannot handle transfers
 * that cross a 64k boundary. When the address reaches 0xNffff, it will wrap
 * around to 0xN0000, rather than increment to 0x(N+1)0000 !
 * Make sure you align your buffers properly! Runtime check recommended.
 */

/******* CHECK the following for dma channels >=4 ***********/
/* enable/disable a specific DMA channel */
#define ENABLE_DMA(n)	outb_p((n), DMA_NR_TO_REGBASE(n)+DMA_MASK)
#define DISABLE_DMA(n)	outb_p((n)|4, DMA_NR_TO_REGBASE(n)+DMA_MASK)


/* Clear the 'DMA Pointer Flip Flop'.
 * Write 0 for LSB/MSB, 1 for MSB/LSB access.
 * Use this once to initialize the FF to a know state.
 * After that, keep it known. :-)
 */
#define CLEAR_DMA_FF(ch)	outb_p(0, DMA_NR_TO_REGBASE(ch)+DMA_CLEAR_FF)


#define DMA_MODE_READ	0x44	/* I/O to memory, no autoinit, increment, single mode */
#define DMA_MODE_WRITE	0x48	/* memory to I/O, no autoinit, increment, single mode */

/* set mode (above) for a specific DMA channel */
#define SET_DMA_MODE(ch, mode)	\
/***	printk(" dma mode(0x%x) := 0x%x. ", DMA_NR_TO_REGBASE(ch)+DMA_MODE, (mode)|((ch)&3)); \ ***/ \
	outb_p((mode)|((ch)&3), DMA_NR_TO_REGBASE(ch)+DMA_MODE) 

/* Set only the page register bits of the transfer address.
 * This is used for successive transfers when we know the contents of
 * the lower 16 bits of the DMA current address register, but a 64k boundary
 * may have been crossed.
 */
#define SET_DMA_PAGE(ch, a)	\
/***  printk("set dma pagereg %x: %x.  ", DMA_NR_TO_PAGEREG(ch), (a)); \ ***/ \
			outb_p((a), DMA_NR_TO_PAGEREG(ch))

/* Set transfer address & page bits for specific DMA channel
 * Assumes dma flipflop is clear.
 */
#define SET_DMA_ADDR(ch, a)	\
	/* page bits */	SET_DMA_PAGE((ch), (a)>>16); \
/*** printk("Addr: LSB %x, %x.  ", (a)&0xff, DMA_NR_TO_REGBASE(ch)+(((ch)&3)<<1)); \ ***/ \
	/* LSB */	outb_p((a)&0xff, DMA_NR_TO_REGBASE(ch)+(((ch)&3)<<1)); \
/*** printk("Addr: MSB: %x, %x.  ", ((a)>>8) & 0xff, DMA_NR_TO_REGBASE(ch)+(((ch)&3)<<1)); \ ***/ \
	/* MSB */	outb_p(((a)>>8) & 0xff, DMA_NR_TO_REGBASE(ch)+(((ch)&3)<<1))

/* Set transfer size (max 64k) for a specific DMA channel.
 * You must ensure the parameters are valid.
 * NOTE: from a manual: "the number of transfers is one more 
 * than the initial word count"! This is taken into account.
 * Assumes dma flip-flop is clear.
 */
#define SET_DMA_COUNT(ch, n)	\
/*** printk("Count: LSB %x, %x.  ", ((n)-1) & 0xff, DMA_NR_TO_REGBASE(ch)+(((ch)&3)<<1)+1); \ ***/ \
	/* LSB */	outb_p(((n)-1) & 0xff, DMA_NR_TO_REGBASE(ch)+(((ch)&3)<<1)+1); \
/*** printk("Count: MSB %x, %x.  ", ((n)-1)>>8, DMA_NR_TO_REGBASE(ch)+(((ch)&3)<<1)+1); \ ***/ \
	/* MSB */	outb_p(((n)-1)>>8, DMA_NR_TO_REGBASE(ch)+(((ch)&3)<<1)+1)

#endif /* _LINUX_SYSTEM_H */

