|
|
Atari coding BBS
Zilog Falcon |
Posted by: earx
|
Sep,05.2006-09:02
|
*
* Zilog 85X30 serial driver for RTLinux
* (asynchronous and synchronous modes)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* This is based on drivers/serial/sunzilog.c by David S. Miller, itself
* which is based on the old drivers/sbus/char/zs.c code. A lot
* of code has been simply moved over directly from there but
* much has been rewritten. Credits therefore go out to Eddie
* C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their
* work there.
* And it is not all, it is also based on the rt_com driver from Jens Michaelsen,
* Jochen Küpper, Hua Mao and Roberto Finazzi.
*
* Copyright (C) 2004-2005 Marc Le Douarain
*/
#include <rtl.h>
#include <rtl_sched.h>
#include <asm/io.h>
#include <linux/ioport.h>
#include "rt_com_zilog.h"
#include "zilog_and_com.h"
#define RTCZ_NAME "rt_com_zilog"
#define RTCZ_VERSION "0.2.2"
// I/O ports with D/C pin low
#define Z_PORT_B_CONTROL 0x210
#define Z_PORT_A_CONTROL 0x211
// I/O ports with D/C pin high
#define Z_PORT_B_DATA 0x212
#define Z_PORT_A_DATA 0x213
/* if we want to share the irq handler of "rt_com" or not... */
#define USE_OWN_IRQ_HANDLER
#define Z_IRQ 12
#define ZS_CLOCK 15974400l /* Zilog input clock rate. */
#define ZS_CLOCK_DIVISOR 16 /* Default divisor this driver uses (for asynchronous). */
#define RT_COM_ZILOG_CNT 2
static struct rt_com_zilog_struct rt_com_table[ RT_COM_ZILOG_CNT ] =
{
{ Z_PORT_A_CONTROL, Z_PORT_A_DATA },
{ Z_PORT_B_CONTROL, Z_PORT_B_DATA }
};
/* global variable to know if driver init is ok. */
int rt_com_zilog_driver_init_error = 0;
static int debugIT = 0;
//freeze if a lot of tasks already switching fastly...
//#define ZSDELAY() nanosleep( hrt2ts( 5000 ), NULL );
//seems that no delay is required with our ISA bus?
#define ZSDELAY()
/* Reading and writing Zilog8530 registers. The delays are to make this
* driver work on the Sun4 which needs a settling delay after each chip
* register access, other machines handle this in hardware via auxiliary
* flip-flops which implement the settle time we do in software.
*
* The port lock must be held and local IRQs must be disabled
* when {read,write}_zsreg is invoked.
*/
static inline unsigned char read_zsreg(struct rt_com_zilog_struct *channel,
unsigned char reg)
{
unsigned char retval;
outb(reg, channel->control);
ZSDELAY();
retval = inb(channel->control);
ZSDELAY();
return retval;
}
static inline void write_zsreg(struct rt_com_zilog_struct *channel,
unsigned char reg, unsigned char value)
{
outb(reg, channel->control);
ZSDELAY();
outb(value, channel->control);
ZSDELAY();
}
static inline int sbus_readb( int * p)
{
return inb(*p);
}
static inline void sbus_writeb( int d, int * p)
{
outb(d,*p);
}
#define ZS_WSYNC(__channel) sbus_readb(&((__channel)->control))
static void sunzilog_clear_fifo(struct rt_com_zilog_struct *channel)
{
int i;
for (i = 0; i < 32; i++) {
unsigned char regval;
regval = sbus_readb(&channel->control);
ZSDELAY();
//v0.2.0 if (regval & Rx_CH_AV)
if (!(regval & Rx_CH_AV))
break;
regval = read_zsreg(channel, R1);
sbus_readb(&channel->data);
ZSDELAY();
if (regval & (PAR_ERR | Rx_OVR | CRC_ERR)) {
sbus_writeb(ERR_RES, &channel->control);
ZSDELAY();
ZS_WSYNC(channel);
}
}
}
/* This function must only be called when the TX is not busy. The UART
* port lock must be held and local interrupts disabled.
*/
static void __load_zsregs(struct rt_com_zilog_struct *channel)
{
int i;
unsigned char *regs = channel->curregs;
/* Let pending transmits finish. */
for (i = 0; i < 1000; i++) {
unsigned char stat = read_zsreg(channel, R1);
if (stat & ALL_SNT)
break;
udelay(100);
}
sbus_writeb(ERR_RES, &channel->control);
ZSDELAY();
ZS_WSYNC(channel);
sunzilog_clear_fifo(channel);
/* Disable all interrupts. */
write_zsreg(channel, R1,
regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB));
/* Set parity, sync config, stop bits, and clock divisor. */
write_zsreg(channel, R4, regs[R4]);
//rtl_printf("Init: Write R4=%x\n", regs[R4]);
/* Set TX/RX controls sans the enable bits. */
write_zsreg(channel, R3, regs[R3] & ~RxENAB);
write_zsreg(channel, R5, regs[R5] & ~TxENAB);
//rtl_printf("Init: Write R3=%x R5=%x R10=%x\n", regs[R3], regs[R5], regs[R10]);
/* Set Rx FIFO interrupt level now for ESCC (old chip will write normal R7) */
/* R7' is seen with R7 and the bit PRIME of R15 */
write_zsreg(channel, R15, regs[R15]|PRIME);
write_zsreg(channel, R7, regs[R7P]);
write_zsreg(channel, R15, regs[R15]);
//rtl_printf("Init: Write R7Prime=%x\n", regs[R7P]);
/* Synchronous mode config. */
write_zsreg(channel, R6, regs[R6]);
write_zsreg(channel, R7, regs[R7]);
/* Set misc. TX/RX control bits. */
write_zsreg(channel, R10, regs[R10]);
/* Don't mess with the interrupt vector (R2, unused by us) and
* master interrupt control (R9). We make sure this is setup
* properly at probe time then never touch it again.
*/
/* Disable baud generator. */
write_zsreg(channel, R14, regs[R14] & ~BRENAB);
/* Clock mode control. */
write_zsreg(channel, R11, regs[R11]);
//rtl_printf("Init: Write R11=%x\n", regs[R11]);
/* Lower and upper byte of baud rate generator divisor. */
write_zsreg(channel, R12, regs[R12]);
write_zsreg(channel, R13, regs[R13]);
//rtl_printf( "Init: Write R12=%x then Read R12=%x\n", regs[R12], read_zsreg( channel, R12 ) );
//rtl_printf( "Init: Write R13=%x then Read R13=%x\n", regs[R13], read_zsreg( channel, R13 ) );
/* Now rewrite R14, with BRENAB (if set). */
write_zsreg(channel, R14, regs[R14]);
//rtl_printf("Init: Write R14=%x\n", regs[R14]);
/* External status interrupt control. */
write_zsreg(channel, R15, regs[R15]);
//rtl_printf("Init: Write R15=%x\n", regs[R15]);
/* Reset external status interrupts. */
write_zsreg(channel, R0, RES_EXT_INT);
write_zsreg(channel, R0, RES_EXT_INT);
/* Rewrite R3/R5, this time without enables masked. */
write_zsreg(channel, R3, regs[R3]);
write_zsreg(channel, R5, regs[R5]);
//rtl_printf("Init: Write R3=%x R5=%x R10=%x\n", regs[R3], regs[R5], regs[R10]);
/* Rewrite R1, this time without IRQ enabled masked. */
write_zsreg(channel, R1, regs[R1]);
//rtl_printf("Init: Write R1=%x\n", regs[R1]);
}
/* Reprogram the Zilog channel HW registers with the copies found in the
* software state struct. If the transmitter is busy, we defer this update
* until the next TX complete interrupt. Else, we do it right now.
*
* The UART port lock must be held and local interrupts disabled.
*/
static void sunzilog_maybe_update_regs(struct rt_com_zilog_struct *channel)
{
// if (!ZS_REGS_HELD(up)) {
// if (ZS_TX_ACTIVE(up)) {
// up->flags |= SUNZILOG_FLAG_REGS_HELD;
// } else {
__load_zsregs(channel);
// }
// }
}
/** Get first byte from the write buffer.
*
* @param p rt_com_struct of the line we are writing to.
* @param c Address to put the char in.
* @return Number of characters we actually got.
*
* @author Jens Michaelsen, Jochen Küpper
* @version 1999/10/01 */
static inline int rt_com_irq_get( struct rt_com_zilog_struct *p, unsigned char *c )
{
struct rt_buf_struct *b = &( p->obuf );
if( b->head != b->tail ) {
*c = b->buf[ b->tail++ ];
b->tail &= ( RT_COM_BUF_SIZ - 1 );
return( 1 );
}
return( 0 );
}
/** Concatenate a byte to the read buffer.
*
* @param p rt_com_struct of the line we are writing to.
* @param ch Byte to put into buffer.
*
* @author Jens Michaelsen, Jochen Küpper
[...]
|
[All messages in this thread] [Start new thread]
What's the anti-troll code? That's your personal code to be able to add comments and messages on the dhs.nu site.
Don't have a code or forgot it? Fix it here.
|
|
|