/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1986
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:dma.c 12.0$ */
/* $ACIS:dma.c 12.0$ */
/* $Source: /ibm/acis/usr/sys/standca/RCS/dma.c,v $ */

#ifndef lint
static char *rcsid = "$Header:dma.c 12.0$";
#endif

/* #include "saio.h" */
#include "dma.h"



/* global variables */

#define  ctl1_smask ((char *) CTL1_SMASK)
#define  crrb      ((char *) CRRB)
#define  ctl1_mode ((char *) CTL1_MODE)
#define  ctl1_base ((char *) CTL1_BASE)

#define  ctl1_req  ((char *) CTL1_REQ)
#define  ctl1_cmd  ((char *) CTL1_CMD)
#define  dbra      ((char *) DBRA)
#define  dmra      ((char *) DMRA)
#define  ctl1_ff   ((char *) CTL1_FF)



char init_dma = 1;		       /* first time initialize routine */




/* per channel structure */

struct dma_softc {
	int busy;		       /* busy */
	int subchannel;		       /* actual subchannel on (8237) */
	struct dma_req *req;	       /* queue for dma_requests */
} dm_softc[8];			       /* more memeber will be added in t */







/*****************************************************************************
Name            : dma_setup( request)
Date created    : 3-21-1985

Last modified   : 4-16-1985
Version         : 1  (stand alone driver)
Parameters      : request structure (refer to dma.h)
Return          : error status
                :  0 => OK
                : -1 => Boundary error
Author          : Robert M. Hadaya
Abstract        :

This routine will set up the corresponding TCW ( mapping registers) and set up
the corresponding 8237 channel.

A kluge initialization is done once.

*****************************************************************************/



int dma_setup(r)

	struct dma_req *r;
{

	int status;
#ifdef TEST1
	printf("DMA setup r=%x Chan=%x addr=%x len=%x op=%x tr=%x party=%x\n",
	    r,
	    r->dm_channel,
	    r->dm_bufaddr,
	    r->dm_length,
	    r->dm_operation,
	    r->dm_transfer,
	    r->dm_party
	    );
#endif
	if (init_dma) {
		dma_init();
		init_dma = 0;
	}
	;			       /* initialization kluge */

	status = 0;
	if (dm_softc[r->dm_channel].busy == 1) {
		printf("channel %x is busy \n", r->dm_channel);
		r->dm_error = -2;
		return (-1);
	}
	;

	if (r->dm_party != 3) {
		printf(" First party DMA not supported\n");
		r->dm_error = -3;
		return (-1);
	} else {		       /* third party DMA */

		switch (r->dm_channel) {
		case 0:		       /* 8bit controller 1  */
		case 1:
		case 2:
		case 3:
			status = ctl1_setup(r);
			break;
		case 4:
			status = -15;
			break;	       /* channel 4 unused   */
		case 5:		       /* 16 bit controller2 */
		case 6:
		case 7:
			status = ctl2_setup(r);
			break;
		case 8:
			status = copro_setup(r);
			break;	       /* coprocessor channel */

		default:
			status = -16;  /* invalid channel # */
		}
	}
#ifdef TEST1
	printf("status = %d\n", status);
#endif
	r->dm_error = status;
	return (0);
}


/*
Set up the first 8237 controller which corresponds to the 4 8 bit channels.
*/

int ctl1_setup(r)
	struct dma_req *r;
{
	short displacement;	       /* 2k displacement    */
	short len;
	short start_prefix;	       /* first tcw prefix   */
	short prefix;		       /* tcw prefix         */
	int real_addr;		       /* passed buffadr     */
	int ch;			       /* 8237 channel       */

	int chan;
	char mode = 0;		       /* mode byte            */
	char cmd = 0;		       /* command byte         */
	char mask = 0;		       /* mask byte            */
	int i;
	int status;		       /* returned status      */

	int temp1, temp2;
	int tcw_num;		       /* tcw number */

	chan = r->dm_channel;
	ch = dm_softc[chan].subchannel;

	real_addr = (int)r->dm_bufaddr;
#ifdef TEST1
	printf(" ch=%d real_addr =%x\n", ch, real_addr);
#endif


	/* setup IOCC registers          */



	temp2 = (*dmra);	       /* page mode only on 3 party     */
	*dmra = temp2 & (~(0x80 >> ch)); /* page mode only on 3 party     */
	/* set up 8237 controller        */

	mode = (mode | (r->dm_transfer) | (r->dm_operation) | ch);
#ifdef TEST1
	printf("8237 mode =%x  ", mode);
#endif
	*ctl1_mode = mode;	       /* issue mode byte              */


	displacement = (short)real_addr & 0x000007ff;
	len = (r->dm_length) - 1;
	if (len <= 0) {
		r->dm_error = -1;
		printf(" length is <= 0  \n");
		return (-1);
	}
	;


	*ctl1_ff = 0;		       /* clear first last flip/flop   */
	/* base, low order byte first   */
	*(char *)(CTL1_BASE + 2 * ch) = displacement;
	*(char *)(CTL1_BASE + 2 * ch) = displacement >> 8;

#ifdef TEST1
	printf(" base[%x]=%x high base=%x\n", CTL1_BASE + 2 * ch, (char)displacement, (char)displacement >> 8);

#endif
	*ctl1_ff = 0;		       /* count, low order byte first  */
	*(char *)(CTL1_BASE + (2 * ch) + 1) = len;
	*(char *)(CTL1_BASE + (2 * ch) + 1) = len >> 8;
#ifdef TEST1
	printf("low len[%x]= %d high len =%d \n", (CTL1_BASE + (2 * ch) + 1), (char)len, (char)len >> 8);

#endif

	/* set up corresponding TCWs */

	start_prefix = (short)(real_addr >> 11) & 0x00001fff;
	tcw_num = ((len + 1) / 2024) + 1; /* find # of tcw to set up   */
	if (displacement != 0)
		tcw_num++;
	if (tcw_num > 32) {
		r->dm_error = -1;
		printf(" more than 32 TCWs => boundary error \n");
		return (-1);
	}
	;

	/* Calculate  TCWs */


	/* write prefixes in TCWs    */
	for (i = 0; i < tcw_num; i++) {
		prefix = start_prefix + i;
		*(short *)(TCW_BASE + (2 * (chan * 64 + i))) = prefix | RSC_ACC | REAL_ACC;

#ifdef TEST1
		printf(" tcw addr=%x   ", (TCW_BASE + (2 * (chan * 64 + i))));
		printf(" tcw[ %d ]=%x  ", i, prefix | RSC_ACC | REAL_ACC);
		printf(" read tcw=%x", *(short *)(TCW_BASE + (2 * (chan * 64 + i))));

#endif
	}
/*          *ctl1_cmd= 0x20;               /* enable 8237  */

	return (0);		       /* everything is ok */
}


int dma_start(channel)
	int channel;
{
	char ch;

	ch = dm_softc[channel].subchannel;
	/* enable specific channel */
	*ctl1_smask = ch;
	return;
}


dma_init()
{

/*
initialize per channel data structure. Take care of 8237 subchannel
assignement (weird assignment).
note that 16 bit support is not included .
*/
	static int sub_chan[9] = {
		2, 1, 0, 3, 255, 5, 6, 7, 8
	};
	int i;

#ifdef TEST1
	printf("dma_init() entered\n");
#endif
	for (i = 0; i < 4; i++) {
		dm_softc[i].subchannel = sub_chan[i];
		dm_softc[i].busy = 0;  /* mark them not busy */
		*ctl1_smask = 0x4 | i; /* mask 8237 */
		*ctl1_req = i;	       /* disable software dma request  */
	}
	*crrb = (*crrb) | CTL1_ENABLE | 0x20; /* arbitrer enable */
	*ctl1_cmd = 0x20;	       /* enable 8237  */
	return;

}


/*  This routine will be called from the requesting device interrupt handler*/

dma_done(channel)
	int channel;
{

	char ch;
	char status;
	ch = dm_softc[channel].subchannel;
	/* disable specific channel */
	status = *ctl1_cmd;
#ifdef TEST1
	printf(" 8237 status reg =%x \n", status);
#endif
	*ctl1_smask = 0x4 | ch;


}


ctl2_setup()
{
/* not implemented yet */
}


copro_setup()
{
/* not implemented yet */
}


;
