Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 27 Aug 1997 19:39:27 -0700
From:      Julian Elischer <julian@whistle.com>
To:        bde@freebsd.org
Cc:        hackers@freebsd.org
Subject:   sio.c "turbo mode" additions.
Message-ID:  <3404E4DF.1B37ADEA@whistle.com>

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

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

Bruce,

Here are a set of diffs that allow the sio driver in 2.2.2 to take
into account that the hardware has had it's clock doubled (or more),
and to use any baud rate that it can reach within 4%. (the usual
standard).

We have a module here that is specific to our code, that would set
the given parameter (console baud multiple) to suit our (x 2)
sio hardware, however the same effect can be achieved 
using a config parameter, or by setting flags in the config file
for the sio device.

Other than style (you always don't like my style so I take 
that for granted) What objections/problems do you see in this?
I run use this to get 230400 baud (and it shows up as 230400
in the stty status information. It allows the kernel hacker
to specify in his config line that a particular tty line is
overclocked, from 1 to 16 times. 16 would give 1843200 baud.
As I said, this is for 2.2.2 and incorporates some of the 
patches that have gone nto the -current version. a -current
patch would be smaller, but I'm sure you can see what it would
consist of. Would you consider this to be useful enough to be
put in -current (appropriatly modified) and tehn after testing,
into 2.2?

As far as style goes.. I will change things if you want,
I want the code to go in and don't care about the style of it.

julian

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

*** /tmp_mnt/built1/work/julian/2.2R4C-DIAG/usr/src/sys/i386/isa/sio.c	Sun Jun 22 18:38:30 1997
--- sio.c	Thu Aug 21 18:16:53 1997
***************
*** 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.1 1997/08/21 18:06:21 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
***************
*** 104,112 ****
--- 105,117 ----
  #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 ****
--- 200,206 ----
  	int	unit;		/* unit	number */
  	int	dtr_wait;	/* time to hold DTR down on close (* 1/hz) */
  	u_int	tx_fifo_size;
+ 	u_int	baud_multiple;	/* chip has been supercharged by multiple X */
  	u_int	wopeners;	/* # processes waiting for DCD in open() */
  
  	/*
***************
*** 331,336 ****
--- 337,344 ----
  };
  
  static	int	comconsole = -1;
+ static	Port_t	siocniobase;
+ 	int	siocn_baud_multiple = 1; /* set from vendor startup 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.
--- 350,423 ----
  #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
--- 620,634 ----
  	 * 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;
  
--- 862,879 ----
  		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_multiple = siocn_baud_multiple;
! 	} else {
! 		com->baud_multiple = COM_BAUD_MULTIPLE(isdp);
  		com->it_in.c_ispeed = com->it_in.c_ospeed = TTYDEF_SPEED;
+ 	}
  	termioschars(&com->it_in);
  	com->it_out = com->it_in;
  
***************
*** 938,943 ****
--- 999,1006 ----
  					  COM_MPMASTER(isdp))->id_irq == 0;
  	 }
  #endif /* COM_MULTIPORT */
+ 	if (unit == comconsole)
+ 		printf(", console");
  	printf("\n");
  
  	s = spltty();
***************
*** 1868,1873 ****
--- 1931,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_multiple)
+ {
+ 	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_multiple * 115200 * 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_multiple * 115200);
+ 		if ((check < 96) || (check > 104)) {
+ 			return (EINVAL); /* not close enough */
+ 		}
+ 
+ 		/*
+ 		 * Make the reported speed show what we
+ 		 * are actually doing.
+ 		 */
+ 		*speed = (baud_multiple * 115200)/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_multiple == 0) { /* catch 0 as well */
! 		com->baud_multiple = 1;
! 		printf("sio%d: warning, baud multiple was 0\n", unit); 
! 	}
! 	error = makedivisor( &(t->c_ospeed), &divisor , com->baud_multiple);
! 	if (error)
! 		return error;
! 	t->c_ispeed = t->c_ospeed;
! 	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 */
  	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_multiple);
  	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,2646 ----
  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_multiple = COM_BAUD_MULTIPLE(dvp);
! 			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

--------------345BF6515E652F787AAE88DB--




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3404E4DF.1B37ADEA>