static _INLINE_ void transmit_chars(struct NIOS_serial *info) { np_uart * uart= (np_uart *)(info->port); if (info->x_char) { /* Send next char */ uart->np_uarttxdata = info->x_char; info->x_char = 0; goto clear_and_return; } if((info->xmit_cnt <= 0) || info->tty->stopped) { /* That's peculiar... TX ints off */ uart->np_uartcontrol &= ~np_uartcontrol_itrdy_mask; goto clear_and_return; } /* Send char */ uart->np_uarttxdata = info->xmit_buf[info->xmit_tail++]; info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); info->xmit_cnt--; if (info->xmit_cnt < WAKEUP_CHARS) rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); if(info->xmit_cnt <= 0) { /* All done for now... TX ints off */ uart->np_uartcontrol &= ~np_uartcontrol_itrdy_mask; goto clear_and_return; } clear_and_return: /* Clear interrupt (should be auto)*/ return; }
static _INLINE_ void transmit_chars(struct bf535_serial *info) { int idx = info->hub2; if (info->x_char) { /* Send next char */ local_put_char(idx, info->x_char); info->x_char = 0; goto clear_and_return; } if((info->xmit_cnt <= 0) || info->tty->stopped) { /* TX ints off */ ACCESS_PORT_IER(idx) /* Change access to IER & data port */ UART_IER(idx) &= ~UART_IER_ETBEI; goto clear_and_return; } /* Send char */ local_put_char(idx,info->xmit_buf[info->xmit_tail++]); info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); info->xmit_cnt--; if (info->xmit_cnt < WAKEUP_CHARS) rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); if(info->xmit_cnt <= 0) { /* All done for now... TX ints off */ ACCESS_PORT_IER(idx) /* Change access to IER & data port */ UART_IER(idx) &= ~UART_IER_ETBEI; goto clear_and_return; } clear_and_return: /* Clear interrupt (should be auto)*/ return; }
static _INLINE_ void transmit_chars(struct m68k_serial *info) { m68328_uart *uart = &uart_addr[info->line]; if (info->x_char) { /* Send next char */ uart->utx.b.txdata = info->x_char; info->x_char = 0; goto clear_and_return; } if((info->xmit_cnt <= 0) || info->tty->stopped) { /* That's peculiar... TX ints off */ uart->ustcnt &= ~USTCNT_TX_INTR_MASK; goto clear_and_return; } /* Send char */ uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++]; info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); info->xmit_cnt--; if (info->xmit_cnt < WAKEUP_CHARS) rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); if(info->xmit_cnt <= 0) { /* All done for now... TX ints off */ uart->ustcnt &= ~USTCNT_TX_INTR_MASK; goto clear_and_return; } clear_and_return: /* Clear interrupt (should be auto)*/ return; }
static _INLINE_ void transmit_chars(struct LEON_serial *info) { if (info->x_char) { /* Send next char */ leon->uartdata1 = info->x_char; info->x_char = 0; goto clear_and_return; } if((info->xmit_cnt <= 0) || info->tty->stopped) { /* That's peculiar... TX ints off */ leon->uartctrl1 &= ~UCTRL_TI; goto clear_and_return; } /* Send char */ leon->uartdata1 = info->xmit_buf[info->xmit_tail++]; info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); info->xmit_cnt--; if (info->xmit_cnt < WAKEUP_CHARS) rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); if(info->xmit_cnt <= 0) { /* All done for now... TX ints off */ leon->uartctrl1 &= ~UCTRL_TI; goto clear_and_return; } clear_and_return: /* Clear interrupt (should be auto)*/ return; }
static _INLINE_ void transmit_chars(struct sci_struct *sci) { if (sci->info->x_char) { sci_outp(sci, SCI_TDR, sci->info->x_char); sci->info->x_char = 0; return; } if ((sci->info->xmit_cnt <= 0) || sci->info->tty->stopped) { sci_ctrl_reset(sci, SCI_SCR_TIE); return; } sci_outp(sci, SCI_TDR, sci->info->xmit_buf[sci->info->xmit_tail++]); sci->info->xmit_tail = sci->info->xmit_tail & (SERIAL_XMIT_SIZE-1); sci_outp(sci,SCI_SSR,sci_in(sci,SCI_SSR) & ~SCI_SSR_TDRE); sci->info->xmit_cnt--; if (sci->info->xmit_cnt < WAKEUP_CHARS) rs_sched_event(sci, RS_EVENT_WRITE_WAKEUP); #ifdef SERIAL_DEBUG_INTR printk("THRE..."); #endif if (sci->info->xmit_cnt <= 0) { sci_ctrl_reset(sci, SCI_SCR_TIE); } }
static inline void transmit_chars(struct cnxt_serial *info) { struct uart_regs *uart = info->uart; if (info->x_char) { /* Send next char */ //xmit_char(info->x_char); uart->fifo=info->x_char; info->x_char = 0; goto clear_and_return; } if((info->xmit_cnt <= 0) || info->tty->stopped) { /* That's peculiar... */ goto clear_and_return; } /* Send char */ //xmit_char(info->xmit_buf[info->xmit_tail++]); info->uart->fifo=info->xmit_buf[info->xmit_tail++]; info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); info->xmit_cnt--; if (info->xmit_cnt < 256) rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); if(info->xmit_cnt <= 0) { goto clear_and_return; } clear_and_return: /* Clear interrupt (should be auto)*/ return; }
static void transmit_chars(struct async_struct *info) { custom.intreq = IF_TBE; mb(); if (info->x_char) { custom.serdat = info->x_char | 0x100; mb(); info->state->icount.tx++; info->x_char = 0; return; } if (info->xmit.head == info->xmit.tail || info->tty->stopped || info->tty->hw_stopped) { info->IER &= ~UART_IER_THRI; custom.intena = IF_TBE; mb(); return; } custom.serdat = info->xmit.buf[info->xmit.tail++] | 0x100; mb(); info->xmit.tail = info->xmit.tail & (SERIAL_XMIT_SIZE-1); info->state->icount.tx++; if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) < WAKEUP_CHARS) rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); #ifdef SERIAL_DEBUG_INTR printk("THRE..."); #endif if (info->xmit.head == info->xmit.tail) { custom.intena = IF_TBE; mb(); info->IER &= ~UART_IER_THRI; } }
static void serial_send_next_write(struct async_struct *info) { int line; mach_msg_type_number_t data_count; kern_return_t kr; line = MINOR(info->tty->device) - info->tty->driver.minor_start; data_count = SERIAL_XMIT_SIZE - info->xmit_tail; if (data_count > info->xmit_cnt) data_count = info->xmit_cnt; if (data_count > IO_INBAND_MAX) data_count = IO_INBAND_MAX; info->write_busy = TRUE; kr = serv_device_write_async(info->device_port, info->reply_port, 0, 0, &info->xmit_buf[info->xmit_tail], data_count, TRUE); if (kr != D_SUCCESS) { if (info->tty != NULL) { MACH3_DEBUG(1, kr, ("transmit_chars(dev 0x%x): " "serv_device_write_async", info->tty->device)); } info->xmit_cnt = 0; info->write_busy = FALSE; } if (info->xmit_cnt < WAKEUP_CHARS) rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); #ifdef SERIAL_DEBUG_INTR printk("THRE..."); #endif }
/* * This is the serial driver's generic interrupt routine */ static void rs_interruptTx(int irq, void *dev_id, struct pt_regs *regs) { unsigned int count, status; struct s3c3410_serial *info = &s3c3410_info; if (info->x_char) { outb(info->x_char, S3C3410X_UART_BASE+S3C3410X_UTXH_B); info->x_char = 0; return; } if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tty->hw_stopped ) { tx_stop(); return; } for (count = TX_FIFO_DEPTH; count > 0; --count) { status = inb(S3C3410X_UART_BASE+S3C3410X_UFSTAT); if (status & UFSTAT_TFF) { handle_status (info, UFSTAT_TFF); break; } else { outb(info->xmit_buf[info->xmit_tail++], S3C3410X_UART_BASE+S3C3410X_UTXH_B); info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE - 1); if (--info->xmit_cnt <= 0) break; } } if (info->xmit_cnt < WAKEUP_CHARS) rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); if (info->xmit_cnt <= 0) tx_stop(); return; }
/* I need to do this for the SCCs, so it is left as a reminder. */ static _INLINE_ void check_modem_status(struct async_struct *info) { int status; /* struct async_icount *icount; */ struct async_icount_24 *icount; status = serial_in(info, UART_MSR); if (status & UART_MSR_ANY_DELTA) { icount = &info->state->icount; /* update input line counters */ if (status & UART_MSR_TERI) icount->rng++; if (status & UART_MSR_DDSR) icount->dsr++; if (status & UART_MSR_DDCD) { icount->dcd++; #ifdef CONFIG_HARD_PPS if ((info->flags & ASYNC_HARDPPS_CD) && (status & UART_MSR_DCD)) hardpps(); #endif } if (status & UART_MSR_DCTS) icount->cts++; wake_up_interruptible(&info->delta_msr_wait); } if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { #if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) printk("ttys%d CD now %s...", info->line, (status & UART_MSR_DCD) ? "on" : "off"); #endif if (status & UART_MSR_DCD) wake_up_interruptible(&info->open_wait); else { #ifdef SERIAL_DEBUG_OPEN printk("scheduling hangup..."); #endif queue_task(&info->tqueue_hangup, &tq_scheduler); } } if (info->flags & ASYNC_CTS_FLOW) { if (info->port.tty->hw_stopped) { if (status & UART_MSR_CTS) { #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) printk("CTS tx start..."); #endif info->port.tty->hw_stopped = 0; info->IER |= UART_IER_THRI; serial_out(info, UART_IER, info->IER); rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); return; } } else { if (!(status & UART_MSR_CTS)) { #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) printk("CTS tx stop..."); #endif info->port.tty->hw_stopped = 1; info->IER &= ~UART_IER_THRI; serial_out(info, UART_IER, info->IER); } } } }
static void ser_interrupt(int irq, void *data, struct pt_regs *regs) { struct async_struct *info = data; u_char iir,lsr; unsigned char ch; /* Get value in IIR for future use */ if ((iir=uart.IIR) & IRQ_PEND) return; /* If we got here, then there is an interrupt waiting for us to service */ while (!(iir & IRQ_PEND)) /* loop until no more ints */ { switch (iir & (IRQ_ID1 | IRQ_ID2 | IRQ_ID3)) { case IRQ_RLS: /* Receiver Line Status */ case IRQ_CTI: /* Character Timeout */ case IRQ_RDA: /* Received Data Available */ /* * Copy chars to the tty-queue ... * Be careful that we aren't passing one of the * Receiver Line Status interrupt-conditions without noticing. */ { int ch; lsr = uart.LSR; while (lsr & DR) { u_char err = 0; ch = uart.RBR; if (lsr & BI) err = TTY_BREAK; else if (lsr & PE) err = TTY_PARITY; else if (lsr & OE) err = TTY_OVERRUN; else if (lsr & FE) err = TTY_FRAME; rs_receive_char(info, ch, err); lsr = uart.LSR; } } break; case IRQ_THRE: /* Transmitter holding register empty */ { int fifo_space = 16; /* If the uart is ready to receive data and there are chars in */ /* the queue we transfer all we can to the uart's FIFO */ if (info->xmit_cnt <= 0 || info->tty->stopped || info->tty->hw_stopped) { /* Disable transmitter empty interrupt */ uart.IER &= ~(ETHREI); /* Need to send a char to acknowledge the interrupt */ uart.THR = 0; break; } /* Handle software flow control */ if (info->x_char) { uart.THR = info->x_char; info->x_char = 0; fifo_space--; } /* Fill the fifo */ while (fifo_space > 0) { fifo_space--; uart.THR = info->xmit_buf[info->xmit_tail++]; info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); if (--info->xmit_cnt == 0) break; } /* Don't need THR interrupts any more */ if (info->xmit_cnt == 0) uart.IER &= ~(ETHREI); if (info->xmit_cnt < WAKEUP_CHARS) rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); } break; case IRQ_MS: /* Must be modem status register interrupt? */ { u_char msr = uart.MSR; if (info->flags & ASYNC_INITIALIZED) { if (msr & DCTS) rs_check_cts(info, (msr & CTS)); /* active high */ if (msr & DDCD) rs_dcd_changed(info, !(msr & DCD)); /* active low */ } } break; } /* switch (iir) */ iir = uart.IIR; } /* while IRQ_PEND */ ch=inb(GAYLE_IRQ_STATUS); /* printk("gayle: %02X - %02X (pre)\n",inb(GAYLE_IRQ_STATUS2),inb(GAYLE_IRQ_STATUS)); */ outb(0xdc | (ch & 0x03),GAYLE_IRQ_STATUS); /* printk("gayle: %02X - %02X (post)\n",inb(GAYLE_IRQ_STATUS2), inb(GAYLE_IRQ_STATUS)); */ }
static void check_modem_status(struct async_struct *info) { unsigned char status = ciab.pra & (SER_DCD | SER_CTS | SER_DSR); unsigned char dstatus; struct async_icount *icount; /* Determine bits that have changed */ dstatus = status ^ current_ctl_bits; current_ctl_bits = status; if (dstatus) { icount = &info->state->icount; /* update input line counters */ if (dstatus & SER_DSR) icount->dsr++; if (dstatus & SER_DCD) { icount->dcd++; #ifdef CONFIG_HARD_PPS if ((info->flags & ASYNC_HARDPPS_CD) && !(status & SER_DCD)) hardpps(); #endif } if (dstatus & SER_CTS) icount->cts++; wake_up_interruptible(&info->delta_msr_wait); } if ((info->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) { #if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) printk("ttyS%d CD now %s...", info->line, (!(status & SER_DCD)) ? "on" : "off"); #endif if (!(status & SER_DCD)) wake_up_interruptible(&info->open_wait); else { #ifdef SERIAL_DEBUG_OPEN printk("doing serial hangup..."); #endif if (info->tty) tty_hangup(info->tty); } } if (info->flags & ASYNC_CTS_FLOW) { if (info->tty->hw_stopped) { if (!(status & SER_CTS)) { #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) printk("CTS tx start..."); #endif info->tty->hw_stopped = 0; info->IER |= UART_IER_THRI; custom.intena = IF_SETCLR | IF_TBE; mb(); /* set a pending Tx Interrupt, transmitter should restart now */ custom.intreq = IF_SETCLR | IF_TBE; mb(); rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); return; } } else { if ((status & SER_CTS)) { #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) printk("CTS tx stop..."); #endif info->tty->hw_stopped = 1; info->IER &= ~UART_IER_THRI; /* disable Tx interrupt and remove any pending interrupts */ custom.intena = IF_TBE; mb(); custom.intreq = IF_TBE; mb(); } } } }