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

📄 8253xtty.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 5 页
字号:
/* -*- linux-c -*- *//* $Id: 8253xtty.c,v 1.23 2002/02/10 22:17:25 martillo Exp $ * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. * * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be) * * Modified by Francois Wautier 2000 (fw@auroratech.com) * * Extended extensively by Joachim Martillo 2001 (Telford002@aol.com) * 	to provide synchronous/asynchronous TTY/Callout/character/network device * 	capabilities. * * Modifications and extensions * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. * * 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. *//* Standard in kernel modules */#define DEFINE_VARIABLE#include <linux/module.h>   /* Specifically, a module */#include <asm/io.h>#include <linux/timer.h>#include <linux/interrupt.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/mm.h>#include <linux/version.h>#include <asm/uaccess.h>#include <linux/pci.h>#include "8253xctl.h"#include "sp502.h"DECLARE_TASK_QUEUE(tq_8253x_serial); /* this just initializes a list head called */				     /* tq_8253x_serial*/struct tty_driver sab8253x_serial_driver, sab8253x_callout_driver, sync_sab8253x_serial_driver;int sab8253x_refcount;/* Trace things on serial device, useful for console debugging: */#undef SERIAL_LOG_DEVICE#ifdef SERIAL_LOG_DEVICEstatic void dprint_init(int tty);#endifstatic void sab8253x_change_speed(struct sab_port *port);static struct tty_struct **sab8253x_tableASY = 0;	/* make dynamic */static struct tty_struct **sab8253x_tableCUA = 0;	/* make dynamic */static struct tty_struct **sab8253x_tableSYN = 0;	/* make dynamic */static struct termios **sab8253x_termios = 0 ;static struct termios **sab8253x_termios_locked = 0;#ifdef MODULE#undef XCONFIG_SERIAL_CONSOLE	/* leaving out CONFIG_SERIAL_CONSOLE for now */#endif#ifdef XCONFIG_SERIAL_CONSOLE	/* not really implemented yet */extern int serial_console;struct console sab8253x_console;int sab8253x_console_init(void);#endif#ifndef MIN#define MIN(a,b)	((a) < (b) ? (a) : (b))#endifchar sab8253x_serial_version[16];static void sab8253x_flush_to_ldisc(void *private_){	struct tty_struct *tty = (struct tty_struct *) private_;	unsigned char	*cp;	char		*fp;	int		count;	struct sab_port *port;	struct sk_buff *skb;  		if(tty)	{		port = (struct sab_port *)tty->driver_data; /* probably a silly check */	}	else	{		return;	}		if(!port)	{		return;	}		if (test_bit(TTY_DONT_FLIP, &tty->flags)) 	{		queue_task(&tty->flip.tqueue, &tq_timer);		return;	}	/* note that a hangup may have occurred -- perhaps should check for that */	port->DoingInterrupt = 1;	while(port->sab8253xc_rcvbuflist && (skb_queue_len(port->sab8253xc_rcvbuflist) > 0))	{		skb = skb_dequeue(port->sab8253xc_rcvbuflist);		count = skb->data_len;		cp = skb->data;		fp = skb->data + (count/2);		(*tty->ldisc.receive_buf)(tty, cp, fp, count/2);		dev_kfree_skb_any(skb);	}	port->DoingInterrupt = 0;}/* only used asynchronously */static void inline sab8253x_tec_wait(struct sab_port *port){	int count = port->tec_timeout;		while((READB(port, star) & SAB82532_STAR_TEC) && --count)	{		udelay(1);	}}void sab8253x_start_tx(struct sab_port *port){	unsigned long flags;	register int count;	register int total;	register int offset;	char temporary[32];	register unsigned int slopspace;	register int sendsize;	unsigned int totaltransmit;	unsigned fifospace;	unsigned loadedcount;	struct tty_struct *tty = port->tty;		fifospace = port->xmit_fifo_size;	loadedcount = 0;		if(port->sabnext2.transmit == NULL)	{		return;	}		save_flags(flags); 	cli();						while(count = port->sabnext2.transmit->Count, (count & OWNER) == OWN_SAB)	{		count &= ~OWN_SAB; /* OWN_SAB is really 0 but cannot guarantee in the future */				if(port->sabnext2.transmit->HostVaddr)		{			total = (port->sabnext2.transmit->HostVaddr->tail - 				 port->sabnext2.transmit->HostVaddr->data); /* packet size */		}		else		{			total = 0;		/* the data is only in the crc/trailer */		}				if(tty && (tty->stopped || tty->hw_stopped))		{			/* works for frame that only has a trailer (crc) */			port->interrupt_mask1 |= SAB82532_IMR1_XPR;			WRITEB(port, imr1, port->interrupt_mask1);			restore_flags(flags);	/* can't send */			return;		}				offset = (total - count);	/* offset to data still to send */				port->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS);		WRITEB(port, imr1, port->interrupt_mask1);		port->all_sent = 0;						if(READB(port,star) & SAB82532_STAR_XFW)		{			if(count <= fifospace)			{				port->xmit_cnt = count;				slopspace = 0;				sendsize = 0;				if(port->sabnext2.transmit->sendcrc) 				/* obviously should not happen for async but might use for				   priority transmission */				{					slopspace = fifospace - count;				}				if(slopspace)				{					if(count)					{						memcpy(temporary, &port->sabnext2.transmit->HostVaddr->data[offset], 						       count);					}					sendsize = MIN(slopspace, (4 - port->sabnext2.transmit->crcindex)); 				/* how many bytes to send */					memcpy(&temporary[count], 					       &((unsigned char*)(&port->sabnext2.transmit->crc))					       [port->sabnext2.transmit->crcindex], 					       sendsize);					port->sabnext2.transmit->crcindex += sendsize;					if(port->sabnext2.transmit->crcindex >= 4)					{						port->sabnext2.transmit->sendcrc = 0;					}					port->xmit_buf = temporary;				}				else				{					port->xmit_buf =	/* set up wrifefifo variables */						&port->sabnext2.transmit->HostVaddr->data[offset];				}				port->xmit_cnt += sendsize;				count = 0;			}			else			{				count -= fifospace;				port->xmit_cnt = fifospace;				port->xmit_buf =	/* set up wrifefifo variables */					&port->sabnext2.transmit->HostVaddr->data[offset];							}			port->xmit_tail= 0;			loadedcount = port->xmit_cnt;			(*port->writefifo)(port);			totaltransmit = Sab8253xCountTransmitDescriptors(port);			if((sab8253xt_listsize - totaltransmit) > 2) 			{				sab8253x_sched_event(port, SAB8253X_EVENT_WRITE_WAKEUP);			}						if((sab8253xt_listsize - totaltransmit) > (sab8253xt_listsize/2))			{				port->buffergreedy = 0;			}			else			{				port->buffergreedy = 1;			}						port->xmit_buf = NULL; /* this var is used to indicate whether to call kfree */						fifospace -= loadedcount;						if ((count <= 0) && (port->sabnext2.transmit->sendcrc == 0))			{				port->sabnext2.transmit->Count = OWN_DRIVER;#ifdef FREEININTERRUPT		/* treat this routine as if taking place in interrupt */				if(port->sabnext2.transmit->HostVaddr)				{					skb_unlink(port->sabnext2.transmit->HostVaddr);					dev_kfree_skb_any(port->sabnext2.transmit->HostVaddr);					port->sabnext2.transmit->HostVaddr = 0; /* no skb */				}				port->sabnext2.transmit->crcindex = 0; /* no single byte */#endif				port->sabnext2.transmit = port->sabnext2.transmit->VNext;				if((port->sabnext2.transmit->Count & OWNER) == OWN_SAB)				{					if(fifospace > 0)					{						continue;	/* the only place where this code really loops */					}					if(fifospace < 0)					{						printk(KERN_ALERT "sab8253x:  bad math in interrupt handler.\n");					}					port->interrupt_mask1 &= ~(SAB82532_IMR1_XPR);					WRITEB(port, imr1, port->interrupt_mask1);				}				else				{					port->interrupt_mask1 |= SAB82532_IMR1_XPR;					WRITEB(port, imr1, port->interrupt_mask1);				}				sab8253x_cec_wait(port);				/* Issue a Transmit Frame command. */				WRITEB(port, cmdr, SAB82532_CMDR_XF); 				/* This could be optimized to load from next skbuff */				/* SAB82532_CMDR_XF is the same as SAB82532_CMDR_XTF */				restore_flags(flags);				return;			}			sab8253x_cec_wait(port);			/* Issue a Transmit Frame command. */			WRITEB(port, cmdr, SAB82532_CMDR_XF);	/* same as SAB82532_CMDR_XTF */			port->sabnext2.transmit->Count = (count|OWN_SAB);		}		port->interrupt_mask1 &= ~(SAB82532_IMR1_XPR);		WRITEB(port, imr1, port->interrupt_mask1);		restore_flags(flags);		return;	}	/*  The While loop only exits via return*/	/* we get here by skipping the loop  */	port->interrupt_mask1 |= SAB82532_IMR1_XPR;	WRITEB(port, imr1, port->interrupt_mask1);	restore_flags(flags);	return;}/* * ------------------------------------------------------------ * sab8253x_stop() and sab8253x_start() * * This routines are called before setting or resetting tty->stopped. * They enable or disable transmitter interrupts, as necessary. * ------------------------------------------------------------ */static void sab8253x_stop(struct tty_struct *tty){	struct sab_port *port = (struct sab_port *)tty->driver_data;	unsigned long flags;		if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_stop"))	{		return;	}		save_flags(flags); 	cli();	/* maybe should turn off ALLS as well		   but the stop flags are checked		   so ALLS is probably harmless		   and I have seen too much evil		   associated with that interrupt*/	port->interrupt_mask1 |= SAB82532_IMR1_XPR;	WRITEB(port, imr1, port->interrupt_mask1);	restore_flags(flags);}static void sab8253x_start(struct tty_struct *tty){	struct sab_port *port = (struct sab_port *)tty->driver_data;			if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_start"))	{		return;	}		sab8253x_start_tx(port);}/* * This routine is used by the interrupt handler to schedule * processing in the software interrupt portion of the driver. *//* no obvious changes for sync tty */static void sab8253x_receive_chars(struct sab_port *port,			    union sab8253x_irq_status *stat){	struct tty_struct *tty = port->tty;	unsigned char buf[32];	unsigned char reordered[32];	unsigned char status;	int free_fifo = 0;	int i, count = 0;	struct sk_buff *skb;		/* Read number of BYTES (Character + Status) available. */	if (stat->images[ISR0_IDX] & SAB82532_ISR0_RPF) 	{		count = port->recv_fifo_size;		free_fifo++;	}		if (stat->images[ISR0_IDX] & SAB82532_ISR0_TCD) 	{		count = READB(port,rbcl) & (port->recv_fifo_size - 1);		free_fifo++;	}		/* Issue a FIFO read command in case we where idle. */	if (stat->sreg.isr0 & SAB82532_ISR0_TIME) 	{		sab8253x_cec_wait(port);		WRITEB(port, cmdr, SAB82532_CMDR_RFRD);	}		if (stat->images[ISR0_IDX] & SAB82532_ISR0_RFO) 	{				/* FIFO overflow */		free_fifo++;	}		/* Read the FIFO. */	(*port->readfifo)(port, buf, count);		/* Issue Receive Message Complete command. */	if (free_fifo) 	{		sab8253x_cec_wait(port);		WRITEB(port, cmdr, SAB82532_CMDR_RMC);	}	#ifdef CONSOLE_SUPPORT	if (port->is_console)	{		wake_up(&keypress_wait);	}#endif	if (!tty)	{		return;	}		if(!count)	{		return;	}		for(i = 0; i < count; i += 2)	{		reordered[i/2] = buf[i];		status = buf[i+1];		if (status & SAB82532_RSTAT_PE) 		{			status = TTY_PARITY;			port->icount.parity++;		} 		else if (status & SAB82532_RSTAT_FE) 		{			status = TTY_FRAME;			port->icount.frame++;		}		else		{			status = TTY_NORMAL;		}		reordered[(count+i)/2] = status;	}		if(port->active2.receive == NULL)	{		return;	}		memcpy(port->active2.receive->HostVaddr->tail, reordered, count);	port->active2.receive->HostVaddr->tail += count;	port->active2.receive->HostVaddr->data_len = count;	port->active2.receive->HostVaddr->len = count;	if(skb = dev_alloc_skb(port->recv_fifo_size), skb == NULL) /* use dev_alloc_skb because at int								      there is header space but so what*/	{		port->icount.buf_overrun++;		port->active2.receive->HostVaddr->tail = port->active2.receive->HostVaddr->data; /* clear the buffer */		port->active2.receive->Count = (port->recv_fifo_size|OWN_SAB);		port->active2.receive->HostVaddr->data_len = 0;		port->active2.receive->HostVaddr->len = 0;	}	else	{		skb_unlink(port->active2.receive->HostVaddr);		skb_queue_tail(port->sab8253xc_rcvbuflist, port->active2.receive->HostVaddr);		skb_queue_head(port->sab8253xbuflist, skb);		port->active2.receive->HostVaddr = skb;		port->active2.receive->Count = (port->recv_fifo_size|OWN_SAB);	}	queue_task(&tty->flip.tqueue, &tq_timer);}static void sab8253x_transmit_chars(struct sab_port *port,				    union sab8253x_irq_status *stat){		if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) /* got an all sent int? */	{		port->interrupt_mask1 |= SAB82532_IMR1_ALLS;		WRITEB(port, imr1, port->interrupt_mask1);		port->all_sent = 1;	/* not much else to do */	} /* a very weird chip -- this int only indicates this int */		sab8253x_start_tx(port);}static void sab8253x_check_status(struct sab_port *port,			   union sab8253x_irq_status *stat){	struct tty_struct *tty = port->tty;	int modem_change = 0;	mctlsig_t         *sig;	struct sk_buff *skb;		if (!tty)	{		return;	}		if(port->active2.receive == NULL)	{		goto check_modem;	}		if (stat->images[ISR1_IDX] & SAB82532_ISR1_BRK) 	{#ifdef XCONFIG_SERIAL_CONSOLE		if (port->is_console) 		{			batten_down_hatches(info); /* need to add this function */			return;		}#endif 				port->active2.receive->HostVaddr->tail[0] = 0;		port->active2.receive->HostVaddr->tail[1] = TTY_PARITY;		port->active2.receive->HostVaddr->tail += 2;		port->active2.receive->HostVaddr->data_len = 2;		port->active2.receive->HostVaddr->len = 2;				if(skb = dev_alloc_skb(port->recv_fifo_size), skb == NULL)		{			port->icount.buf_overrun++;			port->active2.receive->HostVaddr->tail = port->active2.receive->HostVaddr->data; 				/* clear the buffer */			port->active2.receive->Count = (port->recv_fifo_size|OWN_SAB);			port->active2.receive->HostVaddr->data_len = 0;			port->active2.receive->HostVaddr->len = 0;		}		else

⌨️ 快捷键说明

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