153887Smckusick /* 253887Smckusick * Copyright (c) 1992 The Regents of the University of California. 353887Smckusick * All rights reserved. 453887Smckusick * 553887Smckusick * This code is derived from software contributed to Berkeley by 653887Smckusick * Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc. 753887Smckusick * 853887Smckusick * %sccs.include.redist.c% 953887Smckusick * 1053887Smckusick * from: $Hdr: rs.c,v 4.300 91/06/09 06:43:03 root Rel41 $ SONY 1153887Smckusick * 12*57183Sutashiro * @(#)rs.c 7.3 (Berkeley) 12/17/92 1353887Smckusick */ 1453887Smckusick 1553887Smckusick /* rs.c 6.1 83/07/29 */ 1653887Smckusick 1753887Smckusick #include "rs.h" 1853887Smckusick #if NRS > 0 1953887Smckusick /* 2053887Smckusick * RS driver 2153887Smckusick * 2253887Smckusick */ 23*57183Sutashiro #include <machine/fix_machine_type.h> 2453887Smckusick 2553887Smckusick #if NBK > 0 2653887Smckusick #include "bk.h" 2753887Smckusick #endif 28*57183Sutashiro #include <sys/param.h> 29*57183Sutashiro #include <sys/conf.h> 30*57183Sutashiro #include <sys/proc.h> 31*57183Sutashiro #include <sys/user.h> 32*57183Sutashiro #include <sys/kernel.h> 33*57183Sutashiro #include <sys/ioctl.h> 34*57183Sutashiro #include <sys/tty.h> 35*57183Sutashiro #include <sys/buf.h> 36*57183Sutashiro #include <sys/malloc.h> 3753887Smckusick 3853887Smckusick #ifdef CPU_SINGLE 39*57183Sutashiro #include <news3400/hbdev/hbvar.h> 4053887Smckusick #else 4153887Smckusick #include "../iop/iopvar.h" 4253887Smckusick #endif 4353887Smckusick 44*57183Sutashiro #include <news3400/iop/rsreg.h> 45*57183Sutashiro #include <news3400/sio/sccparam.h> 4653887Smckusick 4753887Smckusick #define RS_RXE RXE 4853887Smckusick #define RS_TXE TXE 4953887Smckusick #define RS_ON (RXE|TXE|RTS|DTR) 5053887Smckusick #define RS_OFF TXE 5153887Smckusick #define RS_RTS RTS 5253887Smckusick #define RS_DTR DTR 5353887Smckusick #define RS_CTS CTS 5453887Smckusick #define RS_DCD DCD 5553887Smckusick #define RS_DSR DSR 5653887Smckusick #define RS_RI RI 5753887Smckusick #define RS_BRK XBREAK 5853887Smckusick 5953887Smckusick #ifdef AUTO_ENABLE 6053887Smckusick #define RS_AUTO_ENABLE AUTO_ENABLE 6153887Smckusick #endif 6253887Smckusick 6353887Smckusick #ifdef CPU_SINGLE 6453887Smckusick #define iop_device hb_device 6553887Smckusick #define ii_unit hi_unit 6653887Smckusick #define ii_flags hi_flags 6753887Smckusick #define ii_alive hi_alive 6853887Smckusick #endif 6953887Smckusick 7053887Smckusick /* 7153887Smckusick * Definition of the driver for the auto-configuration program. 7253887Smckusick */ 7353887Smckusick int rsprobe(), rsattach(), rsrint(), rsxint(), rssint(); 7453887Smckusick struct iop_device *rsinfo[NRS]; 7553887Smckusick 7653887Smckusick #ifdef CPU_SINGLE 7753887Smckusick struct hb_driver rsdriver = { rsprobe, 0, rsattach, 0, 0, "rs", rsinfo }; 7853887Smckusick #else 7953887Smckusick struct iop_driver rsdriver = { rsprobe, 0, rsattach, 0, "rs", rsinfo }; 8053887Smckusick #endif 8153887Smckusick 8253887Smckusick /* 8353887Smckusick * Local variables for the driver 8453887Smckusick */ 8553887Smckusick 8653887Smckusick struct tty rs_tty[NRS*4]; 8753887Smckusick char rssoftCAR[NRS]; 8853887Smckusick 8953887Smckusick int rs_flags[NRS*4]; 9053887Smckusick int rs_param[NRS*4]; 9153887Smckusick char rs_active[NRS*4]; 9253887Smckusick char rs_stopped[NRS*4]; 9353887Smckusick 9453887Smckusick int rs_rate[NRS*4]; 9553887Smckusick int rs_average[NRS*4]; 9653887Smckusick char rs_timeout[NRS*4]; 9753887Smckusick char rs_watch; 9853887Smckusick 9953887Smckusick #ifndef lint 10053887Smckusick int nrs = NRS*4; /* used by iostat */ 10153887Smckusick #endif 10253887Smckusick 10353887Smckusick extern int tty00_is_console; 10453887Smckusick extern void rsstart(); 10553887Smckusick extern void ttrstrt(); 10653887Smckusick extern void rsctrl(); 10753887Smckusick 10853887Smckusick #define RS_CARR(unit) (rssoftCAR[(unit) >> 2] & (1 << ((unit) & 03))) 10953887Smckusick #define RS_FLAG(unit, flag) (rs_flags[unit] & (flag)) 11053887Smckusick 11153887Smckusick #define RF_FLOWCTL 0x0010 /* use H/W flow control */ 11253887Smckusick #define RF_EXTCLK 0x0100 /* allow external clock */ 11353887Smckusick #define RF_NODELAY 0x1000 /* disable interrupt delay */ 11453887Smckusick 11553887Smckusick /* 11653887Smckusick * Routine for configuration 11753887Smckusick */ 11853887Smckusick /*ARGSUSED*/ 11953887Smckusick rsprobe(ii) 12053887Smckusick struct iop_device *ii; 12153887Smckusick { 12253887Smckusick 12353887Smckusick return (rs_probe(ii)); 12453887Smckusick } 12553887Smckusick 12653887Smckusick /* 12753887Smckusick * Routine called to attach a rs. 12853887Smckusick */ 12953887Smckusick rsattach(ii) 13053887Smckusick register struct iop_device *ii; 13153887Smckusick { 13253887Smckusick int i; 13353887Smckusick 13453887Smckusick rssoftCAR[ii->ii_unit] = ii->ii_flags; 13553887Smckusick for (i = 0; i < 4; i++) 13653887Smckusick rs_flags[ii->ii_unit * 4 + i] = 13753887Smckusick (ii->ii_flags >> i) & (RF_FLOWCTL|RF_EXTCLK|RF_NODELAY); 13853887Smckusick if (rs_watch == 0) { 13953887Smckusick rs_watchdog(); 14053887Smckusick rs_watch = 1; 14153887Smckusick } 14253887Smckusick } 14353887Smckusick 14453887Smckusick rs_watchdog() 14553887Smckusick { 14653887Smckusick register int unit, s; 14753887Smckusick 14853887Smckusick for (unit = 0; unit < NRS*4; unit++) { 14953887Smckusick if (rs_active[unit] == 0) 15053887Smckusick continue; 15153887Smckusick s = spltty(); 15253887Smckusick rs_average[unit] = (rs_average[unit] * 7 + rs_rate[unit]) >> 3; 15353887Smckusick rs_rate[unit] = 0; 15453887Smckusick (void) splx(s); 15553887Smckusick } 15653887Smckusick timeout(rs_watchdog, (caddr_t)0, hz / 10); 15753887Smckusick } 15853887Smckusick 15953887Smckusick /* 16053887Smckusick * Open a RS line. Turn on this rs if this is the first use of it. 16153887Smckusick */ 16253887Smckusick /*ARGSUSED*/ 16353887Smckusick rsopen(dev, flag, mode, p) 16453887Smckusick dev_t dev; 16553887Smckusick int flag, mode; 16653887Smckusick struct proc *p; 16753887Smckusick { 16853887Smckusick register int unit; 16953887Smckusick register struct tty *tp; 17053887Smckusick register struct iop_device *ii; 17153887Smckusick int s; 17253887Smckusick 17353887Smckusick unit = minor(dev); 17453887Smckusick if (unit >= NRS*4 || (ii = rsinfo[unit >> 2]) == 0 || ii->ii_alive == 0) 17553887Smckusick return (ENXIO); 17653887Smckusick if (rs_active[unit] == 0) { 17753887Smckusick if (rs_init(unit) < 0) 17853887Smckusick return (ENXIO); 17953887Smckusick rs_enable(unit); 18053887Smckusick rs_active[unit] = 1; 18153887Smckusick } 18253887Smckusick tp = &rs_tty[unit]; 18353887Smckusick if (tp->t_state&TS_XCLUDE && curproc->p_ucred->cr_uid != 0) 18453887Smckusick return (EBUSY); 18553887Smckusick tp->t_addr = (caddr_t)0; 18653887Smckusick tp->t_oproc = rsstart; 18753887Smckusick #ifdef notyet /* KU:XXX */ 18853887Smckusick tp->t_ctrlproc = rsctrl; 18953887Smckusick #endif 19053887Smckusick /* 19153887Smckusick * If this is first open, initialze tty state to default. 19253887Smckusick */ 19353887Smckusick if ((tp->t_state & TS_ISOPEN) == 0) { 19453887Smckusick tp->t_state |= TS_WOPEN; 19553887Smckusick ttychars(tp); 19653887Smckusick if (tp->t_ispeed == 0) { 19753887Smckusick tp->t_iflag = TTYDEF_IFLAG; 19853887Smckusick tp->t_oflag = TTYDEF_OFLAG; 19953887Smckusick tp->t_cflag = TTYDEF_CFLAG; 20053887Smckusick tp->t_lflag = TTYDEF_LFLAG; 20153887Smckusick tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 20253887Smckusick } 20353887Smckusick rsparam(tp, &tp->t_termios); 20453887Smckusick ttsetwater(tp); 20553887Smckusick } 20653887Smckusick /* 20753887Smckusick * Wait receiver and status interrupt 20853887Smckusick */ 20953887Smckusick /* 21053887Smckusick * Wait for carrier, then process line discipline specific open. 21153887Smckusick */ 21253887Smckusick rsmctl(dev, RS_ON, DMSET); 21353887Smckusick if (rs_param[unit] & DCD || RS_CARR(unit)) 21453887Smckusick tp->t_state |= TS_CARR_ON; 21553887Smckusick s = spltty(); /* spl5 -> spltty, 90/02/28 sak */ 21653887Smckusick while ((tp->t_state & TS_CARR_ON) == 0) { 21753887Smckusick tp->t_state |= TS_WOPEN; 21853887Smckusick sleep((caddr_t)&tp->t_rawq, TTIPRI); 21953887Smckusick } 22053887Smckusick #ifdef notyet /* KU:XXX */ 22153887Smckusick if (RS_FLAG(unit, RF_FLOWCTL)) { 22253887Smckusick tp->t_state |= TS_HFLWCTL; 22353887Smckusick rsmctl(dev, RS_AUTO_ENABLE, DMBIS); 22453887Smckusick } else { 22553887Smckusick tp->t_state &= ~TS_HFLWCTL; 22653887Smckusick rsmctl(dev, RS_AUTO_ENABLE, DMBIC); 22753887Smckusick } 22853887Smckusick #endif 22953887Smckusick (void) splx(s); 23053887Smckusick return ((*linesw[tp->t_line].l_open)(dev, tp)); 23153887Smckusick } 23253887Smckusick 23353887Smckusick /* 23453887Smckusick * Close a RS line. 23553887Smckusick */ 23653887Smckusick /*ARGSUSED*/ 23753887Smckusick rsclose(dev, flag) 23853887Smckusick dev_t dev; 23953887Smckusick int flag; 24053887Smckusick { 24153887Smckusick register struct tty *tp; 24253887Smckusick register unit; 24353887Smckusick 24453887Smckusick unit = minor(dev); 24553887Smckusick tp = &rs_tty[unit]; 24653887Smckusick (*linesw[tp->t_line].l_close)(tp); 24753887Smckusick (void) rsmctl(unit, RS_BRK, DMBIC); 24853887Smckusick if (tp->t_cflag & HUPCL || (tp->t_state & TS_ISOPEN) == 0) 24953887Smckusick (void) rsmctl(unit, RS_OFF, DMSET); 25053887Smckusick ttyclose(tp); 25153887Smckusick 25253887Smckusick if (RS_FLAG(unit, RF_FLOWCTL)) 25353887Smckusick (void)rsmctl(unit, RS_RTS, DMBIC); 25453887Smckusick } 25553887Smckusick 25653887Smckusick rsread(dev, uio, flag) 25753887Smckusick dev_t dev; 25853887Smckusick struct uio *uio; 25953887Smckusick int flag; 26053887Smckusick { 26153887Smckusick register struct tty *tp; 26253887Smckusick 26353887Smckusick tp = &rs_tty[minor(dev)]; 26453887Smckusick return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 26553887Smckusick } 26653887Smckusick 26753887Smckusick rswrite(dev, uio, flag) 26853887Smckusick dev_t dev; 26953887Smckusick struct uio *uio; 27053887Smckusick int flag; 27153887Smckusick { 27253887Smckusick register struct tty *tp; 27353887Smckusick 27453887Smckusick tp = &rs_tty[minor(dev)]; 27553887Smckusick return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 27653887Smckusick } 27753887Smckusick 27853887Smckusick rsenable(unit) 27953887Smckusick int unit; 28053887Smckusick { 28153887Smckusick 28253887Smckusick rs_timeout[unit] = 0; 28353887Smckusick rs_enable(unit); 28453887Smckusick } 28553887Smckusick 28653887Smckusick /* 28753887Smckusick * RS receiver interrupt. 28853887Smckusick */ 28953887Smckusick _rsrint(unit, buf, n) 29053887Smckusick register int unit; 29153887Smckusick register char *buf; 29253887Smckusick register int n; 29353887Smckusick { 29453887Smckusick register struct iop_device *ii; 29553887Smckusick register struct tty *tp; 29653887Smckusick register int (*rint)(); 29753887Smckusick 29853887Smckusick #ifdef notyet /* KU:XXX */ 29953887Smckusick intrcnt[INTR_RS0 + unit]++; 30053887Smckusick #endif 30153887Smckusick ii = rsinfo[unit >> 2]; 30253887Smckusick if (ii == 0 || ii->ii_alive == 0) 30353887Smckusick return; 30453887Smckusick tp = &rs_tty[unit]; 30553887Smckusick if ((tp->t_state & TS_ISOPEN) == 0) { 30653887Smckusick wakeup((caddr_t)&tp->t_rawq); 30753887Smckusick goto enable; 30853887Smckusick } 30953887Smckusick /* 31053887Smckusick * Loop fetching characters from the silo for this 31153887Smckusick * rs until there are no more in the silo. 31253887Smckusick */ 31353887Smckusick rint = linesw[tp->t_line].l_rint; 31453887Smckusick while (--n >= 0) { 31553887Smckusick #if NBK > 0 31653887Smckusick if (tp->t_line == NETLDISC) { 31753887Smckusick c &= 0177; 31853887Smckusick BKINPUT(c, tp); 31953887Smckusick } else 32053887Smckusick #endif /* NBK > 0 */ 32153887Smckusick (*rint)(*buf++, tp); 32253887Smckusick } 32353887Smckusick enable: 32453887Smckusick rs_rate[unit]++; 32553887Smckusick if (rs_average[unit] >= 10 && RS_FLAG(unit, RF_NODELAY) == 0) { 32653887Smckusick if (rs_timeout[unit] == 0) { 32753887Smckusick rs_timeout[unit] = 1; 32853887Smckusick timeout(rsenable, (caddr_t)unit, hz / 100); 32953887Smckusick } 33053887Smckusick } else 33153887Smckusick rs_enable(unit); 33253887Smckusick } 33353887Smckusick 33453887Smckusick /*ARGSUSED*/ 33553887Smckusick rsioctl(dev, cmd, data, flag) 33653887Smckusick dev_t dev; 33753887Smckusick caddr_t data; 33853887Smckusick { 33953887Smckusick register struct tty *tp; 34053887Smckusick register int unit = minor(dev); 34153887Smckusick int error; 34253887Smckusick 34353887Smckusick tp = &rs_tty[unit]; 34453887Smckusick error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 34553887Smckusick if (error >= 0) 34653887Smckusick return (error); 34753887Smckusick error = ttioctl(tp, cmd, data, flag); 34853887Smckusick if (error >= 0) 34953887Smckusick return (error); 35053887Smckusick 35153887Smckusick switch (cmd) { 35253887Smckusick 35353887Smckusick case TIOCSBRK: 35453887Smckusick (void) rsmctl(dev, RS_BRK, DMBIS); 35553887Smckusick break; 35653887Smckusick 35753887Smckusick case TIOCCBRK: 35853887Smckusick (void) rsmctl(dev, RS_BRK, DMBIC); 35953887Smckusick break; 36053887Smckusick 36153887Smckusick case TIOCSDTR: 36253887Smckusick (void) rsmctl(dev, RS_DTR|RS_RTS, DMBIS); 36353887Smckusick break; 36453887Smckusick 36553887Smckusick case TIOCCDTR: 36653887Smckusick if (curproc->p_ucred->cr_uid && 36753887Smckusick curproc->p_session->s_ttyp != tp) 36853887Smckusick return (EACCES); 36953887Smckusick (void) rsmctl(dev, RS_DTR|RS_RTS, DMBIC); 37053887Smckusick break; 37153887Smckusick 37253887Smckusick case TIOCMSET: 37353887Smckusick (void) rsmctl(dev, dmtors(*(int *)data), DMSET); 37453887Smckusick break; 37553887Smckusick 37653887Smckusick case TIOCMBIS: 37753887Smckusick (void) rsmctl(dev, dmtors(*(int *)data), DMBIS); 37853887Smckusick break; 37953887Smckusick 38053887Smckusick case TIOCMBIC: 38153887Smckusick (void) rsmctl(dev, dmtors(*(int *)data), DMBIC); 38253887Smckusick break; 38353887Smckusick 38453887Smckusick case TIOCMGET: 38553887Smckusick *(int *)data = rstodm(rsmctl(dev, 0, DMGET)); 38653887Smckusick break; 38753887Smckusick 38853887Smckusick default: 38953887Smckusick return (ENOTTY); 39053887Smckusick } 39153887Smckusick return (0); 39253887Smckusick } 39353887Smckusick 39453887Smckusick dmtors(bits) 39553887Smckusick register int bits; 39653887Smckusick { 39753887Smckusick register int b; 39853887Smckusick 39953887Smckusick b = 0; 40053887Smckusick if (bits & DML_LE) b |= RS_TXE|RS_RXE; 40153887Smckusick if (bits & DML_DTR) b |= RS_DTR; 40253887Smckusick if (bits & DML_RTS) b |= RS_RTS; 40353887Smckusick if (bits & DML_CTS) b |= RS_CTS; 40453887Smckusick if (bits & DML_CAR) b |= RS_DCD; 40553887Smckusick if (bits & DML_RNG) b |= RS_RI; 40653887Smckusick if (bits & DML_DSR) b |= RS_DSR; 40753887Smckusick #ifdef AUTO_ENABLE 40853887Smckusick if (bits & DML_USR) b |= RS_AUTO_ENABLE; 40953887Smckusick #endif /* AUTO_ENABLE */ 41053887Smckusick return(b); 41153887Smckusick } 41253887Smckusick 41353887Smckusick rstodm(bits) 41453887Smckusick register int bits; 41553887Smckusick { 41653887Smckusick register int b; 41753887Smckusick 41853887Smckusick b = 0; 41953887Smckusick if (bits & (RS_TXE|RS_RXE)) b |= DML_LE; 42053887Smckusick if (bits & RS_DTR) b |= DML_DTR; 42153887Smckusick if (bits & RS_RTS) b |= DML_RTS; 42253887Smckusick if (bits & RS_CTS) b |= DML_CTS; 42353887Smckusick if (bits & RS_DCD) b |= DML_CAR; 42453887Smckusick if (bits & RS_RI) b |= DML_RNG; 42553887Smckusick if (bits & RS_DSR) b |= DML_DSR; 42653887Smckusick #ifdef AUTO_ENABLE 42753887Smckusick if (bits & RS_AUTO_ENABLE) b |= DML_USR; 42853887Smckusick #endif 42953887Smckusick return(b); 43053887Smckusick } 43153887Smckusick 43253887Smckusick /* 43353887Smckusick * compat table 43453887Smckusick */ 43553887Smckusick struct speedtab rsspeedtab[] = { 43653887Smckusick 0, 0, 43753887Smckusick 50, 1, 43853887Smckusick 75, 2, 43953887Smckusick 110, 3, 44053887Smckusick 134, 4, 44153887Smckusick 150, 5, 44253887Smckusick 200, 6, 44353887Smckusick 300, 7, 44453887Smckusick 600, 8, 44553887Smckusick 1200, 9, 44653887Smckusick 1800, 10, 44753887Smckusick 2400, 11, 44853887Smckusick 4800, 12, 44953887Smckusick 9600, 13, 45053887Smckusick 19200, 14, 45153887Smckusick 38400, 15, 45253887Smckusick -1, -1 45353887Smckusick }; 45453887Smckusick 45553887Smckusick /* 45653887Smckusick * Set parameters from open or stty into the RS hardware 45753887Smckusick * registers. 45853887Smckusick */ 45953887Smckusick rsparam(tp, t) 46053887Smckusick register struct tty *tp; 46153887Smckusick register struct termios *t; 46253887Smckusick { 46353887Smckusick register int param; 46453887Smckusick register int cflag = t->c_cflag; 46553887Smckusick int unit = minor(tp->t_dev); 46653887Smckusick int s; 46753887Smckusick int ospeed = ttspeedtab(t->c_ospeed, rsspeedtab); 46853887Smckusick 46953887Smckusick /* check requested parameters */ 47053887Smckusick if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed) || 47153887Smckusick (cflag & CSIZE) == CS5 || (cflag & CSIZE) == CS6) 47253887Smckusick return (EINVAL); 47353887Smckusick /* and copy to tty */ 47453887Smckusick tp->t_ispeed = t->c_ispeed; 47553887Smckusick tp->t_ospeed = t->c_ospeed; 47653887Smckusick tp->t_cflag = cflag; 47753887Smckusick 47853887Smckusick /* 47953887Smckusick * Block interrupts so parameters will be set 48053887Smckusick * before the line interrupts. 48153887Smckusick */ 48253887Smckusick s = spltty(); 48353887Smckusick if (tp->t_ospeed == 0) { 48453887Smckusick tp->t_cflag |= HUPCL; 48553887Smckusick (void) rsmctl(unit, RS_OFF, DMSET); 48653887Smckusick (void) splx(s); 48753887Smckusick return (0); 48853887Smckusick } 48953887Smckusick 49053887Smckusick param = rs_get_param(unit) & 49153887Smckusick ~(CHAR_SIZE|PARITY|EVEN|STOPBIT|BAUD_RATE|NOCHECK); 49253887Smckusick if ((cflag & CREAD) == 0) 49353887Smckusick param &= ~RXE; 49453887Smckusick if (cflag & CS6) 49553887Smckusick param |= C6BIT; 49653887Smckusick if (cflag & CS7) 49753887Smckusick param |= C7BIT; 49853887Smckusick if (cflag & PARENB) 49953887Smckusick param |= PARITY; 50053887Smckusick if ((cflag & PARODD) == 0) 50153887Smckusick param |= EVEN; 50253887Smckusick if ((tp->t_iflag & INPCK) == 0) 50353887Smckusick param |= NOCHECK; 50453887Smckusick if (cflag & CSTOPB) 50553887Smckusick param |= STOP2; 50653887Smckusick else 50753887Smckusick param |= STOP1; 50853887Smckusick 50953887Smckusick rs_param[unit] = param | ospeed; 51053887Smckusick 51153887Smckusick if (RS_FLAG(unit, RF_EXTCLK)) 51253887Smckusick rs_param[unit] |= EXTCLK_ENABLE; 51353887Smckusick else 51453887Smckusick rs_param[unit] &= ~EXTCLK_ENABLE; 51553887Smckusick rs_set_param(unit, rs_param[unit]); 51653887Smckusick (void) splx(s); 51753887Smckusick 51853887Smckusick return (0); 51953887Smckusick } 52053887Smckusick 52153887Smckusick /* 52253887Smckusick * RS transmitter interrupt. 52353887Smckusick * Restart the idle line. 52453887Smckusick */ 52553887Smckusick _rsxint(unit, count) 52653887Smckusick int unit; 52753887Smckusick int count; 52853887Smckusick { 52953887Smckusick register struct tty *tp; 53053887Smckusick register int s; 53153887Smckusick 53253887Smckusick #ifdef notyet /* KU:XXX */ 53353887Smckusick intrcnt[INTR_RS0 + unit]++; 53453887Smckusick #endif 53553887Smckusick rs_stopped[unit] = 0; 53653887Smckusick tp = &rs_tty[unit]; 53753887Smckusick tp->t_state &= ~TS_BUSY; 53853887Smckusick s = spltty(); 53953887Smckusick if (tp->t_state & TS_FLUSH) 54053887Smckusick tp->t_state &= ~TS_FLUSH; 54153887Smckusick else 54253887Smckusick ndflush(&tp->t_outq, count); 54353887Smckusick (void) splx(s); 54453887Smckusick if (tp->t_line) 54553887Smckusick (*linesw[tp->t_line].l_start)(tp); 54653887Smckusick else 54753887Smckusick rsstart(tp); 54853887Smckusick } 54953887Smckusick 55053887Smckusick /* 55153887Smckusick * Start (restart) transmission on the given RS line. 55253887Smckusick */ 55353887Smckusick void 55453887Smckusick rsstart(tp) 55553887Smckusick register struct tty *tp; 55653887Smckusick { 55753887Smckusick register int unit, nch; 55853887Smckusick int s; 55953887Smckusick 56053887Smckusick unit = minor(tp->t_dev); 56153887Smckusick 56253887Smckusick /* 56353887Smckusick * Must hold interrupts in following code to prevent 56453887Smckusick * state of the tp from changing. 56553887Smckusick */ 56653887Smckusick s = spltty(); 56753887Smckusick /* 56853887Smckusick * If it's currently active, or delaying, no need to do anything. 56953887Smckusick */ 57053887Smckusick if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 57153887Smckusick goto out; 57253887Smckusick /* 57353887Smckusick * If ther are still characters in the IOP, 57453887Smckusick * just reenable transmit. 57553887Smckusick */ 57653887Smckusick if (rs_stopped[unit]) { 57753887Smckusick rs_start(unit); 57853887Smckusick rs_stopped[unit] = 0; 57953887Smckusick goto out; 58053887Smckusick } 58153887Smckusick /* 58253887Smckusick * If there are sleepers, and output has drained below low 58353887Smckusick * water mark, wake up the sleepers. 58453887Smckusick */ 58553887Smckusick if (tp->t_outq.c_cc <= tp->t_lowat) { 58653887Smckusick if (tp->t_state & TS_ASLEEP) { 58753887Smckusick tp->t_state &= ~TS_ASLEEP; 58853887Smckusick wakeup((caddr_t)&tp->t_outq); 58953887Smckusick } 59053887Smckusick selwakeup(&tp->t_wsel); 59153887Smckusick } 59253887Smckusick /* 59353887Smckusick * Now restart transmission unless the output queue is 59453887Smckusick * empty. 59553887Smckusick */ 59653887Smckusick if (tp->t_outq.c_cc == 0) 59753887Smckusick goto out; 59853887Smckusick if (tp->t_flags & (RAW|LITOUT)) 59953887Smckusick nch = ndqb(&tp->t_outq, 0); 60053887Smckusick else { 60153887Smckusick nch = ndqb(&tp->t_outq, 0200); 60253887Smckusick /* 60353887Smckusick * If first thing on queue is a delay process it. 60453887Smckusick */ 60553887Smckusick if (nch == 0) { 60653887Smckusick nch = getc(&tp->t_outq); 60753887Smckusick timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 60853887Smckusick tp->t_state |= TS_TIMEOUT; 60953887Smckusick goto out; 61053887Smckusick } 61153887Smckusick } 61253887Smckusick /* 61353887Smckusick * If characters to transmit, restart transmission. 61453887Smckusick */ 61553887Smckusick if (nch) { 61653887Smckusick tp->t_state |= TS_BUSY; 61753887Smckusick rs_output(unit, nch); 61853887Smckusick } 61953887Smckusick out: 62053887Smckusick (void) splx(s); 62153887Smckusick } 62253887Smckusick 62353887Smckusick /* 62453887Smckusick * Stop output on a line, e.g. for ^S/^Q or output flush. 62553887Smckusick */ 62653887Smckusick /*ARGSUSED*/ 62753887Smckusick rsstop(tp, flag) 62853887Smckusick register struct tty *tp; 62953887Smckusick { 63053887Smckusick register int unit, s; 63153887Smckusick 63253887Smckusick unit = minor(tp->t_dev); 63353887Smckusick s = spltty(); 63453887Smckusick if (tp->t_state & TS_BUSY) { 63553887Smckusick rs_stop(unit, 0); 63653887Smckusick rs_stopped[unit] = 1; 63753887Smckusick if ((tp->t_state & TS_TTSTOP) == 0) { 63853887Smckusick tp->t_state |= TS_FLUSH; 63953887Smckusick rs_stop(unit, 1); 64053887Smckusick } 64153887Smckusick } 64253887Smckusick (void) splx(s); 64353887Smckusick } 64453887Smckusick 64553887Smckusick /* 64653887Smckusick * RS modem control 64753887Smckusick */ 64853887Smckusick rsmctl(dev, bits, how) 64953887Smckusick dev_t dev; 65053887Smckusick int bits, how; 65153887Smckusick { 65253887Smckusick register int unit, mbits; 65353887Smckusick int s; 65453887Smckusick 65553887Smckusick #ifdef AUTO_ENABLE 65653887Smckusick bits &= (RS_RXE|RS_TXE|RS_RTS|RS_DTR|RS_BRK|RS_AUTO_ENABLE); 65753887Smckusick #else 65853887Smckusick bits &= (RS_RXE|RS_TXE|RS_RTS|RS_DTR|RS_BRK); 65953887Smckusick #endif 66053887Smckusick 66153887Smckusick unit = minor(dev); 66253887Smckusick s = spltty(); /* spl5 -> spltty, 90/02/28 sak */ 66353887Smckusick 66453887Smckusick mbits = rs_get_param(unit); 66553887Smckusick switch (how) { 66653887Smckusick 66753887Smckusick case DMSET: 66853887Smckusick mbits = mbits & ~(RS_RXE|RS_TXE|RS_RTS|RS_DTR|RS_BRK) | bits; 66953887Smckusick break; 67053887Smckusick 67153887Smckusick case DMBIS: 67253887Smckusick mbits |= bits; 67353887Smckusick break; 67453887Smckusick 67553887Smckusick case DMBIC: 67653887Smckusick mbits &= ~bits; 67753887Smckusick break; 67853887Smckusick 67953887Smckusick case DMGET: 68053887Smckusick (void) splx(s); 68153887Smckusick return(mbits); 68253887Smckusick } 68353887Smckusick rs_param[unit] = mbits; 68453887Smckusick rs_set_param(unit, rs_param[unit]); 68553887Smckusick 68653887Smckusick (void) splx(s); 68753887Smckusick return(mbits); 68853887Smckusick } 68953887Smckusick 69053887Smckusick /* 69153887Smckusick * Reset state of driver if IOP reset was necessary. 69253887Smckusick * Reset the parameter and status, and 69353887Smckusick * restart transmitters. 69453887Smckusick */ 69553887Smckusick rsreset() 69653887Smckusick { 69753887Smckusick register int unit; 69853887Smckusick register struct tty *tp; 69953887Smckusick register struct iop_device *ii; 70053887Smckusick 70153887Smckusick for (unit = 0; unit < NRS * 4; unit++) { 70253887Smckusick ii = rsinfo[unit >> 2]; 70353887Smckusick if (ii == 0 || ii->ii_alive == 0) 70453887Smckusick continue; 70553887Smckusick printf(" rs%d", unit); 70653887Smckusick tp = &rs_tty[unit]; 70753887Smckusick if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 70853887Smckusick rs_reset(unit); 70953887Smckusick rsparam(tp, &tp->t_termios); 71053887Smckusick (void) rsmctl(unit, RS_ON, DMSET); 71153887Smckusick tp->t_state &= ~TS_BUSY; 71253887Smckusick rsstart(tp); 71353887Smckusick } 71453887Smckusick } 71553887Smckusick } 71653887Smckusick 71753887Smckusick /* 71853887Smckusick * RS status interrupt 71953887Smckusick */ 72053887Smckusick _rssint(unit, stat) 72153887Smckusick int unit; 72253887Smckusick int stat; 72353887Smckusick { 72453887Smckusick register struct tty *tp; 72553887Smckusick 72653887Smckusick #ifdef notyet /* KU:XXX */ 72753887Smckusick intrcnt[INTR_RS0 + unit]++; 72853887Smckusick #endif 72953887Smckusick tp = &rs_tty[unit]; 73053887Smckusick if (stat & RS_DCD) { 73153887Smckusick rs_param[unit] |= RS_DCD; 73253887Smckusick (void)(*linesw[tp->t_line].l_modem)(tp, 1); 73353887Smckusick } else if (RS_CARR(unit) == 0 && 73453887Smckusick (*linesw[tp->t_line].l_modem)(tp, 0) == 0) { 73553887Smckusick rs_param[unit] &= ~(RS_DCD | RS_DTR); 73653887Smckusick rs_set_param(unit, rs_param[unit]); 73753887Smckusick } 73853887Smckusick if (stat & OVERRUN_ERROR) { 73953887Smckusick printf("rs%d: fifo overflow\n", unit); 74053887Smckusick rs_param[unit] &= ~OVERRUN_ERROR; 74153887Smckusick rs_set_param(unit, rs_param[unit]); 74253887Smckusick } 74353887Smckusick if (stat & RBREAK) { 74453887Smckusick rs_param[unit] &= ~RBREAK; 74553887Smckusick if (tp->t_state & TS_ISOPEN) 74653887Smckusick (*linesw[tp->t_line].l_rint) 74753887Smckusick (tp->t_flags & RAW ? '\0' : tp->t_cc[VINTR], tp); 74853887Smckusick } 74953887Smckusick } 75053887Smckusick 75153887Smckusick /* 75253887Smckusick * RS control interrupt 75353887Smckusick */ 75453887Smckusick rscint(rs) 75553887Smckusick int rs; 75653887Smckusick { 75753887Smckusick 75853887Smckusick printf("rscint: %d\n", rs); 75953887Smckusick } 76053887Smckusick 76153887Smckusick /* 76253887Smckusick * RS H/W control 76353887Smckusick */ 76453887Smckusick void 76553887Smckusick rsctrl(tp, cmd, arg) 76653887Smckusick struct tty *tp; 76753887Smckusick int cmd; 76853887Smckusick int arg; 76953887Smckusick { 77053887Smckusick #ifdef notyet /* KU:XXX */ 77153887Smckusick int unit = minor(tp->t_dev); 77253887Smckusick 77353887Smckusick switch (cmd) { 77453887Smckusick 77553887Smckusick case TC_HBLOCK: 77653887Smckusick if (RS_FLAG(unit, RF_FLOWCTL)) 77753887Smckusick rsflowctl(unit, arg); 77853887Smckusick break; 77953887Smckusick 78053887Smckusick default: 78153887Smckusick break; 78253887Smckusick } 78353887Smckusick 78453887Smckusick return (0); 78553887Smckusick #endif 78653887Smckusick } 78753887Smckusick 78853887Smckusick rsflowctl(unit, block) 78953887Smckusick int unit; 79053887Smckusick int block; 79153887Smckusick { 79253887Smckusick int s; 79353887Smckusick 79453887Smckusick s = spltty(); 79553887Smckusick if (block) 79653887Smckusick rs_param[unit] &= ~RS_RTS; 79753887Smckusick else 79853887Smckusick rs_param[unit] |= RS_RTS; 79953887Smckusick rs_set_param(unit, rs_param[unit]); 80053887Smckusick (void) splx(s); 80153887Smckusick } 80253887Smckusick 80353887Smckusick /* 80453887Smckusick * Machine dependent functions 80553887Smckusick * 80653887Smckusick * rs_probe() 80753887Smckusick * rs_init() 80853887Smckusick * rsrint() 80953887Smckusick * rsxint() 81053887Smckusick * rssint() 81153887Smckusick * rs_enable() 81253887Smckusick * rs_output() 81353887Smckusick * rs_start() 81453887Smckusick * rs_stop() 81553887Smckusick * rs_reset() 81653887Smckusick * rs_get_param() 81753887Smckusick * rs_set_param() 81853887Smckusick */ 81953887Smckusick #ifdef CPU_SINGLE 820*57183Sutashiro #include <news3400/hbdev/hbvar.h> 821*57183Sutashiro #include <news3400/hbdev/rsreg.h> 822*57183Sutashiro #include <news3400/sio/scc.h> 82353887Smckusick 82453887Smckusick int rslastcount[NRS*4]; 82553887Smckusick int scc_unit[] = { 0, 1, -1, -1, 2, 3, 4, 5, 6, 7, 8, 9 }; 82653887Smckusick int rs_unit[] = { 0, 1, 4, 5, 6, 7, 8, 9, 10, 11 }; 82753887Smckusick 82853887Smckusick rs_probe(hi) 82953887Smckusick struct hb_device *hi; 83053887Smckusick { 83153887Smckusick register int i, cmax; 83253887Smckusick 83353887Smckusick for (i = (hi->hi_unit << 2), cmax = 4; cmax > 0; cmax--, i++) { 83453887Smckusick if (i == 2 || i == 3) 83553887Smckusick continue; 83653887Smckusick if (scc_probe(scc_unit[i])) 83753887Smckusick continue; 83853887Smckusick return (0); 83953887Smckusick } 84053887Smckusick return (1); 84153887Smckusick } 84253887Smckusick 84353887Smckusick rs_init(unit) 84453887Smckusick int unit; 84553887Smckusick { 84653887Smckusick 84753887Smckusick if (scc_open(scc_unit[unit])) { 84853887Smckusick printf("rs_init: chan %d open failed.\n", scc_unit[unit]); 84953887Smckusick return (-1); 85053887Smckusick } 85153887Smckusick return (0); 85253887Smckusick } 85353887Smckusick 85453887Smckusick rs_enable(unit) 85553887Smckusick int unit; 85653887Smckusick { 85753887Smckusick 85853887Smckusick scc_enable(scc_unit[unit]); 85953887Smckusick } 86053887Smckusick 86153887Smckusick rsrint(scc, buf, cnt) 86253887Smckusick int scc; 86353887Smckusick char *buf; 86453887Smckusick int cnt; 86553887Smckusick { 86653887Smckusick 86753887Smckusick _rsrint(rs_unit[scc], buf, cnt); 86853887Smckusick } 86953887Smckusick 87053887Smckusick rsxint(scc) 87153887Smckusick int scc; 87253887Smckusick { 87353887Smckusick int unit = rs_unit[scc]; 87453887Smckusick 87553887Smckusick _rsxint(unit, rslastcount[unit]); 87653887Smckusick } 87753887Smckusick 87853887Smckusick rssint(scc, stat) 87953887Smckusick int scc; 88053887Smckusick int stat; 88153887Smckusick { 88253887Smckusick 88353887Smckusick _rssint(rs_unit[scc], stat); 88453887Smckusick } 88553887Smckusick 88653887Smckusick rs_start(unit) 88753887Smckusick int unit; 88853887Smckusick { 88953887Smckusick 89053887Smckusick scc_start(scc_unit[unit]); 89153887Smckusick } 89253887Smckusick 89353887Smckusick rs_output(unit, n) 89453887Smckusick int unit; 89553887Smckusick int n; 89653887Smckusick { 89753887Smckusick 89853887Smckusick rslastcount[unit] = 89953887Smckusick scc_write(scc_unit[unit], rs_tty[unit].t_outq.c_cf, n); 90053887Smckusick } 90153887Smckusick 90253887Smckusick rs_stop(unit, flush) 90353887Smckusick int unit; 90453887Smckusick int flush; 90553887Smckusick { 90653887Smckusick 90753887Smckusick if (flush) 90853887Smckusick scc_flush(scc_unit[unit]); 90953887Smckusick } 91053887Smckusick 91153887Smckusick rs_reset(unit) 91253887Smckusick int unit; 91353887Smckusick { 91453887Smckusick 91553887Smckusick scc_reset(scc_unit[unit]); 91653887Smckusick } 91753887Smckusick 91853887Smckusick rs_get_param(unit) 91953887Smckusick int unit; 92053887Smckusick { 92153887Smckusick 92253887Smckusick return (scc_get_param(scc_unit[unit])); 92353887Smckusick } 92453887Smckusick 92553887Smckusick rs_set_param(unit, param) 92653887Smckusick int unit; 92753887Smckusick int param; 92853887Smckusick { 92953887Smckusick 93053887Smckusick scc_set_param(scc_unit[unit], param); 93153887Smckusick } 93253887Smckusick #endif /* CPU_SINGLE */ 93353887Smckusick 93453887Smckusick #ifdef IPC_MRX 93553887Smckusick #include "../ipc/newsipc.h" 93653887Smckusick #include "../mrx/h/scc.h" 93753887Smckusick #include "../mrx/h/cio.h" 93853887Smckusick 93953887Smckusick int port_rsrecv[NRS*4]; 94053887Smckusick int port_rsxmit[NRS*4]; 94153887Smckusick int port_rsstat[NRS*4]; 94253887Smckusick int port_rsctrl[NRS*4]; 94353887Smckusick int port_recv_iop[NRS*4]; 94453887Smckusick int port_xmit_iop[NRS*4]; 94553887Smckusick int port_ctrl_iop[NRS*4]; 94653887Smckusick int port_stat_iop[NRS*4]; 94753887Smckusick 94853887Smckusick /* 94953887Smckusick * minor No: 0 - 12 ----> SCC unit No : 0 - 9 95053887Smckusick */ 95153887Smckusick int scc_unit[] = { 1, 0, -1, -1, 3, 2, 5, 4, 7, 6, 9, 8 }; 95253887Smckusick 95353887Smckusick rs_probe(ii) 95453887Smckusick struct iop_device *ii; 95553887Smckusick { 95653887Smckusick register int base = ii->ii_unit << 2; 95753887Smckusick register int i, j; 95853887Smckusick char buf[16]; 95953887Smckusick 96053887Smckusick #define PT_CREATE(buf, name, unit, func, arg) \ 96153887Smckusick port_create(make_name(buf, name, unit), func, arg) 96253887Smckusick #define OB_QUERY(buf, name, unit) \ 96353887Smckusick object_query(make_name(buf, name, unit)) 96453887Smckusick for (i = base; i < base+4; i++) { 96553887Smckusick if ((j = scc_unit[i]) < 0) 96653887Smckusick continue; 96753887Smckusick port_recv_iop[i] = OB_QUERY(buf, "scc_inputX", j); 96853887Smckusick if (port_recv_iop[i] <= 0) 96953887Smckusick return (0); 97053887Smckusick port_xmit_iop[i] = OB_QUERY(buf, "scc_outputX", j); 97153887Smckusick port_ctrl_iop[i] = OB_QUERY(buf, "scc_ctrlX", j); 97253887Smckusick port_stat_iop[i] = OB_QUERY(buf, "scc_statX", j); 97353887Smckusick 97453887Smckusick port_rsrecv[i] = PT_CREATE(buf, "@rsrecvX", j, rsrint, i); 97553887Smckusick port_rsxmit[i] = PT_CREATE(buf, "@rsxmitX", j, rsxint, i); 97653887Smckusick port_rsctrl[i] = PT_CREATE(buf, "@rsctrlX", j, NULL, 0); 97753887Smckusick port_rsstat[i] = PT_CREATE(buf, "@rsstatX", j, rssint, i); 97853887Smckusick } 97953887Smckusick return (1); 98053887Smckusick } 98153887Smckusick 98253887Smckusick rs_init(unit) 98353887Smckusick int unit; 98453887Smckusick { 98553887Smckusick int len; 98653887Smckusick 98753887Smckusick msg_send(port_stat_iop[unit], port_rsstat[unit], NULL, 0, 0); 98853887Smckusick return (0); 98953887Smckusick } 99053887Smckusick 99153887Smckusick rs_enable(unit) 99253887Smckusick int unit; 99353887Smckusick { 99453887Smckusick int len; 99553887Smckusick 99653887Smckusick len = MAX_CIO; 99753887Smckusick msg_send(port_recv_iop[unit], port_rsrecv[unit], &len, sizeof(len), 0); 99853887Smckusick } 99953887Smckusick 100053887Smckusick rsrint(unit) 100153887Smckusick register int unit; 100253887Smckusick { 100353887Smckusick char *addr; 100453887Smckusick int from, len; 100553887Smckusick 100653887Smckusick msg_recv(port_rsrecv[unit], &from, &addr, &len, 0); 100753887Smckusick #ifdef mips 100853887Smckusick clean_dcache(addr, len + 8); 100953887Smckusick #endif 101053887Smckusick _rsrint(unit, addr, len); 101153887Smckusick } 101253887Smckusick 101353887Smckusick rsxint(unit) 101453887Smckusick register int unit; 101553887Smckusick { 101653887Smckusick int from, *len; 101753887Smckusick 101853887Smckusick msg_recv(port_rsxmit[unit], &from, &len, NULL, 0); 101953887Smckusick _rsxint(unit, *len); 102053887Smckusick } 102153887Smckusick 102253887Smckusick rssint(unit) 102353887Smckusick register int unit; 102453887Smckusick { 102553887Smckusick int from, *reply; 102653887Smckusick 102753887Smckusick msg_recv(port_rsstat[unit], &from, &reply, NULL, 0); 102853887Smckusick _rssint(unit, *reply); 102953887Smckusick msg_send(from, port_rsstat[unit], NULL, 0, 0); 103053887Smckusick } 103153887Smckusick 103253887Smckusick rs_start(unit) 103353887Smckusick int unit; 103453887Smckusick { 103553887Smckusick int func; 103653887Smckusick 103753887Smckusick func = CIO_START; 103853887Smckusick msg_send(port_ctrl_iop[unit], 0, &func, sizeof(func), 0); 103953887Smckusick } 104053887Smckusick 104153887Smckusick rs_output(unit, n) 104253887Smckusick int unit; 104353887Smckusick int n; 104453887Smckusick { 104553887Smckusick 104653887Smckusick msg_send(port_xmit_iop[unit], port_rsxmit[unit], 104755766Sbostic rs_tty[unit].t_outq.c_cf, min(n, MAX_CIO), 0); 104853887Smckusick } 104953887Smckusick 105053887Smckusick rs_stop(unit, flush) 105153887Smckusick int unit; 105253887Smckusick int flush; 105353887Smckusick { 105453887Smckusick int func; 105553887Smckusick 105653887Smckusick func = flush ? CIO_FLUSH : CIO_STOP; 105753887Smckusick msg_send(port_ctrl_iop[unit], 0, &func, sizeof(func), 0); 105853887Smckusick } 105953887Smckusick 106053887Smckusick rs_reset(unit) 106153887Smckusick int unit; 106253887Smckusick { 106353887Smckusick int func; 106453887Smckusick 106553887Smckusick func = CIO_RESET; 106653887Smckusick msg_send(port_ctrl_iop[unit], 0, &func, sizeof(func), 0); 106753887Smckusick } 106853887Smckusick 106953887Smckusick rs_get_param(unit) 107053887Smckusick register int unit; 107153887Smckusick { 107253887Smckusick register int port; 107353887Smckusick struct scc_ctrl_req req; 107453887Smckusick int param, *reply; 107553887Smckusick 107653887Smckusick port = port_rsctrl[unit]; 107753887Smckusick req.scc_func = CIO_GETPARAMS; 107853887Smckusick 107953887Smckusick /* message length 8 means 2 * sizeof(int) : func and status */ 108053887Smckusick msg_send(port_ctrl_iop[unit], port, &req, 8, 0); 108153887Smckusick msg_recv(port, NULL, &reply, NULL, 0); 108253887Smckusick 108353887Smckusick param = *reply; 108453887Smckusick msg_free(port); 108553887Smckusick 108653887Smckusick return (param); 108753887Smckusick } 108853887Smckusick 108953887Smckusick rs_set_param(unit, param) 109053887Smckusick register int unit; 109153887Smckusick int param; 109253887Smckusick { 109353887Smckusick struct scc_ctrl_req req; 109453887Smckusick 109553887Smckusick req.scc_func = CIO_SETPARAMS; 109653887Smckusick req.scc_arg = param; 109753887Smckusick 109853887Smckusick /* message length 8 means 2 * sizeof(int) : func and param */ 109953887Smckusick msg_send(port_ctrl_iop[unit], 0, &req, 8, 0); 110053887Smckusick } 110153887Smckusick #endif /* IPC_MRX */ 110253887Smckusick #endif /* NRS > 0 */ 1103