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

📄 8253xutl.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 3 页
字号:
/* -*- linux-c -*- *//* $Id: 8253xutl.c,v 1.3 2002/02/10 22:17:26 martillo Exp $ * 8253xutl.c: SYNC TTY Driver for the SIEMENS SAB8253X DUSCC. * * Implementation, 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 "8253xctl.h"#include "8253x.h"#include <linux/pci.h>#include <linux/fs.h>#include "sp502.h"#ifdef MODULE#undef XCONFIG_SERIAL_CONSOLE#endifvoid sab8253x_start_txS(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; /* a little gross tty flags whether					       invoked from a tty or the network */		fifospace = port->xmit_fifo_size; /* This code can handle fragmented frames					     although currently none are generated*/	loadedcount = 0;		if(port->sabnext2.transmit == NULL)	{		return;	}		save_flags(flags); 	cli();						if(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 the crc/trailer */		}				if(tty && (tty->stopped || tty->hw_stopped) && (count == total))		{			/* 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(tty && (totaltransmit < (sab8253xs_listsize/2))) /* only makes sense on a TTY */			{				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;*/			/* Here to make mods to handle arbitrarily fragmented frames look to 8253xtty.c for help */						if ((count <= 0) && (port->sabnext2.transmit->sendcrc == 0))			{				port->sabnext2.transmit->Count = OWN_DRIVER;				if(!tty)				{		/* called by network driver */					++(port->Counters.transmitpacket);				}#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				sab8253x_cec_wait(port);				WRITEB(port, cmdr, SAB82532_CMDR_XME|SAB82532_CMDR_XTF); /* Terminate the frame */								port->sabnext2.transmit = port->sabnext2.transmit->VNext;								if(!tty && port->tx_full)	/* invoked from the network driver */				{					port->tx_full = 0; /* there is a free slot */					switch(port->open_type)					{					case OPEN_SYNC_NET:#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)						port->dev->start = 1;						port->dev->tbusy = 0;	/* maybe need mark_bh here */#else						netif_start_queue(port->dev);#endif						break;											case OPEN_SYNC_CHAR:						wake_up_interruptible(&port->write_wait);						break;											default:						break;					}				}								if((port->sabnext2.transmit->Count & OWNER) == OWN_SAB)				{		/* new frame to send */					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);					if((port->open_type == OPEN_SYNC_CHAR) && port->async_queue)					{		/* if indication of transmission is needed by the */						/* application on a per-frame basis kill_fasync */						/* can provide it */						kill_fasync(&port->async_queue, SIGIO, POLL_OUT);					}				}				restore_flags(flags);				return;			}			/* Issue a Transmit FIFO command. */			sab8253x_cec_wait(port);			WRITEB(port, cmdr, SAB82532_CMDR_XTF);				port->sabnext2.transmit->Count = (count|OWN_SAB);		}		port->interrupt_mask1 &= ~(SAB82532_IMR1_XPR); /* more to send */		WRITEB(port, imr1, port->interrupt_mask1);	}	else	{				/* nothing to send */		port->interrupt_mask1 |= SAB82532_IMR1_XPR;		WRITEB(port, imr1, port->interrupt_mask1);	}	restore_flags(flags);	return;}void sab8253x_transmit_charsS(struct sab_port *port,			      union sab8253x_irq_status *stat){	if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) 	{		port->interrupt_mask1 |= SAB82532_IMR1_ALLS;		WRITEB(port, imr1, port->interrupt_mask1);		port->all_sent = 1;	}	sab8253x_start_txS(port);}/* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. *//*************************************************************************** * sab_baudenh:      Function to compute the "enhanced" baudrate. *                 * *     Parameters   :  *                  encbaud  2* the baudrate. We use the *                           double value so as to support 134.5 (in only) *                  clkspeed The board clock speed in Hz. *                  bgr      Value of reg BGR for baudrate(output) *                  ccr2     Value of reg // CCR2 for baudrate (output) *                  ccr4     Value of reg CCR4 for baudrate (output) *                  truebaud The actual baudrate achieved (output). * * *     Return value : Return FALSE the parameters could not be computed,  * *     Prerequisite : The various ports must have been initialized * *     Remark       : Stolen from the Aurora ase driver. * *     Author       : fw * *     Revision     : Oct 9 2000, creation ***************************************************************************//* * Macro to check to see if the high n bits of the given unsigned long *  are zero. */               #define HIZERO(x, n)        ( ((unsigned long) ((x) << (n)) >> (n)) == (x))/* form an n-bit bitmask */#define NBM(n)                  (~(((~(unsigned long) 0) >> (n)) << (n)))/* shift x by y bits to right, rounded */#define ROUND_SHIFT(x, y)       (((unsigned long) (x) + (NBM(y - 1) + 1)) >> (y))/* perform rounded division */#define ROUND_DIV(x, y) (((x) + ((y) >> 1)) / (y))#define ABSDIF(x, y)    ((x) > (y) ? ((x) - (y)) : ((y) - (x))) static unsigned intsab8253x_baudenh(unsigned long encbaud, unsigned long clk_speed,		 unsigned char *bgr, unsigned char *ccr2,		 unsigned long *truebaudp){	register unsigned short	 tmp;	register unsigned char	 ccr2tmp;	unsigned long		 power2, mant;	unsigned int			 fastclock;		if (encbaud == 0) {		return FALSE;	}		/*	 * Keep dividing quotien by two until it is between the value of 1 and 64,	 *  inclusive.	 */		fastclock = (clk_speed >= 10000000);	/* >= 10 MHz */		for (power2 = 0; power2 < 16; power2++) 	{		/* divisor = baud * 2^M * 16 */		if (!HIZERO(encbaud, power2 + 3)) 		{			if (!HIZERO(encbaud, power2)) 			{	/* baud rate still too big? */				mant = ROUND_DIV(ROUND_SHIFT(clk_speed, power2 + 3), encbaud);								/* mant = (clk_speed / (8 * 2^M)) / (baud * 2) */				/*	= clk_speed / (baud * 16 * 2^M) */			}			else 			{				mant = ROUND_DIV(ROUND_SHIFT(clk_speed, 3), encbaud << power2);				/* mant = (clk_speed / 8) / (baud * 2 * 2^M) */				/*	= clk_speed / (baud * 16 * 2^M) */			}		}		else 		{			mant = ROUND_DIV(clk_speed, encbaud << (power2 + 3));			/* mant = clk_speed / (baud * 2 * 8 * 2^M) */			/*	    = clk_speed / (baud * 16 * 2^M) */		}				/* mant = clk_speed / (baud * 2^M * 16) */				if (mant < 2		    || (mant <= 64 && (!fastclock || power2 != 0))) 		{			break;		}	}		/*	 * Did we not succeed?  (Baud rate is too small)	 */	if (mant > 64) 	{		return FALSE;	}		/*	 * Now, calculate the true baud rate.	 */		if (mant < 1 || (mant == 1 && power2 == 0)) 	{		/* bgr and ccr2 should be initialized to 0 */		*truebaudp = ROUND_SHIFT(clk_speed, 4);	}	else 	{		*truebaudp = ROUND_DIV(clk_speed, mant << (4 + power2));		/* divisor is not zero because mant is [1, 64] */		mant--; /* now [0, 63] */				/*		 * Encode the N and M values into the bgr and ccr2 registers.		 */				tmp = ((unsigned short) mant) | ((unsigned short) power2 << 6);				ccr2tmp = SAB82532_CCR2_BDF;		if ((tmp & 0x200) != 0) 		{			ccr2tmp |= SAB82532_CCR2_BR9;		}		if ((tmp & 0x100) != 0) 		{			ccr2tmp |= SAB82532_CCR2_BR8;		}				*ccr2 = ccr2tmp | (*ccr2 & ~(SAB82532_CCR2_BDF|SAB82532_CCR2_BR8|SAB82532_CCR2_BR9));		*bgr = (unsigned char) tmp;	}		return TRUE;}/* * Calculate the standard mode baud divisor using an integral algorithm. *//*************************************************************************** * sab_baudstd:      Function to compute the "standard " baudrate. *                 * *     Parameters   :  *                  encbaud  2* the baudrate. We use the *                           double value so as to support 134.5 (in only) *                  clkspeed The board clock speed in Hz. *                  bgr      Value of reg BGR for baudrate(output) *                  ccr2     Value of reg CCR2 for baudrate (output) *                  ccr4     Value of reg CCR4 for baudrate (output) *                  truebaud The actual baudrate achieved (output). * * *     Return value : Return FALSE the parameters could not be computed,  * *     Prerequisite : The various ports must have been initialized * *     Remark       : Stolen from the Aurora ase driver. * *     Author       : fw * *     Revision     : Oct 9 2000, creation ***************************************************************************/static unsigned intsab8253x_baudstd(unsigned long encbaud, unsigned long clk_speed,		 unsigned char *bgr, unsigned char *ccr2,		 unsigned long *truebaudp){  register unsigned short	 quot;  register unsigned char	 ccr2tmp;    if (encbaud == 0)   {	  return FALSE;  }    /*   * This divisor algorithm is a little strange.  The   *  divisors are all multiples of 2, except for the   *  magic value of 1.   *   * What we do is do most of the algorithm for multiples   *  of 1, and then switch at the last minute to multiples   *  of 2.   */    /*   * Will we lose any information by left shifting encbaud?   *  If so, then right shift clk_speed instead.   */  if (!HIZERO(encbaud, 3))   {	  quot = (unsigned short) ROUND_DIV(ROUND_SHIFT(clk_speed, 3),					    encbaud);	  /* quot = (clk_speed / 8) / (baud * 2) = clk_speed / (16 * baud) */  }  else   {	  /* encbaud isn't a multiple of 2^29 (baud not mult. of 2^28) */	  quot = (unsigned short) ROUND_DIV(clk_speed, encbaud << 3);  }    /* quot = clk_speed / (baud * 16) */  if (quot < 2)   {	  /* bgr and ccr2 should be initialized to 0 */	  *truebaudp = ROUND_SHIFT(clk_speed, 4);	  return TRUE;  }    /*   * Divide the quotient by two.   */  quot = ROUND_SHIFT(quot, 1);

⌨️ 快捷键说明

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