Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 05 Sep 1997 18:58:11 -0700
From:      Julian Elischer <julian@whistle.com>
To:        hackers@freebsd.org
Subject:   [BDE:] sio.c proposed change. (HISPEED uarts)
Message-ID:  <3410B8B3.59E2B600@whistle.com>

next in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.

--------------FF6D5DF3F54BC7E1CFBAE39
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Bruce, (and others)

here's a version of the changes I submitted before.
I've changed it so that the stored value is the maximum
baud rate 
(the rate when the divisor == 1)
I'm still not sure that we need to limit ourselves to
the 'standard' rates via a table, so I still have not yet 
re-introduced the speed table.

As I mentionned before,
ths is relative to 2.2 and also 
brings over a few -current enhancements WRT 
the attacming of a console.

the purpose of these changes is to allow the supprt of 'overclocked'
sio ports.


thoughts?

julian

--------------FF6D5DF3F54BC7E1CFBAE39
Content-Type: text/plain; charset=us-ascii; name="xxx"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="xxx"

Index: sio.c
===================================================================
RCS file: /home/ncvs/src/sys/i386/isa/sio.c,v
retrieving revision 1.147.2.8
retrieving revision 1.147.2.8.2.2
diff -c -r1.147.2.8 -r1.147.2.8.2.2
*** sio.c	1997/05/11 12:57:38	1.147.2.8
--- sio.c	1997/09/06 01:42:37	1.147.2.8.2.2
***************
*** 31,37 ****
   * SUCH DAMAGE.
   *
   *	from: @(#)com.c	7.5 (Berkeley) 5/16/91
!  *	$Id: sio.c,v 1.147.2.8 1997/05/11 12:57:38 bde Exp $
   */
  
  #include "opt_comconsole.h"
--- 31,37 ----
   * SUCH DAMAGE.
   *
   *	from: @(#)com.c	7.5 (Berkeley) 5/16/91
!  *	$Id: sio.c,v 1.147.2.8.2.2 1997/09/06 01:42:37 julian Exp $
   */
  
  #include "opt_comconsole.h"
***************
*** 61,66 ****
--- 61,67 ----
  #include <sys/kernel.h>
  #include <sys/malloc.h>
  #include <sys/syslog.h>
+ #include <sys/sysctl.h>
  #ifdef DEVFS
  #include <sys/devfsext.h>
  #endif
***************
*** 94,99 ****
--- 95,101 ----
  #define	DEV_TO_UNIT(dev)	(MINOR_TO_UNIT(minor(dev)))
  #define	MINOR_MAGIC_MASK	(CALLOUT_MASK | CONTROL_MASK)
  #define	MINOR_TO_UNIT(mynor)	((mynor) & ~MINOR_MAGIC_MASK)
+ #define	BASIC_BAUD_MAX		115200
  
  #ifdef COM_MULTIPORT
  /* checks in flags for multiport and which is multiport "master chip"
***************
*** 104,112 ****
--- 106,118 ----
  #define	COM_NOTAST4(dev)	((dev)->id_flags & 0x04)
  #endif /* COM_MULTIPORT */
  
+ #define	COM_CONSOLE(dev)	((dev)->id_flags & 0x10)
+ #define	COM_FORCECONSOLE(dev)	((dev)->id_flags & 0x20)
+ #define	COM_LLCONSOLE(dev)	((dev)->id_flags & 0x40)
  #define	COM_LOSESOUTINTS(dev)	((dev)->id_flags & 0x08)
  #define	COM_NOFIFO(dev)		((dev)->id_flags & 0x02)
  #define	COM_VERBOSE(dev)	((dev)->id_flags & 0x80)
+ #define	COM_BAUD_MULTIPLE(dev)	((((dev)->id_flags >> 20) & 0x0F) + 1)
  
  #define	com_scr		7	/* scratch register for 16450-16550 (R/W) */
  
***************
*** 195,200 ****
--- 201,207 ----
  	int	unit;		/* unit	number */
  	int	dtr_wait;	/* time to hold DTR down on close (* 1/hz) */
  	u_int	tx_fifo_size;
+ 	u_int	baud_max;	/* maximum baud rate, (divisor = 1) */
  	u_int	wopeners;	/* # processes waiting for DCD in open() */
  
  	/*
***************
*** 331,336 ****
--- 338,345 ----
  };
  
  static	int	comconsole = -1;
+ static	Port_t	siocniobase;
+ 	int	siocn_baud_max = BASIC_BAUD_MAX ; /* set from vendor code */
  static	speed_t	comdefaultrate = CONSPEED;
  static	u_int	com_events;	/* input chars + weighted output completions */
  static	int	sio_timeout;
***************
*** 342,375 ****
  #endif
  static	const int	nsio_tty = NSIO;
  
- static	struct speedtab comspeedtab[] = {
- 	{ 0,		0 },
- 	{ 50,		COMBRD(50) },
- 	{ 75,		COMBRD(75) },
- 	{ 110,		COMBRD(110) },
- 	{ 134,		COMBRD(134) },
- 	{ 150,		COMBRD(150) },
- 	{ 200,		COMBRD(200) },
- 	{ 300,		COMBRD(300) },
- 	{ 600,		COMBRD(600) },
- 	{ 1200,		COMBRD(1200) },
- 	{ 1800,		COMBRD(1800) },
- 	{ 2400,		COMBRD(2400) },
- 	{ 4800,		COMBRD(4800) },
- 	{ 9600,		COMBRD(9600) },
- 	{ 19200,	COMBRD(19200) },
- 	{ 38400,	COMBRD(38400) },
- 	{ 57600,	COMBRD(57600) },
- 	{ 115200,	COMBRD(115200) },
- 	{ -1,		-1 }
- };
- 
  #ifdef COM_ESP
  /* XXX configure this properly. */
  static	Port_t	likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, };
  static	Port_t	likely_esp_ports[] = { 0x140, 0x180, 0x280, 0 };
  #endif
  
  #if NCRD > 0
  /*
   *	PC-Card (PCMCIA) specific code.
--- 351,424 ----
  #endif
  static	const int	nsio_tty = NSIO;
  
  #ifdef COM_ESP
  /* XXX configure this properly. */
  static	Port_t	likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, };
  static	Port_t	likely_esp_ports[] = { 0x140, 0x180, 0x280, 0 };
  #endif
  
+ /*
+  * handle sysctl read/write requests for console speed
+  * 
+  * In addition to setting comdefaultrate for I/O through /dev/console,
+  * also set the initial and lock values for the /dev/ttyXX device
+  * if there is one associated with the console.  Finally, if the /dev/tty
+  * device has already been open, change the speed on the open running port
+  * itself.
+  */
+ 
+ static int
+ sysctl_machdep_comdefaultrate SYSCTL_HANDLER_ARGS
+ {
+ 	int error, s;
+ 	speed_t newspeed;
+ 	struct com_s *com;
+ 	struct tty *tp;
+ 
+ 	newspeed = comdefaultrate;
+ 
+ 	error = sysctl_handle_opaque(oidp, &newspeed, sizeof newspeed, req);
+ 	if (error || !req->newptr)
+ 		return (error);
+ 
+ 	comdefaultrate = newspeed;
+ 
+ 	if (comconsole < 0)		/* serial console not selected? */
+ 		return (0);
+ 
+ 	com = com_addr(comconsole);
+ 	if (!com)
+ 		return (ENXIO);
+ 
+ 	/*
+ 	 * set the initial and lock rates for /dev/ttydXX and /dev/cuaXX
+ 	 * (note, the lock rates really are boolean -- if non-zero, disallow
+ 	 *  speed changes)
+ 	 * XXX for now don't do the lock speeds  [JRE]
+ 	 */
+ 	com->lt_in.c_ispeed  = com->lt_in.c_ospeed =
+ 	com->lt_out.c_ispeed = com->lt_out.c_ospeed = 0;
+ 	com->it_in.c_ispeed  = com->it_in.c_ospeed =
+ 	com->it_out.c_ispeed = com->it_out.c_ospeed =
+ 	comdefaultrate;
+ 
+ 	/*
+ 	 * if we're open, change the running rate too
+ 	 */
+ 	tp = com->tp;
+ 	if (tp && (tp->t_state & TS_ISOPEN)) {
+ 		tp->t_termios.c_ispeed =
+ 		tp->t_termios.c_ospeed = comdefaultrate;
+ 		s = spltty();
+ 		error = comparam(tp, &tp->t_termios);
+ 		splx(s);
+ 	}
+ 	return error;
+ }
+ 
+ SYSCTL_PROC(_machdep, OID_AUTO, conspeed, CTLTYPE_INT | CTLFLAG_RW,
+ 	    0, 0, sysctl_machdep_comdefaultrate, "I", "");
+ 
  #if NCRD > 0
  /*
   *	PC-Card (PCMCIA) specific code.
***************
*** 572,582 ****
  	 * XXX what about the UART bug avoided by waiting in comparam()?
  	 * We don't want to to wait long enough to drain at 2 bps.
  	 */
! 	outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
! 	outb(iobase + com_dlbl, COMBRD(9600) & 0xff);
! 	outb(iobase + com_dlbh, (u_int) COMBRD(9600) >> 8);
! 	outb(iobase + com_cfcr, CFCR_8BITS);
! 	DELAY((16 + 1) * 1000000 / (9600 / 10));
  
  	/*
  	 * Enable the interrupt gate and disable device interupts.  This
--- 621,635 ----
  	 * XXX what about the UART bug avoided by waiting in comparam()?
  	 * We don't want to to wait long enough to drain at 2 bps.
  	 */
! 	if (iobase == siocniobase)
! 		DELAY((16 + 1) * 1000000 / (comdefaultrate / 10));
! 	else {
! 		outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
! 		outb(iobase + com_dlbl, COMBRD(9600) & 0xff);
! 		outb(iobase + com_dlbh, (u_int) COMBRD(9600) >> 8);
! 		outb(iobase + com_cfcr, CFCR_8BITS);
! 		DELAY((16 + 1) * 1000000 / (9600 / 10));
! 	}
  
  	/*
  	 * Enable the interrupt gate and disable device interupts.  This
***************
*** 810,818 ****
  		com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL;
  		com->it_in.c_lflag = TTYDEF_LFLAG;
  		com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL;
  		com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;
! 	} else
  		com->it_in.c_ispeed = com->it_in.c_ospeed = TTYDEF_SPEED;
  	termioschars(&com->it_in);
  	com->it_out = com->it_in;
  
--- 863,880 ----
  		com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL;
  		com->it_in.c_lflag = TTYDEF_LFLAG;
  		com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL;
+ 		/*
+ 		 * The initial rates equal the console rate
+ 		 * but the value is not locked
+ 		 */
+ 		com->lt_out.c_ispeed = com->lt_out.c_ospeed =
+ 		com->lt_in.c_ispeed = com->lt_in.c_ospeed = 0;
  		com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;
! 		com->baud_max = siocn_baud_max;
! 	} else {
! 		com->baud_max = COM_BAUD_MULTIPLE(isdp) * BASIC_BAUD_MAX;
  		com->it_in.c_ispeed = com->it_in.c_ospeed = TTYDEF_SPEED;
+ 	}
  	termioschars(&com->it_in);
  	com->it_out = com->it_in;
  
***************
*** 938,943 ****
--- 1000,1007 ----
  					  COM_MPMASTER(isdp))->id_irq == 0;
  	 }
  #endif /* COM_MULTIPORT */
+ 	if (unit == comconsole)
+ 		printf(", console");
  	printf("\n");
  
  	s = spltty();
***************
*** 1868,1873 ****
--- 1932,1981 ----
  		goto repeat;
  }
  
+ /* 
+  * given the xtal speed, and a multiple and a speed,
+  * work out the nearest clock-dividor, or return an error
+  * if there isn't one within about 4% of the required speed.
+  * returns the speed adjusted to the correct nearest value as well.
+  * Probably needs less magic numbers.
+  */
+ static int
+ makedivisor( speed_t *speed, int *divisorp, int baud_max)
+ {
+ 	int check, divisor;
+ 
+ 	if (*speed == 0) {
+ 		divisor = 0;
+ 	} else {
+ 		/*
+ 		 * Calculate the divisor. 
+ 		 * Make it 2 x and then use rounding, rather than use
+ 		 * a direct truncation, after all, the correct
+ 		 * divisor might be 0.001 higher.
+ 		 */
+ 		divisor = (baud_max * 2) / (*speed);
+ 
+ 		divisor = (divisor + 1) >> 1; /* round up or down */
+ 		/*
+ 		 * the specs usually say that a speed
+ 		 * must be (+ or -) 5%
+ 		 * to be acceptable. We'll use 4%.
+ 		 */
+ 		check = (100 * divisor * (*speed)) /(baud_max);
+ 		if ((check < 96) || (check > 104)) {
+ 			return (EINVAL); /* not close enough */
+ 		}
+ 
+ 		/*
+ 		 * Make the reported speed show what we
+ 		 * are actually doing.
+ 		 */
+ 		*speed = (baud_max)/divisor;
+ 	}
+ 	*divisorp = divisor;
+ 	return (0);
+ }
+ 
  static int
  comparam(tp, t)
  	struct tty	*tp;
***************
*** 1885,1903 ****
  	int		unit;
  	int		txtimeout;
  
  	/* do historical conversions */
  	if (t->c_ispeed == 0)
  		t->c_ispeed = t->c_ospeed;
  
  	/* check requested parameters */
! 	divisor = ttspeedtab(t->c_ospeed, comspeedtab);
! 	if (divisor < 0 || divisor > 0 && t->c_ispeed != t->c_ospeed)
  		return (EINVAL);
  
  	/* parameters are OK, convert them to the com struct and the device */
- 	unit = DEV_TO_UNIT(tp->t_dev);
- 	com = com_addr(unit);
- 	iobase = com->iobase;
  	s = spltty();
  	if (divisor == 0)
  		(void)commctl(com, TIOCM_DTR, DMBIC);	/* hang up line */
--- 1993,2020 ----
  	int		unit;
  	int		txtimeout;
  
+ 	unit = DEV_TO_UNIT(tp->t_dev);
+ 	com = com_addr(unit);
+ 	iobase = com->iobase;
+ 
  	/* do historical conversions */
  	if (t->c_ispeed == 0)
  		t->c_ispeed = t->c_ospeed;
  
  	/* check requested parameters */
! 	if(com->baud_max == 0) { /* catch 0 as well */
! 		com->baud_max = BASIC_BAUD_MAX;
! 		printf("sio%d: warning, baud multiple was 0\n", unit); 
! 	}
! 	error = makedivisor( &(t->c_ospeed), &divisor , com->baud_max);
! 	if (error)
! 		return error;
! 	t->c_ispeed = t->c_ospeed;
! 	if (divisor <= 0) {
  		return (EINVAL);
+ 	}
  
  	/* parameters are OK, convert them to the com struct and the device */
  	s = spltty();
  	if (divisor == 0)
  		(void)commctl(com, TIOCM_DTR, DMBIC);	/* hang up line */
***************
*** 2394,2400 ****
  	u_char	mcr;
  };
  
- static	Port_t	siocniobase;
  
  static void siocnclose	__P((struct siocnstate *sp));
  static void siocnopen	__P((struct siocnstate *sp));
--- 2511,2516 ----
***************
*** 2444,2450 ****
  	 * data input register.  This also reduces the effects of the
  	 * UMC8669F bug.
  	 */
! 	divisor = ttspeedtab(comdefaultrate, comspeedtab);
  	dlbl = divisor & 0xFF;
  	if (sp->dlbl != dlbl)
  		outb(iobase + com_dlbl, dlbl);
--- 2560,2566 ----
  	 * data input register.  This also reduces the effects of the
  	 * UMC8669F bug.
  	 */
! 	makedivisor( &comdefaultrate, &divisor , siocn_baud_max);
  	dlbl = divisor & 0xFF;
  	if (sp->dlbl != dlbl)
  		outb(iobase + com_dlbl, dlbl);
***************
*** 2489,2509 ****
  siocnprobe(cp)
  	struct consdev	*cp;
  {
! 	int	unit;
! 
! 	/* XXX: ick */
! 	unit = DEV_TO_UNIT(CONUNIT);
! 	siocniobase = CONADDR;
! 
! 	/* make sure hardware exists?  XXX */
! 
! 	/* initialize required fields */
! 	cp->cn_dev = makedev(CDEV_MAJOR, unit);
! #ifdef COMCONSOLE
! 	cp->cn_pri = CN_REMOTE;		/* Force a serial port console */
! #else
! 	cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL;
! #endif
  }
  
  void
--- 2605,2647 ----
  siocnprobe(cp)
  	struct consdev	*cp;
  {
! 	struct isa_device	*dvp;
! 	int			s;
! 	struct siocnstate	sp;
! 
! 	/*
! 	 * Find our first enabled console, if any.  If it is a high-level
! 	 * console device, then initialize it and return successfully.
! 	 * If it is a low-level console device, then initialize it and
! 	 * return unsuccessfully.  It must be initialized in both cases
! 	 * for early use by console drivers and debuggers.  Initializing
! 	 * the hardware is not necessary in all cases, since the i/o
! 	 * routines initialize it on the fly, but it is necessary if
! 	 * input might arrive while the hardware is switched back to an
! 	 * uninitialized state.  We can't handle multiple console devices
! 	 * yet because our low-level routines don't take a device arg.
! 	 * We trust the user to set the console flags properly so that we
! 	 * don't need to probe.
! 	 */
! 	cp->cn_pri = CN_DEAD;
! 	for (dvp = isa_devtab_tty; dvp->id_driver != NULL; dvp++)
! 		if ((dvp->id_driver == &siodriver)
! 		&& (dvp->id_enabled)
! 		&& (COM_CONSOLE(dvp))) {
! 			siocniobase = dvp->id_iobase;
! 			siocn_baud_max
! 				= COM_BAUD_MULTIPLE(dvp) * BASIC_BAUD_MAX;
! 			s = spltty();
! 			siocnopen(&sp);
! 			splx(s);
! 			if (!COM_LLCONSOLE(dvp)) {
! 				cp->cn_dev = makedev(CDEV_MAJOR, dvp->id_unit);
! 				cp->cn_pri = COM_FORCECONSOLE(dvp)
! 					     || boothowto & RB_SERIAL
! 					     ? CN_REMOTE : CN_NORMAL;
! 			}
! 			break;
! 		}
  }
  
  void

--------------FF6D5DF3F54BC7E1CFBAE39--




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3410B8B3.59E2B600>