Add support for different serial clock frequencies and not just the
standard one of 1.8432MHz. This will be used by the puc (PCI "universal" communication card) device driver. Reviewed by: bde
This commit is contained in:
parent
aff5957cfd
commit
57019e6041
@ -255,6 +255,8 @@ struct com_s {
|
||||
u_int delta_error_counts[CE_NTYPES];
|
||||
u_long error_counts[CE_NTYPES];
|
||||
|
||||
u_long rclk;
|
||||
|
||||
struct resource *irqres;
|
||||
struct resource *ioportres;
|
||||
void *cookie;
|
||||
@ -273,6 +275,7 @@ static int espattach __P((struct com_s *com, Port_t esp_port));
|
||||
#endif
|
||||
|
||||
static timeout_t siobusycheck;
|
||||
static u_int siodivisor __P((u_long rclk, speed_t speed));
|
||||
static timeout_t siodtrwakeup;
|
||||
static void comhardclose __P((struct com_s *com));
|
||||
static void sioinput __P((struct com_s *com));
|
||||
@ -324,6 +327,8 @@ static struct cdevsw sio_cdevsw = {
|
||||
|
||||
int comconsole = -1;
|
||||
static volatile speed_t comdefaultrate = CONSPEED;
|
||||
static u_long comdefaultrclk = DEFAULT_RCLK;
|
||||
SYSCTL_ULONG(_machdep, OID_AUTO, conrclk, CTLFLAG_RW, &comdefaultrclk, 0, "");
|
||||
#ifdef __alpha__
|
||||
static volatile speed_t gdbdefaultrate = CONSPEED;
|
||||
#endif
|
||||
@ -342,29 +347,6 @@ static struct callout_handle sio_timeout_handle
|
||||
= CALLOUT_HANDLE_INITIALIZER(&sio_timeout_handle);
|
||||
static int sio_numunits;
|
||||
|
||||
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) },
|
||||
{ 28800, COMBRD(28800) },
|
||||
{ 38400, COMBRD(38400) },
|
||||
{ 57600, COMBRD(57600) },
|
||||
{ 115200, COMBRD(115200) },
|
||||
{ -1, -1 }
|
||||
};
|
||||
|
||||
#ifdef COM_ESP
|
||||
/* XXX configure this properly. */
|
||||
/* XXX quite broken for new-bus. */
|
||||
@ -483,9 +465,10 @@ siodetach(dev)
|
||||
}
|
||||
|
||||
int
|
||||
sioprobe(dev, xrid, noprobe)
|
||||
sioprobe(dev, xrid, rclk, noprobe)
|
||||
device_t dev;
|
||||
int xrid;
|
||||
u_long rclk;
|
||||
int noprobe;
|
||||
{
|
||||
#if 0
|
||||
@ -493,6 +476,7 @@ sioprobe(dev, xrid, noprobe)
|
||||
device_t xdev;
|
||||
#endif
|
||||
struct com_s *com;
|
||||
u_int divisor;
|
||||
bool_t failures[10];
|
||||
int fn;
|
||||
device_t idev;
|
||||
@ -518,6 +502,9 @@ sioprobe(dev, xrid, noprobe)
|
||||
device_set_softc(dev, com);
|
||||
com->bst = rman_get_bustag(port);
|
||||
com->bsh = rman_get_bushandle(port);
|
||||
if (rclk == 0)
|
||||
rclk = DEFAULT_RCLK;
|
||||
com->rclk = rclk;
|
||||
|
||||
while (sio_inited != 2)
|
||||
if (atomic_cmpset_int(&sio_inited, 0, 1)) {
|
||||
@ -630,8 +617,9 @@ sioprobe(dev, xrid, noprobe)
|
||||
DELAY((16 + 1) * 1000000 / (comdefaultrate / 10));
|
||||
else {
|
||||
sio_setreg(com, com_cfcr, CFCR_DLAB | CFCR_8BITS);
|
||||
sio_setreg(com, com_dlbl, COMBRD(SIO_TEST_SPEED) & 0xff);
|
||||
sio_setreg(com, com_dlbh, (u_int) COMBRD(SIO_TEST_SPEED) >> 8);
|
||||
divisor = siodivisor(rclk, SIO_TEST_SPEED);
|
||||
sio_setreg(com, com_dlbl, divisor & 0xff);
|
||||
sio_setreg(com, com_dlbh, divisor >> 8);
|
||||
sio_setreg(com, com_cfcr, CFCR_8BITS);
|
||||
DELAY((16 + 1) * 1000000 / (SIO_TEST_SPEED / 10));
|
||||
}
|
||||
@ -866,9 +854,10 @@ espattach(com, esp_port)
|
||||
#endif /* COM_ESP */
|
||||
|
||||
int
|
||||
sioattach(dev, xrid)
|
||||
sioattach(dev, xrid, rclk)
|
||||
device_t dev;
|
||||
int xrid;
|
||||
u_long rclk;
|
||||
{
|
||||
struct com_s *com;
|
||||
#ifdef COM_ESP
|
||||
@ -927,6 +916,10 @@ sioattach(dev, xrid)
|
||||
com->modem_status_port = iobase + com_msr;
|
||||
com->intr_ctl_port = iobase + com_ier;
|
||||
|
||||
if (rclk == 0)
|
||||
rclk = DEFAULT_RCLK;
|
||||
com->rclk = rclk;
|
||||
|
||||
/*
|
||||
* We don't use all the flags from <sys/ttydefaults.h> since they
|
||||
* are only relevant for logins. It's important to have echo off
|
||||
@ -1495,6 +1488,32 @@ siobusycheck(chan)
|
||||
splx(s);
|
||||
}
|
||||
|
||||
static u_int
|
||||
siodivisor(rclk, speed)
|
||||
u_long rclk;
|
||||
speed_t speed;
|
||||
{
|
||||
long actual_speed;
|
||||
u_int divisor;
|
||||
int error;
|
||||
|
||||
if (speed == 0 || speed > (ULONG_MAX - 1) / 8)
|
||||
return (0);
|
||||
divisor = (rclk / (8UL * speed) + 1) / 2;
|
||||
if (divisor == 0 || divisor >= 65536)
|
||||
return (0);
|
||||
actual_speed = rclk / (16UL * divisor);
|
||||
|
||||
/* 10 times error in percent: */
|
||||
error = ((actual_speed - (long)speed) * 2000 / (long)speed + 1) / 2;
|
||||
|
||||
/* 3.0% maximum error tolerance: */
|
||||
if (error < -30 || error > 30)
|
||||
return (0);
|
||||
|
||||
return (divisor);
|
||||
}
|
||||
|
||||
static void
|
||||
siodtrwakeup(chan)
|
||||
void *chan;
|
||||
@ -2109,26 +2128,33 @@ comparam(tp, t)
|
||||
u_int cfcr;
|
||||
int cflag;
|
||||
struct com_s *com;
|
||||
int divisor;
|
||||
u_int divisor;
|
||||
u_char dlbh;
|
||||
u_char dlbl;
|
||||
int s;
|
||||
int unit;
|
||||
|
||||
unit = DEV_TO_UNIT(tp->t_dev);
|
||||
com = com_addr(unit);
|
||||
if (com == NULL)
|
||||
return (ENODEV);
|
||||
|
||||
/* 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);
|
||||
if (t->c_ospeed == 0)
|
||||
divisor = 0;
|
||||
else {
|
||||
if (t->c_ispeed != t->c_ospeed)
|
||||
return (EINVAL);
|
||||
divisor = siodivisor(com->rclk, t->c_ispeed);
|
||||
if (divisor == 0)
|
||||
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);
|
||||
if (com == NULL)
|
||||
return (ENODEV);
|
||||
s = spltty();
|
||||
if (divisor == 0)
|
||||
(void)commctl(com, TIOCM_DTR, DMBIC); /* hang up line */
|
||||
@ -2203,7 +2229,7 @@ comparam(tp, t)
|
||||
dlbl = divisor & 0xFF;
|
||||
if (sio_getreg(com, com_dlbl) != dlbl)
|
||||
sio_setreg(com, com_dlbl, dlbl);
|
||||
dlbh = (u_int) divisor >> 8;
|
||||
dlbh = divisor >> 8;
|
||||
if (sio_getreg(com, com_dlbh) != dlbh)
|
||||
sio_setreg(com, com_dlbh, dlbh);
|
||||
}
|
||||
@ -2669,7 +2695,7 @@ struct siocnstate {
|
||||
};
|
||||
|
||||
#ifndef __alpha__
|
||||
static speed_t siocngetspeed __P((Port_t, struct speedtab *));
|
||||
static speed_t siocngetspeed __P((Port_t, u_long rclk));
|
||||
#endif
|
||||
static void siocnclose __P((struct siocnstate *sp, Port_t iobase));
|
||||
static void siocnopen __P((struct siocnstate *sp, Port_t iobase, int speed));
|
||||
@ -2728,11 +2754,11 @@ siocntxwait(iobase)
|
||||
*/
|
||||
|
||||
static speed_t
|
||||
siocngetspeed(iobase, table)
|
||||
Port_t iobase;
|
||||
struct speedtab *table;
|
||||
siocngetspeed(iobase, rclk)
|
||||
Port_t iobase;
|
||||
u_long rclk;
|
||||
{
|
||||
int code;
|
||||
u_int divisor;
|
||||
u_char dlbh;
|
||||
u_char dlbl;
|
||||
u_char cfcr;
|
||||
@ -2745,13 +2771,12 @@ siocngetspeed(iobase, table)
|
||||
|
||||
outb(iobase + com_cfcr, cfcr);
|
||||
|
||||
code = dlbh << 8 | dlbl;
|
||||
divisor = dlbh << 8 | dlbl;
|
||||
|
||||
for (; table->sp_speed != -1; table++)
|
||||
if (table->sp_code == code)
|
||||
return (table->sp_speed);
|
||||
|
||||
return (0); /* didn't match anything sane */
|
||||
/* XXX there should be more sanity checking. */
|
||||
if (divisor == 0)
|
||||
return (CONSPEED);
|
||||
return (rclk / (16UL * divisor));
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -2762,7 +2787,7 @@ siocnopen(sp, iobase, speed)
|
||||
Port_t iobase;
|
||||
int speed;
|
||||
{
|
||||
int divisor;
|
||||
u_int divisor;
|
||||
u_char dlbh;
|
||||
u_char dlbl;
|
||||
|
||||
@ -2784,11 +2809,11 @@ siocnopen(sp, iobase, speed)
|
||||
* data input register. This also reduces the effects of the
|
||||
* UMC8669F bug.
|
||||
*/
|
||||
divisor = ttspeedtab(speed, comspeedtab);
|
||||
divisor = siodivisor(comdefaultrclk, speed);
|
||||
dlbl = divisor & 0xFF;
|
||||
if (sp->dlbl != dlbl)
|
||||
outb(iobase + com_dlbl, dlbl);
|
||||
dlbh = (u_int) divisor >> 8;
|
||||
dlbh = divisor >> 8;
|
||||
if (sp->dlbh != dlbh)
|
||||
outb(iobase + com_dlbh, dlbh);
|
||||
outb(iobase + com_cfcr, CFCR_8BITS);
|
||||
@ -2831,6 +2856,7 @@ siocnprobe(cp)
|
||||
{
|
||||
speed_t boot_speed;
|
||||
u_char cfcr;
|
||||
u_int divisor;
|
||||
int s, unit;
|
||||
struct siocnstate sp;
|
||||
|
||||
@ -2868,7 +2894,8 @@ siocnprobe(cp)
|
||||
iobase = port;
|
||||
s = spltty();
|
||||
if (boothowto & RB_SERIAL) {
|
||||
boot_speed = siocngetspeed(iobase, comspeedtab);
|
||||
boot_speed =
|
||||
siocngetspeed(iobase, comdefaultrclk);
|
||||
if (boot_speed)
|
||||
comdefaultrate = boot_speed;
|
||||
}
|
||||
@ -2884,10 +2911,9 @@ siocnprobe(cp)
|
||||
*/
|
||||
cfcr = inb(iobase + com_cfcr);
|
||||
outb(iobase + com_cfcr, CFCR_DLAB | cfcr);
|
||||
outb(iobase + com_dlbl,
|
||||
COMBRD(comdefaultrate) & 0xff);
|
||||
outb(iobase + com_dlbh,
|
||||
(u_int) COMBRD(comdefaultrate) >> 8);
|
||||
divisor = siodivisor(comdefaultrclk, comdefaultrate);
|
||||
outb(iobase + com_dlbl, divisor & 0xff);
|
||||
outb(iobase + com_dlbh, divisor >> 8);
|
||||
outb(iobase + com_cfcr, cfcr);
|
||||
|
||||
siocnopen(&sp, iobase, comdefaultrate);
|
||||
@ -2962,6 +2988,7 @@ siocnattach(port, speed)
|
||||
{
|
||||
int s;
|
||||
u_char cfcr;
|
||||
u_int divisor;
|
||||
struct siocnstate sp;
|
||||
|
||||
siocniobase = port;
|
||||
@ -2982,10 +3009,9 @@ siocnattach(port, speed)
|
||||
*/
|
||||
cfcr = inb(siocniobase + com_cfcr);
|
||||
outb(siocniobase + com_cfcr, CFCR_DLAB | cfcr);
|
||||
outb(siocniobase + com_dlbl,
|
||||
COMBRD(comdefaultrate) & 0xff);
|
||||
outb(siocniobase + com_dlbh,
|
||||
(u_int) COMBRD(comdefaultrate) >> 8);
|
||||
divisor = siodivisor(comdefaultrclk, comdefaultrate);
|
||||
outb(siocniobase + com_dlbl, divisor & 0xff);
|
||||
outb(siocniobase + com_dlbh, divisor >> 8);
|
||||
outb(siocniobase + com_cfcr, cfcr);
|
||||
|
||||
siocnopen(&sp, siocniobase, comdefaultrate);
|
||||
@ -3002,6 +3028,7 @@ siogdbattach(port, speed)
|
||||
{
|
||||
int s;
|
||||
u_char cfcr;
|
||||
u_int divisor;
|
||||
struct siocnstate sp;
|
||||
int unit = 1; /* XXX !!! */
|
||||
|
||||
@ -3029,10 +3056,9 @@ siogdbattach(port, speed)
|
||||
*/
|
||||
cfcr = inb(siogdbiobase + com_cfcr);
|
||||
outb(siogdbiobase + com_cfcr, CFCR_DLAB | cfcr);
|
||||
outb(siogdbiobase + com_dlbl,
|
||||
COMBRD(gdbdefaultrate) & 0xff);
|
||||
outb(siogdbiobase + com_dlbh,
|
||||
(u_int) COMBRD(gdbdefaultrate) >> 8);
|
||||
divisor = siodivisor(comdefaultrclk, gdbdefaultrate);
|
||||
outb(siogdbiobase + com_dlbl, divisor & 0xff);
|
||||
outb(siogdbiobase + com_dlbh, divisor >> 8);
|
||||
outb(siogdbiobase + com_cfcr, cfcr);
|
||||
|
||||
siocnopen(&sp, siogdbiobase, gdbdefaultrate);
|
||||
|
@ -149,14 +149,14 @@ sio_isa_probe(dev)
|
||||
/* Check isapnp ids */
|
||||
if (ISA_PNP_PROBE(device_get_parent(dev), dev, sio_ids) == ENXIO)
|
||||
return (ENXIO);
|
||||
return (sioprobe(dev, 0, 0));
|
||||
return (sioprobe(dev, 0, 0UL, 0));
|
||||
}
|
||||
|
||||
static int
|
||||
sio_isa_attach(dev)
|
||||
device_t dev;
|
||||
{
|
||||
return (sioattach(dev, 0));
|
||||
return (sioattach(dev, 0, 0UL));
|
||||
}
|
||||
|
||||
DRIVER_MODULE(sio, isa, sio_isa_driver, sio_devclass, 0, 0);
|
||||
|
@ -98,14 +98,14 @@ sio_pccard_probe(dev)
|
||||
#endif
|
||||
/* Do not probe IRQ - pccard doesn't turn on the interrupt line */
|
||||
/* until bus_setup_intr */
|
||||
return (sioprobe(dev, 0, 1));
|
||||
return (sioprobe(dev, 0, 0UL, 1));
|
||||
}
|
||||
|
||||
static int
|
||||
sio_pccard_attach(dev)
|
||||
device_t dev;
|
||||
{
|
||||
return (sioattach(dev, 0));
|
||||
return (sioattach(dev, 0, 0UL));
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -92,7 +92,7 @@ sio_pci_attach(dev)
|
||||
if (id->desc == NULL)
|
||||
return (ENXIO);
|
||||
sio_pci_kludge_unit(dev);
|
||||
return (sioattach(dev, id->rid));
|
||||
return (sioattach(dev, id->rid, 0UL));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -138,7 +138,7 @@ sio_pci_probe(dev)
|
||||
if (id->desc == NULL)
|
||||
return (ENXIO);
|
||||
device_set_desc(dev, id->desc);
|
||||
return (sioprobe(dev, id->rid, 0));
|
||||
return (sioprobe(dev, id->rid, 0UL, 0));
|
||||
}
|
||||
|
||||
DRIVER_MODULE(sio, pci, sio_pci_driver, sio_devclass, 0, 0);
|
||||
|
@ -34,10 +34,12 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/* Receiver clock frequency for "standard" pc serial ports. */
|
||||
#define DEFAULT_RCLK 1843200
|
||||
|
||||
#ifdef PC98
|
||||
/* 16 bit baud rate divisor (lower byte in dca_data, upper in dca_ier) */
|
||||
#define COMBRD(x) (1843200 / (16*(x)))
|
||||
#ifdef PC98
|
||||
#define COMBRD_RSA(x) (14745600 / (16*(x)))
|
||||
#endif
|
||||
|
||||
|
@ -63,9 +63,9 @@
|
||||
#define CLR_FLAG(dev, bit) device_set_flags(dev, device_get_flags(dev) & ~(bit))
|
||||
#endif /* PC98 */
|
||||
|
||||
int sioattach __P((device_t dev, int xrid));
|
||||
int sioattach __P((device_t dev, int xrid, u_long rclk));
|
||||
int siodetach __P((device_t dev));
|
||||
int sioprobe __P((device_t dev, int xrid, int noprobe));
|
||||
int sioprobe __P((device_t dev, int xrid, u_long rclk, int noprobe));
|
||||
|
||||
extern devclass_t sio_devclass;
|
||||
extern char sio_driver_name[];
|
||||
|
Loading…
x
Reference in New Issue
Block a user