From owner-freebsd-hackers Fri Sep 5 19:00:22 1997 Return-Path: Received: (from root@localhost) by hub.freebsd.org (8.8.7/8.8.7) id TAA13923 for hackers-outgoing; Fri, 5 Sep 1997 19:00:22 -0700 (PDT) Received: from alpo.whistle.com (alpo.whistle.com [207.76.204.38]) by hub.freebsd.org (8.8.7/8.8.7) with ESMTP id TAA13918 for ; Fri, 5 Sep 1997 19:00:18 -0700 (PDT) Received: (from daemon@localhost) by alpo.whistle.com (8.8.5/8.8.5) id SAA22661 for ; Fri, 5 Sep 1997 18:58:36 -0700 (PDT) Received: from current1.whistle.com(207.76.205.22) via SMTP by alpo.whistle.com, id smtpd022659; Sat Sep 6 01:58:34 1997 Message-ID: <3410B8B3.59E2B600@whistle.com> Date: Fri, 05 Sep 1997 18:58:11 -0700 From: Julian Elischer Organization: Whistle Communications X-Mailer: Mozilla 3.0Gold (X11; I; FreeBSD 2.2-CURRENT i386) MIME-Version: 1.0 To: hackers@freebsd.org Subject: [BDE:] sio.c proposed change. (HISPEED uarts) Content-Type: multipart/mixed; boundary="------------FF6D5DF3F54BC7E1CFBAE39" Sender: owner-freebsd-hackers@freebsd.org X-Loop: FreeBSD.org Precedence: bulk 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 #include #include + #include #ifdef DEVFS #include #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--