⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 zs.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * decserial.c: Serial port driver for IOASIC DECstations. * * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras. * Derived from drivers/macintosh/macserial.c by Harald Koerfgen. * * DECstation changes * Copyright (C) 1998-2000 Harald Koerfgen * Copyright (C) 2000,2001 Maciej W. Rozycki <macro@ds2.pg.gda.pl> * * For the rest of the code the original Copyright applies: * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au) * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * * * Note: for IOASIC systems the wiring is as follows: * * mouse/keyboard: * DIN-7 MJ-4  signal        SCC * 2     1     TxD       <-  A.TxD * 3     4     RxD       ->  A.RxD * * EIA-232/EIA-423: * DB-25 MMJ-6 signal        SCC * 2     2     TxD       <-  B.TxD * 3     5     RxD       ->  B.RxD * 4           RTS       <- ~A.RTS * 5           CTS       -> ~B.CTS * 6     6     DSR       -> ~A.SYNC * 8           CD        -> ~B.DCD * 12          DSRS(DCE) -> ~A.CTS  (*) * 15          TxC       ->  B.TxC * 17          RxC       ->  B.RxC * 20    1     DTR       <- ~A.DTR * 22          RI        -> ~A.DCD * 23          DSRS(DTE) <- ~B.RTS * * (*) EIA-232 defines the signal at this pin to be SCD, while DSRS(DCE) *     is shared with DSRS(DTE) at pin 23. */#include <linux/config.h>#include <linux/version.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/interrupt.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/major.h>#include <linux/string.h>#include <linux/fcntl.h>#include <linux/mm.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/ioport.h>#ifdef CONFIG_SERIAL_CONSOLE#include <linux/console.h>#endif#include <asm/io.h>#include <asm/pgtable.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/segment.h>#include <asm/bitops.h>#include <asm/uaccess.h>#include <asm/wbflush.h>#include <asm/bootinfo.h>#ifdef CONFIG_DECSTATION#include <asm/dec/interrupts.h>#include <asm/dec/machtype.h>#include <asm/dec/tc.h>#include <asm/dec/ioasic_addrs.h>#endif#ifdef CONFIG_BAGET_MIPS#include <asm/baget/baget.h>unsigned long system_base;#endif#ifdef CONFIG_KGDB#include <asm/kgdb.h>#endif#ifdef CONFIG_MAGIC_SYSRQ#include <linux/sysrq.h>#endif#include "zs.h"/* * It would be nice to dynamically allocate everything that * depends on NUM_SERIAL, so we could support any number of * Z8530s, but for now... */#define NUM_SERIAL	2		/* Max number of ZS chips supported */#define NUM_CHANNELS	(NUM_SERIAL * 2)	/* 2 channels per chip */#define CHANNEL_A_NR  (zs_parms->channel_a_offset > zs_parms->channel_b_offset)                                        /* Number of channel A in the chip */ #define ZS_CHAN_IO_SIZE 8#define ZS_CLOCK        7372800 	/* Z8530 RTxC input clock rate */#define RECOVERY_DELAY  udelay(2)struct zs_parms {	unsigned long scc0;	unsigned long scc1;	int channel_a_offset;	int channel_b_offset;	int irq;	int clock;};static struct zs_parms *zs_parms;#ifdef CONFIG_DECSTATIONstatic struct zs_parms ds_parms = {	scc0 : SCC0,	scc1 : SCC1,	channel_a_offset : 1,	channel_b_offset : 9,	irq : SERIAL,	clock : ZS_CLOCK};#endif#ifdef CONFIG_BAGET_MIPSstatic struct zs_parms baget_parms = {	scc0 : UNI_SCC0,	scc1 : UNI_SCC1,	channel_a_offset : 9,	channel_b_offset : 1,	irq : BAGET_SCC_IRQ,	clock : 14745000};#endif#ifdef CONFIG_DECSTATION#define DS_BUS_PRESENT (IOASIC)#else#define DS_BUS_PRESENT 0#endif#ifdef CONFIG_BAGET_MIPS#define BAGET_BUS_PRESENT (mips_machtype == MACH_BAGET202)#else#define BAGET_BUS_PRESENT 0#endif#define BUS_PRESENT (DS_BUS_PRESENT || BAGET_BUS_PRESENT)struct dec_zschannel zs_channels[NUM_CHANNELS];struct dec_serial zs_soft[NUM_CHANNELS];int zs_channels_found;struct dec_serial *zs_chain;	/* list of all channels */struct tty_struct zs_ttys[NUM_CHANNELS];#ifdef CONFIG_SERIAL_CONSOLEstatic struct console sercons;#endif#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) \    && !defined(MODULE)static unsigned long break_pressed; /* break, really ... */#endifstatic unsigned char zs_init_regs[16] __initdata = {	0,                           /* write 0 */	0,			     /* write 1 */	0xf0,                        /* write 2 */	(Rx8),                       /* write 3 */	(X16CLK | SB1),              /* write 4 */	(Tx8),                       /* write 5 */	0, 0, 0,                     /* write 6, 7, 8 */	(VIS),                       /* write 9 */	(NRZ),                       /* write 10 */	(TCBR | RCBR),               /* write 11 */	0, 0,                        /* BRG time constant, write 12 + 13 */	(BRSRC | BRENABL),           /* write 14 */	0 			     /* write 15 */};DECLARE_TASK_QUEUE(tq_zs_serial);struct tty_driver serial_driver, callout_driver;static int serial_refcount;/* serial subtype definitions */#define SERIAL_TYPE_NORMAL	1#define SERIAL_TYPE_CALLOUT	2/* number of characters left in xmit buffer before we ask for more */#define WAKEUP_CHARS 256/* * Debugging. */#undef SERIAL_DEBUG_INTR#undef SERIAL_DEBUG_OPEN#undef SERIAL_DEBUG_FLOW#undef SERIAL_DEBUG_THROTTLE#undef SERIAL_PARANOIA_CHECK#undef ZS_DEBUG_REGS#ifdef SERIAL_DEBUG_THROTTLE#define _tty_name(tty,buf) tty_name(tty,buf)#endif#define RS_STROBE_TIME 10#define RS_ISR_PASS_LIMIT 256#define _INLINE_ inlinestatic void probe_sccs(void);static void change_speed(struct dec_serial *info);static void rs_wait_until_sent(struct tty_struct *tty, int timeout);static struct tty_struct *serial_table[NUM_CHANNELS];static struct termios *serial_termios[NUM_CHANNELS];static struct termios *serial_termios_locked[NUM_CHANNELS];#ifndef MIN#define MIN(a,b)	((a) < (b) ? (a) : (b))#endif/* * tmp_buf is used as a temporary buffer by serial_write.  We need to * lock it in case the copy_from_user blocks while swapping in a page, * and some other program tries to do a serial write at the same time. * Since the lock will only come under contention when the system is * swapping and available memory is low, it makes sense to share one * buffer across all the serial ports, since it significantly saves * memory if large numbers of serial ports are open. */static unsigned char tmp_buf[4096]; /* This is cheating */static DECLARE_MUTEX(tmp_buf_sem);static inline int serial_paranoia_check(struct dec_serial *info,					dev_t device, const char *routine){#ifdef SERIAL_PARANOIA_CHECK	static const char *badmagic =		"Warning: bad magic number for serial struct (%d, %d) in %s\n";	static const char *badinfo =		"Warning: null mac_serial for (%d, %d) in %s\n";	if (!info) {		printk(badinfo, MAJOR(device), MINOR(device), routine);		return 1;	}	if (info->magic != SERIAL_MAGIC) {		printk(badmagic, MAJOR(device), MINOR(device), routine);		return 1;	}#endif	return 0;}/* * This is used to figure out the divisor speeds and the timeouts */static int baud_table[] = {	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,	9600, 19200, 38400, 57600, 115200, 0 };/*  * Reading and writing Z8530 registers. */static inline unsigned char read_zsreg(struct dec_zschannel *channel,				       unsigned char reg){	unsigned char retval;	if (reg != 0) {		*channel->control = reg & 0xf;		wbflush(); RECOVERY_DELAY;	}	retval = *channel->control;	RECOVERY_DELAY;	return retval;}static inline void write_zsreg(struct dec_zschannel *channel,			       unsigned char reg, unsigned char value){	if (reg != 0) {		*channel->control = reg & 0xf;		wbflush(); RECOVERY_DELAY;	}	*channel->control = value;	wbflush(); RECOVERY_DELAY;	return;}static inline unsigned char read_zsdata(struct dec_zschannel *channel){	unsigned char retval;	retval = *channel->data;	RECOVERY_DELAY;	return retval;}static inline void write_zsdata(struct dec_zschannel *channel,				unsigned char value){	*channel->data = value;	wbflush(); RECOVERY_DELAY;	return;}static inline void load_zsregs(struct dec_zschannel *channel,			       unsigned char *regs){/*	ZS_CLEARERR(channel);	ZS_CLEARFIFO(channel); */	/* Load 'em up */	write_zsreg(channel, R4, regs[R4]);	write_zsreg(channel, R3, regs[R3] & ~RxENABLE);	write_zsreg(channel, R5, regs[R5] & ~TxENAB);	write_zsreg(channel, R9, regs[R9]);	write_zsreg(channel, R1, regs[R1]);	write_zsreg(channel, R2, regs[R2]);	write_zsreg(channel, R10, regs[R10]);	write_zsreg(channel, R11, regs[R11]);	write_zsreg(channel, R12, regs[R12]);	write_zsreg(channel, R13, regs[R13]);	write_zsreg(channel, R14, regs[R14]);	write_zsreg(channel, R15, regs[R15]);	write_zsreg(channel, R3, regs[R3]);	write_zsreg(channel, R5, regs[R5]);	return;}/* Sets or clears DTR/RTS on the requested line */static inline void zs_rtsdtr(struct dec_serial *info, int which, int set){        unsigned long flags;	save_flags(flags); cli();	if (info->zs_channel != info->zs_chan_a) {		if (set) {			info->zs_chan_a->curregs[5] |= (which & (RTS | DTR));		} else {			info->zs_chan_a->curregs[5] &= ~(which & (RTS | DTR));		}		write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);	}	restore_flags(flags);}/* Utility routines for the Zilog */static inline int get_zsbaud(struct dec_serial *ss){	struct dec_zschannel *channel = ss->zs_channel;	int brg;	/* The baud rate is split up between two 8-bit registers in	 * what is termed 'BRG time constant' format in my docs for	 * the chip, it is a function of the clk rate the chip is	 * receiving which happens to be constant.	 */	brg = (read_zsreg(channel, 13) << 8);	brg |= read_zsreg(channel, 12);	return BRG_TO_BPS(brg, (zs_parms->clock/(ss->clk_divisor)));}/* On receive, this clears errors and the receiver interrupts */static inline void rs_recv_clear(struct dec_zschannel *zsc){	write_zsreg(zsc, 0, ERR_RES);	write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */}/* * ---------------------------------------------------------------------- * * Here starts the interrupt handling routines.  All of the following * subroutines are declared as inline and are folded into * rs_interrupt().  They were separated out for readability's sake. * * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93 * ----------------------------------------------------------------------- */static int tty_break;	/* Set whenever BREAK condition is detected.  *//* * This routine is used by the interrupt handler to schedule * processing in the software interrupt portion of the driver. */static _INLINE_ void rs_sched_event(struct dec_serial *info,				  int event){	info->event |= 1 << event;	queue_task(&info->tqueue, &tq_zs_serial);	mark_bh(SERIAL_BH);}static _INLINE_ void receive_chars(struct dec_serial *info,				   struct pt_regs *regs){	struct tty_struct *tty = info->tty;	unsigned char ch, stat, flag;	while ((read_zsreg(info->zs_channel, R0) & Rx_CH_AV) != 0) {		stat = read_zsreg(info->zs_channel, R1);		ch = read_zsdata(info->zs_channel);		if (!tty && !info->hook && !info->hook->rx_char)			continue;		if (tty_break) {			tty_break = 0;#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE)			if (info->line == sercons.index) {				if (!break_pressed) {					break_pressed = jiffies;					goto ignore_char;				}				break_pressed = 0;			}#endif			flag = TTY_BREAK;			if (info->flags & ZILOG_SAK)				do_SAK(tty);		} else {			if (stat & Rx_OVR) {				flag = TTY_OVERRUN;			} else if (stat & FRM_ERR) {				flag = TTY_FRAME;			} else if (stat & PAR_ERR) {				flag = TTY_PARITY;			} else				flag = 0;			if (flag)				/* reset the error indication */				write_zsreg(info->zs_channel, R0, ERR_RES);		}#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE)		if (break_pressed && info->line == sercons.index) {			if (ch != 0 &&			    time_before(jiffies, break_pressed + HZ*5)) {				handle_sysrq(ch, regs, NULL, NULL);				break_pressed = 0;				goto ignore_char;			}			break_pressed = 0;		}#endif		if (info->hook && info->hook->rx_char) {			(*info->hook->rx_char)(ch, flag);			return;  		}				if (tty->flip.count >= TTY_FLIPBUF_SIZE) {			static int flip_buf_ovf;			++flip_buf_ovf;			continue;		}		tty->flip.count++;		{			static int flip_max_cnt;			if (flip_max_cnt < tty->flip.count)				flip_max_cnt = tty->flip.count;		}		*tty->flip.flag_buf_ptr++ = flag;		*tty->flip.char_buf_ptr++ = ch;	ignore_char:	}	if (tty)		tty_flip_buffer_push(tty);}static void transmit_chars(struct dec_serial *info){	if ((read_zsreg(info->zs_channel, R0) & Tx_BUF_EMP) == 0)		return;	info->tx_active = 0;	if (info->x_char) {		/* Send next char */		write_zsdata(info->zs_channel, info->x_char);		info->x_char = 0;		info->tx_active = 1;		return;	}	if ((info->xmit_cnt <= 0) || (info->tty && info->tty->stopped)	    || info->tx_stopped) {		write_zsreg(info->zs_channel, R0, RES_Tx_P);		return;	}	/* Send char */	write_zsdata(info->zs_channel, info->xmit_buf[info->xmit_tail++]);	info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);	info->xmit_cnt--;	info->tx_active = 1;	if (info->xmit_cnt < WAKEUP_CHARS)		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);}static _INLINE_ void status_handle(struct dec_serial *info){	unsigned char stat;	/* Get status from Read Register 0 */	stat = read_zsreg(info->zs_channel, R0);	if (stat & BRK_ABRT) {#ifdef SERIAL_DEBUG_INTR		printk("handling break....");#endif		tty_break = 1;	}	if (info->zs_channel != info->zs_chan_a) {		/* FIXEM: Check for DCD transitions */		if (((stat ^ info->read_reg_zero) & DCD) != 0		    && info->tty && !C_CLOCAL(info->tty)) {			if (stat & DCD) {				wake_up_interruptible(&info->open_wait);			} else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) {				tty_hangup(info->tty);			}		}		/* Check for CTS transitions */		if (info->tty && C_CRTSCTS(info->tty)) {			if ((stat & CTS) != 0) {				if (info->tx_stopped) {					info->tx_stopped = 0;					if (!info->tx_active)						transmit_chars(info);				}			} else {				info->tx_stopped = 1;			}		}	}	/* Clear status condition... */	write_zsreg(info->zs_channel, R0, RES_EXT_INT);	info->read_reg_zero = stat;}/* * This is the serial driver's generic interrupt routine */void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs){	struct dec_serial *info = (struct dec_serial *) dev_id;	unsigned char zs_intreg;	int shift;	/* NOTE: The read register 3, which holds the irq status,	 *       does so for both channels on each chip.  Although	 *       the status value itself must be read from the A	 *       channel and is only valid when read from channel A.	 *       Yes... broken hardware...	 */#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)	if (info->zs_chan_a == info->zs_channel)		shift = 3;	/* Channel A */	else		shift = 0;	/* Channel B */	for (;;) {		zs_intreg = read_zsreg(info->zs_chan_a, R3) >> shift; 		if ((zs_intreg & CHAN_IRQMASK) == 0)			break;		if (zs_intreg & CHBRxIP) {			receive_chars(info, regs);		}		if (zs_intreg & CHBTxIP) {			transmit_chars(info);		}		if (zs_intreg & CHBEXT) {			status_handle(info);		}	}		/* Why do we need this ? */	write_zsreg(info->zs_channel, 0, RES_H_IUS);}#ifdef ZS_DEBUG_REGSvoid zs_dump (void) {	int i, j;	for (i = 0; i < zs_channels_found; i++) {		struct dec_zschannel *ch = &zs_channels[i]; 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -