📄 rs232.c
字号:
switch (tp->tty_termios.c_cflag & CSIZE) { /* XXX - are U_Dn like CSn? */ case CS5: line_controls |= U_D5; break; case CS5: line_controls |= U_D6; break; case CS5: line_controls |= U_D7; break; case CS5: line_controls |= U_D8; break; } lock(); MFP->mf_ucr = line_controls; MFP->mf_tddr = divisor; unlock();#endif /* MACHINE == ATARI */}/*===========================================================================* * rs_init * *===========================================================================*/PUBLIC void rs_init(tp)tty_t *tp; /* which TTY */{ int dummy;/* Initialize RS232 for one line. */ register rs232_t *rs; int line;#if (MACHINE == IBM_PC) port_t this_8250; int irq; long v;#endif /* Associate RS232 and TTY structures. */ line = tp - &tty_table[NR_CONS]; rs = tp->tty_priv = &rs_lines[line]; rs->tty = tp; /* Set up input queue. */ rs->ihead = rs->itail = rs->ibuf;#if (MACHINE == IBM_PC) /* Precalculate port numbers for speed. Magic numbers in the code (once). */ this_8250 = addr_8250[line]; rs->xmit_port = this_8250 + 0; rs->recv_port = this_8250 + 0; rs->div_low_port = this_8250 + 0; rs->div_hi_port = this_8250 + 1; rs->int_enab_port = this_8250 + 1; rs->int_id_port = this_8250 + 2; rs->line_ctl_port = this_8250 + 3; rs->modem_ctl_port = this_8250 + 4; rs->line_status_port = this_8250 + 5; rs->modem_status_port = this_8250 + 6;#endif /* Set up the hardware to a base state, in particular * o turn off DTR (MC_DTR) to try to stop the external device. * o be careful about the divisor latch. Some BIOS's leave it enabled * here and that caused trouble (no interrupts) in version 1.5 by * hiding the interrupt enable port in the next step, and worse trouble * (continual interrupts) in an old version by hiding the receiver * port in the first interrupt. Call rs_ioctl() early to avoid this. * o disable interrupts at the chip level, to force an edge transition * on the 8259 line when interrupts are next enabled and active. * RS232 interrupts are guaranteed to be disabled now by the 8259 * mask, but there used to be trouble if the mask was set without * handling a previous interrupt. */ istop(rs); /* sets modem_ctl_port */ rs_config(rs);#if (MACHINE == IBM_PC) sys_outb(rs->int_enab_port, 0);#endif /* Clear any harmful leftover interrupts. An output interrupt is harmless * and will occur when interrupts are enabled anyway. Set up the output * queue using the status from clearing the modem status interrupt. */#if (MACHINE == IBM_PC) sys_inb(rs->line_status_port, &dummy); sys_inb(rs->recv_port, &dummy);#endif rs->ostate = devready(rs) | ORAW | OSWREADY; /* reads modem_ctl_port */ rs->ohead = rs->otail = rs->obuf;#if (MACHINE == IBM_PC) /* Enable interrupts for both interrupt controller and device. */ irq = (line & 1) == 0 ? RS232_IRQ : SECONDARY_IRQ; rs->irq = irq; rs->irq_hook_id = rs->irq; /* call back with irq line number */ if (sys_irqsetpolicy(irq, IRQ_REENABLE, &rs->irq_hook_id) != OK) { printf("RS232: Couldn't obtain hook for irq %d\n", irq); } else { if (sys_irqenable(&rs->irq_hook_id) != OK) { printf("RS232: Couldn't enable irq %d (hooked)\n", irq); } } rs_irq_set |= (1 << irq); sys_outb(rs->int_enab_port, IE_LINE_STATUS_CHANGE | IE_MODEM_STATUS_CHANGE | IE_RECEIVER_READY | IE_TRANSMITTER_READY);#else /* MACHINE == ATARI */ /* Initialize the 68901 chip, then enable interrupts. */ MFP->mf_scr = 0x00; MFP->mf_tcdcr |= T_Q004; MFP->mf_rsr = R_ENA; MFP->mf_tsr = T_ENA; MFP->mf_aer = (MFP->mf_aer | (IO_SCTS|IO_SDCD)) ^ (MFP->mf_gpip & (IO_SCTS|IO_SDCD)); MFP->mf_ddr = (MFP->mf_ddr & ~ (IO_SCTS|IO_SDCD)); MFP->mf_iera |= (IA_RRDY|IA_RERR|IA_TRDY|IA_TERR); MFP->mf_imra |= (IA_RRDY|IA_RERR|IA_TRDY|IA_TERR); MFP->mf_ierb |= (IB_SCTS|IB_SDCD); MFP->mf_imrb |= (IB_SCTS|IB_SDCD);#endif /* MACHINE == ATARI */ /* Fill in TTY function hooks. */ tp->tty_devread = rs_read; tp->tty_devwrite = rs_write; tp->tty_echo = rs_echo; tp->tty_icancel = rs_icancel; tp->tty_ocancel = rs_ocancel; tp->tty_ioctl = rs_ioctl; tp->tty_break = rs_break; tp->tty_close = rs_close; /* Tell external device we are ready. */ istart(rs);}/*===========================================================================* * rs_interrupt * *===========================================================================*/PUBLIC void rs_interrupt(m)message *m; /* which TTY */{ unsigned long irq_set; int i; rs232_t *rs; irq_set= m->NOTIFY_ARG; for (i= 0, rs = rs_lines; i<NR_RS_LINES; i++, rs++) { if (irq_set & (1 << rs->irq)) rs232_handler(rs); }}/*===========================================================================* * rs_icancel * *===========================================================================*/PRIVATE int rs_icancel(tp, dummy)tty_t *tp; /* which TTY */int dummy;{/* Cancel waiting input. */ rs232_t *rs = tp->tty_priv; lock(); rs->icount = 0; rs->itail = rs->ihead; istart(rs); unlock(); return 0; /* dummy */}/*===========================================================================* * rs_ocancel * *===========================================================================*/PRIVATE int rs_ocancel(tp, dummy)tty_t *tp; /* which TTY */int dummy;{/* Cancel pending output. */ rs232_t *rs = tp->tty_priv; lock(); rs->ostate &= ~(ODONE | OQUEUED); rs->ocount = 0; rs->otail = rs->ohead; unlock(); return 0; /* dummy */}/*===========================================================================* * rs_read * *===========================================================================*/PRIVATE int rs_read(tp, try)tty_t *tp; /* which tty */int try;{/* Process characters from the circular input buffer. */ rs232_t *rs = tp->tty_priv; int icount, count, ostate; if (!(tp->tty_termios.c_cflag & CLOCAL)) { if (try) return 1; /* Send a SIGHUP if hangup detected. */ lock(); ostate = rs->ostate; rs->ostate &= ~ODEVHUP; /* save ostate, clear DEVHUP */ unlock(); if (ostate & ODEVHUP) { sigchar(tp, SIGHUP); tp->tty_termios.c_ospeed = B0; /* Disable further I/O. */ return; } } if (try) { if (rs->icount > 0) return 1; return 0; } while ((count = rs->icount) > 0) { icount = bufend(rs->ibuf) - rs->itail; if (count > icount) count = icount; /* Perform input processing on (part of) the input buffer. */ if ((count = in_process(tp, rs->itail, count)) == 0) break; lock(); /* protect interrupt sensitive variables */ rs->icount -= count; if (!rs->idevready && rs->icount < RS_ILOWWATER) istart(rs); unlock(); if ((rs->itail += count) == bufend(rs->ibuf)) rs->itail = rs->ibuf; }}/*===========================================================================* * rs_ostart * *===========================================================================*/PRIVATE void rs_ostart(rs)rs232_t *rs; /* which rs line */{/* Tell RS232 there is something waiting in the output buffer. */ rs->ostate |= OQUEUED; if (txready(rs)) out_int(rs);}/*===========================================================================* * rs_break * *===========================================================================*/PRIVATE int rs_break(tp, dummy)tty_t *tp; /* which tty */int dummy;{/* Generate a break condition by setting the BREAK bit for 0.4 sec. */ rs232_t *rs = tp->tty_priv; int line_controls; sys_inb(rs->line_ctl_port, &line_controls); sys_outb(rs->line_ctl_port, line_controls | LC_BREAK); /* XXX */ /* milli_delay(400); */ /* ouch */ printf("RS232 break\n"); sys_outb(rs->line_ctl_port, line_controls); return 0; /* dummy */}/*===========================================================================* * rs_close * *===========================================================================*/PRIVATE int rs_close(tp, dummy)tty_t *tp; /* which tty */int dummy;{/* The line is closed; optionally hang up. */ rs232_t *rs = tp->tty_priv; int r; if (tp->tty_termios.c_cflag & HUPCL) { sys_outb(rs->modem_ctl_port, MC_OUT2 | MC_RTS); } return 0; /* dummy */}/* Low level (interrupt) routines. */#if (MACHINE == IBM_PC)/*===========================================================================* * rs232_handler * *===========================================================================*/PRIVATE void rs232_handler(rs)struct rs232 *rs;{/* Interrupt hander for RS232. */ while (TRUE) { int v; /* Loop to pick up ALL pending interrupts for device. * This usually just wastes time unless the hardware has a buffer * (and then we have to worry about being stuck in the loop too long). * Unfortunately, some serial cards lock up without this. */ sys_inb(rs->int_id_port, &v); switch (v) { case IS_RECEIVER_READY: in_int(rs); continue; case IS_TRANSMITTER_READY: out_int(rs); continue; case IS_MODEM_STATUS_CHANGE: modem_int(rs); continue; case IS_LINE_STATUS_CHANGE: line_int(rs); continue; } return; }}#endif /* MACHINE == IBM_PC */#if (MACHINE == ATARI)/*===========================================================================* * siaint * *===========================================================================*/PRIVATE void siaint(type)int type; /* interrupt type */{/* siaint is the rs232 interrupt procedure for Atari ST's. For ST there are * as much as 5 interrupt lines used for rs232. The trap type byte left on the * stack by the assembler interrupt handler identifies the interrupt cause. */ register unsigned char code; register rs232_t *rs = &rs_lines[0]; int s = lock(); switch (type & 0x00FF) { case 0x00: /* receive buffer full */ in_int(rs); break; case 0x01: /* receive error */ line_int(rs); break; case 0x02: /* transmit buffer empty */ out_int(rs); break; case 0x03: /* transmit error */ code = MFP->mf_tsr; if (code & ~(T_ENA | T_UE | T_EMPTY)) { printf("sia: transmit error: status=%x\r\n", code); /* MFP->mf_udr = lastchar; */ /* retry */ } break; case 0x04: /* modem lines change */ modem_int(rs); break; } restore(s);}#endif /* MACHINE == ATARI *//*===========================================================================* * in_int * *===========================================================================*/PRIVATE void in_int(rs)register rs232_t *rs; /* line with input interrupt */{/* Read the data which just arrived. * If it is the oxoff char, clear OSWREADY, else if OSWREADY was clear, set * it and restart output (any char does this, not just xon). * Put data in the buffer if room, otherwise discard it. * Set a flag for the clock interrupt handler to eventually notify TTY. */ int c;#if (MACHINE == IBM_PC) sys_inb(rs->recv_port, &c);#else /* MACHINE == ATARI */ c = MFP->mf_udr;#endif if (!(rs->ostate & ORAW)) { if (c == rs->oxoff) { rs->ostate &= ~OSWREADY; } else if (!(rs->ostate & OSWREADY)) { rs->ostate |= OSWREADY; if (txready(rs)) out_int(rs); } } if (rs->icount == buflen(rs->ibuf)) return; /* input buffer full, discard */ if (++rs->icount == RS_IHIGHWATER && rs->idevready) istop(rs); *rs->ihead = c; if (++rs->ihead == bufend(rs->ibuf)) rs->ihead = rs->ibuf; if (rs->icount == 1) { rs->tty->tty_events = 1; force_timeout(); }}/*===========================================================================* * line_int * *===========================================================================*/PRIVATE void line_int(rs)register rs232_t *rs; /* line with line status interrupt */{/* Check for and record errors. */#if (MACHINE == IBM_PC) sys_inb(rs->line_status_port, &rs->lstatus);#else /* MACHINE == ATARI */ rs->lstatus = MFP->mf_rsr; MFP->mf_rsr &= R_ENA; rs->pad = MFP->mf_udr; /* discard char in case of LS_OVERRUN_ERR */#endif /* MACHINE == ATARI */ if (rs->lstatus & LS_FRAMING_ERR) ++rs->framing_errors; if (rs->lstatus & LS_OVERRUN_ERR) ++rs->overrun_errors; if (rs->lstatus & LS_PARITY_ERR) ++rs->parity_errors; if (rs->lstatus & LS_BREAK_INTERRUPT) ++rs->break_interrupts;}/*===========================================================================* * modem_int * *===========================================================================*/PRIVATE void modem_int(rs)register rs232_t *rs; /* line with modem interrupt */{/* Get possibly new device-ready status, and clear ODEVREADY if necessary. * If the device just became ready, restart output. */#if (MACHINE == ATARI) /* Set active edge interrupt so that next change causes a new interrupt */ MFP->mf_aer = (MFP->mf_aer | (IO_SCTS|IO_SDCD)) ^ (MFP->mf_gpip & (IO_SCTS|IO_SDCD));#endif if (devhup(rs)) { rs->ostate |= ODEVHUP; rs->tty->tty_events = 1; force_timeout(); } if (!devready(rs)) rs->ostate &= ~ODEVREADY; else if (!(rs->ostate & ODEVREADY)) { rs->ostate |= ODEVREADY; if (txready(rs)) out_int(rs); }}/*===========================================================================* * out_int * *===========================================================================*/PRIVATE void out_int(rs)register rs232_t *rs; /* line with output interrupt */{/* If there is output to do and everything is ready, do it (local device is * known ready). * Notify TTY when the buffer goes empty. */ if (rs->ostate >= (ODEVREADY | OQUEUED | OSWREADY)) { /* Bit test allows ORAW and requires the others. */#if (MACHINE == IBM_PC) sys_outb(rs->xmit_port, *rs->otail);#else /* MACHINE == ATARI */ MFP->mf_udr = *rs->otail;#endif if (++rs->otail == bufend(rs->obuf)) rs->otail = rs->obuf; if (--rs->ocount == 0) { rs->ostate ^= (ODONE | OQUEUED); /* ODONE on, OQUEUED off */ rs->tty->tty_events = 1; force_timeout(); } else if (rs->ocount == RS_OLOWWATER) { /* running low? */ rs->tty->tty_events = 1; force_timeout(); } }}#endif /* NR_RS_LINES > 0 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -