📄 mxser.c
字号:
if (info->xmit_cnt <= 0) { info->IER &= ~UART_IER_THRI; outb(info->IER, info->base + UART_IER); }}static inline void mxser_check_modem_status(struct mxser_struct *info, int status){ /* update input line counters */ if (status & UART_MSR_TERI) info->icount.rng++; if (status & UART_MSR_DDSR) info->icount.dsr++; if (status & UART_MSR_DDCD) info->icount.dcd++; if (status & UART_MSR_DCTS) info->icount.cts++; wake_up_interruptible(&info->delta_msr_wait); if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { if (status & UART_MSR_DCD) wake_up_interruptible(&info->open_wait); else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && (info->flags & ASYNC_CALLOUT_NOHUP))) set_bit(MXSER_EVENT_HANGUP, &info->event); schedule_task(&info->tqueue); } if (info->flags & ASYNC_CTS_FLOW) { if (info->tty->hw_stopped) { if (status & UART_MSR_CTS) { info->tty->hw_stopped = 0; info->IER |= UART_IER_THRI; outb(info->IER, info->base + UART_IER); set_bit(MXSER_EVENT_TXLOW, &info->event); MOD_INC_USE_COUNT; if (schedule_task(&info->tqueue) == 0) MOD_DEC_USE_COUNT; } } else { if (!(status & UART_MSR_CTS)) { info->tty->hw_stopped = 1; info->IER &= ~UART_IER_THRI; outb(info->IER, info->base + UART_IER); } } }}static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, struct mxser_struct *info){ DECLARE_WAITQUEUE(wait, current); unsigned long flags; int retval; int do_clocal = 0; /* * If the device is in the middle of being closed, then block * until it's done, and then try again. */ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { if (info->flags & ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait);#ifdef SERIAL_DO_RESTART if (info->flags & ASYNC_HUP_NOTIFY) return (-EAGAIN); else return (-ERESTARTSYS);#else return (-EAGAIN);#endif } /* * If this is a callout device, then just make sure the normal * device isn't being used. */ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { if (info->flags & ASYNC_NORMAL_ACTIVE) return (-EBUSY); if ((info->flags & ASYNC_CALLOUT_ACTIVE) && (info->flags & ASYNC_SESSION_LOCKOUT) && (info->session != current->session)) return (-EBUSY); if ((info->flags & ASYNC_CALLOUT_ACTIVE) && (info->flags & ASYNC_PGRP_LOCKOUT) && (info->pgrp != current->pgrp)) return (-EBUSY); info->flags |= ASYNC_CALLOUT_ACTIVE; return (0); } /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { if (info->flags & ASYNC_CALLOUT_ACTIVE) return (-EBUSY); info->flags |= ASYNC_NORMAL_ACTIVE; return (0); } if (info->flags & ASYNC_CALLOUT_ACTIVE) { if (info->normal_termios.c_cflag & CLOCAL) do_clocal = 1; } else { if (tty->termios->c_cflag & CLOCAL) do_clocal = 1; } /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in * this loop, info->count is dropped by one, so that * mxser_close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ retval = 0; add_wait_queue(&info->open_wait, &wait); save_flags(flags); cli(); if (!tty_hung_up_p(filp)) info->count--; restore_flags(flags); info->blocked_open++; while (1) { save_flags(flags); cli(); if (!(info->flags & ASYNC_CALLOUT_ACTIVE)) outb(inb(info->base + UART_MCR) | UART_MCR_DTR | UART_MCR_RTS, info->base + UART_MCR); restore_flags(flags); current->state = TASK_INTERRUPTIBLE; if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) {#ifdef SERIAL_DO_RESTART if (info->flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS;#else retval = -EAGAIN;#endif break; } if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && !(info->flags & ASYNC_CLOSING) && (do_clocal || (inb(info->base + UART_MSR) & UART_MSR_DCD))) break; if (signal_pending(current)) { retval = -ERESTARTSYS; break; } schedule(); } current->state = TASK_RUNNING; remove_wait_queue(&info->open_wait, &wait); if (!tty_hung_up_p(filp)) info->count++; info->blocked_open--; if (retval) return (retval); info->flags |= ASYNC_NORMAL_ACTIVE; return (0);}static int mxser_startup(struct mxser_struct *info){ unsigned long flags; unsigned long page; page = get_free_page(GFP_KERNEL); if (!page) return (-ENOMEM); save_flags(flags); cli(); if (info->flags & ASYNC_INITIALIZED) { free_page(page); restore_flags(flags); return (0); } if (!info->base || !info->type) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); free_page(page); restore_flags(flags); return (0); } if (info->xmit_buf) free_page(page); else info->xmit_buf = (unsigned char *) page; /* * Clear the FIFO buffers and disable them * (they will be reenabled in mxser_change_speed()) */ if (info->xmit_fifo_size == 16) outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), info->base + UART_FCR); /* * At this point there's no way the LSR could still be 0xFF; * if it is, then bail out, because there's likely no UART * here. */ if (inb(info->base + UART_LSR) == 0xff) { restore_flags(flags); if (suser()) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); return (0); } else return (-ENODEV); } /* * Clear the interrupt registers. */ (void) inb(info->base + UART_LSR); (void) inb(info->base + UART_RX); (void) inb(info->base + UART_IIR); (void) inb(info->base + UART_MSR); /* * Now, initialize the UART */ outb(UART_LCR_WLEN8, info->base + UART_LCR); /* reset DLAB */ info->MCR = UART_MCR_DTR | UART_MCR_RTS; outb(info->MCR, info->base + UART_MCR); /* * Finally, enable interrupts */ info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; outb(info->IER, info->base + UART_IER); /* enable interrupts */ /* * And clear the interrupt registers again for luck. */ (void) inb(info->base + UART_LSR); (void) inb(info->base + UART_RX); (void) inb(info->base + UART_IIR); (void) inb(info->base + UART_MSR); if (info->tty) test_and_clear_bit(TTY_IO_ERROR, &info->tty->flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; /* * and set the speed of the serial port */ mxser_change_speed(info, 0); info->flags |= ASYNC_INITIALIZED; restore_flags(flags); return (0);}/* * This routine will shutdown a serial port; interrupts maybe disabled, and * DTR is dropped if the hangup on close termio flag is on. */static void mxser_shutdown(struct mxser_struct *info){ unsigned long flags; if (!(info->flags & ASYNC_INITIALIZED)) return; save_flags(flags); cli(); /* Disable interrupts */ /* * clear delta_msr_wait queue to avoid mem leaks: we may free the irq * here so the queue might never be waken up */ wake_up_interruptible(&info->delta_msr_wait); /* * Free the IRQ, if necessary */ if (info->xmit_buf) { free_page((unsigned long) info->xmit_buf); info->xmit_buf = 0; } info->IER = 0; outb(0x00, info->base + UART_IER); /* disable all intrs */ if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS); outb(info->MCR, info->base + UART_MCR); /* clear Rx/Tx FIFO's */ outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), info->base + UART_FCR); /* read data port to reset things */ (void) inb(info->base + UART_RX); if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); info->flags &= ~ASYNC_INITIALIZED; restore_flags(flags);}/* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */static int mxser_change_speed(struct mxser_struct *info, struct termios *old_termios){ int quot = 0; unsigned cflag, cval, fcr; int i; int ret = 0; unsigned long flags; if (!info->tty || !info->tty->termios) return ret; cflag = info->tty->termios->c_cflag; if (!(info->base)) return ret;#ifndef B921600#define B921600 (B460800 +1)#endif switch (cflag & (CBAUD | CBAUDEX)) { case B921600: i = 20; break; case B460800: i = 19; break; case B230400: i = 18; break; case B115200: i = 17; break; case B57600: i = 16; break; case B38400: i = 15; break; case B19200: i = 14; break; case B9600: i = 13; break; case B4800: i = 12; break; case B2400: i = 11; break; case B1800: i = 10; break; case B1200: i = 9; break; case B600: i = 8; break; case B300: i = 7; break; case B200: i = 6; break; case B150: i = 5; break; case B134: i = 4; break; case B110: i = 3; break; case B75: i = 2; break; case B50: i = 1; break; default: i = 0; break; } if (i == 15) { if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) i = 16; /* 57600 bps */ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) i = 17; /* 115200 bps */#ifdef ASYNC_SPD_SHI if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) i = 18;#endif#ifdef ASYNC_SPD_WARP if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) i = 19;#endif } if (mxvar_baud_table[i] == 134) { quot = (2 * info->baud_base / 269); } else if (mxvar_baud_table[i]) { quot = info->baud_base / mxvar_baud_table[i]; if (!quot && old_termios) { /* re-calculate */ info->tty->termios->c_cflag &= ~CBAUD; info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); switch (info->tty->termios->c_cflag & (CBAUD | CBAUDEX)) { case B921600: i = 20; break; case B460800: i = 19; break; case B230400: i = 18; break; case B115200: i = 17; break; case B57600: i = 16; break; case B38400: i = 15; break; case B19200: i = 14; break; case B9600: i = 13; break; case B4800: i = 12; break; case B2400: i = 11; break; case B1800: i = 10; break; case B1200: i = 9; break; case B600: i = 8; break; case B300: i = 7; break; case B200: i = 6; break; case B150: i = 5; break; case B134: i = 4; break; case B110: i = 3; break; case B75: i = 2; break; case B50: i = 1; break; default: i = 0; break; } if (i == 15) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -