void serial_outc(unsigned char c, int line) { uart_state_t *port = uart_states + line; while (!(READ_SERCSR(port->status, line) & M_DUART_TX_RDY)) ; WRITE_SERCSR(c, port->tx_hold, line); while (!(READ_SERCSR(port->status, port->line) & M_DUART_TX_EMT)) ; }
static irqreturn_t duart_int(int irq, void *dev_id, struct pt_regs *regs) { uart_state_t *us = (uart_state_t *)dev_id; struct tty_struct *tty = us->tty; unsigned int status = READ_SERCSR(us->status, us->line); #ifdef DUART_SPEW printk("DUART INT\n"); #endif if (status & M_DUART_RX_RDY) { int counter = 2048; unsigned int ch; if (status & M_DUART_OVRUN_ERR) tty_insert_flip_char(tty, 0, TTY_OVERRUN); if (status & M_DUART_PARITY_ERR) { printk("Parity error!\n"); } else if (status & M_DUART_FRM_ERR) { printk("Frame error!\n"); } while (counter > 0) { if (!(READ_SERCSR(us->status, us->line) & M_DUART_RX_RDY)) break; ch = READ_SERCSR(us->rx_hold, us->line); if (tty->flip.count < TTY_FLIPBUF_SIZE) { *tty->flip.char_buf_ptr++ = ch; *tty->flip.flag_buf_ptr++ = 0; tty->flip.count++; } udelay(1); counter--; } tty_flip_buffer_push(tty); } if (status & M_DUART_TX_RDY) { transmit_char_pio(us); } return IRQ_HANDLED; }
static void ser_console_write(struct console *cons, const char *s, unsigned int count) { int line = cons->index; uart_state_t *port = uart_states + line; u32 imr; imr = READ_SERCSR(port->imr, line); WRITE_SERCSR(0, port->imr, line); while (count--) { if (*s == '\n') serial_outc('\r', line); serial_outc(*s++, line); } WRITE_SERCSR(imr, port->imr, line); }
/* * Close a reference count out. If reference count hits zero, null the * tty, kill the interrupts. The tty_io driver is responsible for making * sure we've cleared out our internal buffers before calling close() */ static void duart_close(struct tty_struct *tty, struct file *filp) { uart_state_t *us = (uart_state_t *) tty->driver_data; unsigned long flags; #ifdef DUART_SPEW printk("duart_close called by %i (%s)\n", current->pid, current->comm); #endif if (!us || !us->open) return; spin_lock_irqsave(&open_lock, flags); if (tty_hung_up_p(filp)) { MOD_DEC_USE_COUNT; spin_unlock_irqrestore(&open_lock, flags); return; } if (--us->open < 0) { us->open = 0; printk(KERN_ERR "duart: bad open count: %d\n", us->open); } if (us->open) { spin_unlock_irqrestore(&open_lock, flags); return; } spin_unlock_irqrestore(&open_lock, flags); tty->closing = 1; /* Stop accepting input */ duart_mask_ints(us->line, M_DUART_IMR_RX); /* Wait for FIFO to drain */ while (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_EMT)) ; if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); tty->closing = 0; MOD_DEC_USE_COUNT; }
static inline void transmit_char_pio(uart_state_t *us) { struct tty_struct *tty = us->tty; int blocked = 0; if (spin_trylock(&us->outp_lock)) { for (;;) { if (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_RDY)) break; if (us->outp_count <= 0 || tty->stopped || tty->hw_stopped) { break; } else { WRITE_SERCSR(us->outp_buf[us->outp_head], us->tx_hold, us->line); us->outp_head = (us->outp_head + 1) & (SERIAL_XMIT_SIZE-1); if (--us->outp_count <= 0) break; } udelay(10); } spin_unlock(&us->outp_lock); } else { blocked = 1; } if (!us->outp_count || tty->stopped || tty->hw_stopped || blocked) { us->flags &= ~TX_INTEN; duart_mask_ints(us->line, M_DUART_IMR_TX); } if (us->open && (us->outp_count < (SERIAL_XMIT_SIZE/2))) { /* * We told the discipline at one point that we had no * space, so it went to sleep. Wake it up when we hit * half empty */ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) tty->ldisc.write_wakeup(tty); wake_up_interruptible(&tty->write_wait); } }
static void duart_wait_until_sent(struct tty_struct *tty, int timeout) { uart_state_t *us = (uart_state_t *) tty->driver_data; unsigned long orig_jiffies; orig_jiffies = jiffies; #ifdef DUART_SPEW printk("duart_wait_until_sent(%d)+\n", timeout); #endif while (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_EMT)) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); if (signal_pending(current)) break; if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } #ifdef DUART_SPEW printk("duart_wait_until_sent()-\n"); #endif }
/* Unmask the passed interrupt lines at the duart level */ static inline void duart_unmask_ints(unsigned int line, unsigned int mask) { uart_state_t *port = uart_states + line; u64 tmp = READ_SERCSR(port->imr, line); WRITE_SERCSR(tmp | mask, port->imr, line); }