📄 w90n745_uart.c
字号:
state = info->state;#ifdef SERIAL_DEBUG_OPEN printk("Shutting down serial port %d (irq %d)....", info->line, state->irq);#endif 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); // // First unlink the serial port from the IRQ chain... // if (info->next_port) info->next_port->prev_port = info->prev_port; if (info->prev_port) info->prev_port->next_port = info->next_port; else IRQ_ports[state->irq] = info->next_port; figure_IRQ_timeout(state->irq); // // Free the IRQ, if necessary // // rx if (state->irq && (!IRQ_ports[state->irq] || !IRQ_ports[state->irq]->next_port)) { if (IRQ_ports[state->irq]) { free_irq(state->irq, &IRQ_ports[state->irq]); retval = request_irq(state->irq, rs_interrupt_single, SA_SHIRQ, "serial", &IRQ_ports[state->irq]); if (retval) printk("serial shutdown: request_irq: error %d" " Couldn't reacquire IRQ.\n", retval); } else free_irq(state->irq, &IRQ_ports[state->irq]); }/* if (state->irq - 1 && (!IRQ_ports[state->irq - 1] || !IRQ_ports[state->irq - 1]->next_port)) { if (IRQ_ports[state->irq - 1]) { free_irq(state->irq - 1, &IRQ_ports[state->irq - 1]); retval = request_irq(state->irq - 1, rs_interrupt_single, SA_SHIRQ, "serial", &IRQ_ports[state->irq - 1]); if (retval) printk("serial shutdown: request_irq: error %d" " Couldn't reacquire IRQ.\n", retval); } else free_irq(state->irq - 1, &IRQ_ports[state->irq - 1]); }*/ if (info->xmit.buf) { unsigned long pg = (unsigned long) info->xmit.buf; info->xmit.buf = 0; free_page(pg); }/* info->IER = 0; serial_outp(info, UART_IER, 0x00); // disable all intrs*/ disable_uart_rx_interrupt(info->line); disable_uart_tx_interrupt(info->line);/*#ifdef CONFIG_SERIAL_MANY_PORTS if (info->flags & ASYNC_FOURPORT) { // reset interrupts on the AST Fourport board (void) inb((info->port & 0xFE0) | 0x01F); info->MCR |= UART_MCR_OUT1; } else#endif info->MCR &= ~UART_MCR_OUT2; info->MCR |= ALPHA_KLUDGE_MCR; // Don't ask*/ /* // disable break condition serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC); if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); serial_outp(info, UART_MCR, info->MCR); // disable FIFO's serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); serial_outp(info, UART_FCR, 0);*//*#ifdef CONFIG_SERIAL_RSA // // Reset the RSA board back to 115kbps compat mode. // if ((state->type == PORT_RSA) && (state->baud_base == SERIAL_RSA_BAUD_BASE && disable_rsa(info))) state->baud_base = SERIAL_RSA_BAUD_BASE_LO;#endif*/ (void)serial_in(info, COM_RX); // read data port to reset things if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags);/* if (uart_config[info->state->type].flags & UART_STARTECH) { // Arrange to enter sleep mode serial_outp(info, UART_LCR, 0xBF); serial_outp(info, UART_EFR, UART_EFR_ECB); serial_outp(info, UART_LCR, 0); serial_outp(info, UART_IER, UART_IERX_SLEEP); serial_outp(info, UART_LCR, 0xBF); serial_outp(info, UART_EFR, 0); serial_outp(info, UART_LCR, 0); } if (info->state->type == PORT_16750) { // Arrange to enter sleep mode serial_outp(info, UART_IER, UART_IERX_SLEEP); }*/ info->flags &= ~ASYNC_INITIALIZED; restore_flags(flags);}#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */static int baud_table[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };/*static int tty_get_baud_rate(struct tty_struct *tty){ struct async_struct * info = (struct async_struct *)tty->driver_data; unsigned int cflag, i; cflag = tty->termios->c_cflag; i = cflag & CBAUD; if (i & CBAUDEX) { i &= ~CBAUDEX; if (i < 1 || i > 2) tty->termios->c_cflag &= ~CBAUDEX; else i += 15; } if (i == 15) { if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) i += 1; if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) i += 2; } return baud_table[i];}*/#endif/* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */static void change_speed(struct async_struct *info, struct termios *old_termios){ int quot = 0, baud_base, baud;// unsigned cflag, cval, fcr = 0; unsigned cflag, cval; int bits; unsigned long flags; unsigned int div; if (!info->tty || !info->tty->termios) return; cflag = info->tty->termios->c_cflag; if (!CONFIGURED_SERIAL_PORT(info)) return; // byte size and parity switch (cflag & CSIZE) { case CS5: cval = 0x00; bits = 7; break; case CS6: cval = 0x01; bits = 8; break; case CS7: cval = 0x02; bits = 9; break; case CS8: cval = 0x03; bits = 10; break; // Never happens, but GCC is too dumb to figure it out default: cval = 0x00; bits = 7; break; } if (cflag & CSTOPB) { cval |= 0x04; bits++; } if (cflag & PARENB) { cval |= UART_LCR_PARITY;//add No.121 bits++; } if (cflag & PARODD) cval |= UART_LCR_OPAR; else if (cflag & PARENB) cval |= UART_LCR_EPAR; else cval |= UART_LCR_NPAR;/* if (cflag & PARENB) { cval |= UART_LCR_PARITY; bits++; } if (!(cflag & PARODD)) cval |= UART_LCR_EPAR;#ifdef CMSPAR if (cflag & CMSPAR) cval |= UART_LCR_SPAR;#endif*/ // Determine divisor based on baud rate baud = tty_get_baud_rate(info->tty); if (!baud) baud = 9600; // B0 transition handled in rs_set_termios/*#ifdef CONFIG_SERIAL_RSA if ((info->state->type == PORT_RSA) && (info->state->baud_base != SERIAL_RSA_BAUD_BASE) && enable_rsa(info)) info->state->baud_base = SERIAL_RSA_BAUD_BASE;#endif*/ baud_base = info->state->baud_base;/* if (info->state->type == PORT_16C950) { if (baud <= baud_base) serial_icr_write(info, UART_TCR, 0); else if (baud <= 2*baud_base) { serial_icr_write(info, UART_TCR, 0x8); baud_base = baud_base * 2; } else if (baud <= 4*baud_base) { serial_icr_write(info, UART_TCR, 0x4); baud_base = baud_base * 4; } else serial_icr_write(info, UART_TCR, 0); }*//* if (baud == 38400 && ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) quot = info->state->custom_divisor; else { if (baud == 134) // Special case since 134 is really 134.5 quot = (2*baud_base / 269); else if (baud) quot = baud_base / baud; }*/ quot = 1; //tricky // If the quotient is zero refuse the change if (!quot && old_termios) { info->tty->termios->c_cflag &= ~CBAUD; info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); baud = tty_get_baud_rate(info->tty); if (!baud) baud = 9600;/* if (baud == 38400 && ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) quot = info->state->custom_divisor; else { if (baud == 134) // Special case since 134 is really 134.5 quot = (2*baud_base / 269); else if (baud) quot = baud_base / baud; }*/ } // As a last resort, if the quotient is zero, default to 9600 bps if (!quot) quot = baud_base / 9600; // // Work around a bug in the Oxford Semiconductor 952 rev B // chip which causes it to seriously miscalculate baud rates // when DLL is 0. ///* if (((quot & 0xFF) == 0) && (info->state->type == PORT_16C950) && (info->state->revision == 0x5201)) quot++;*/ info->quot = quot; info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base); info->timeout += HZ/50; // Add .02 seconds of slop/* // Set up FIFO's if (uart_config[info->state->type].flags & UART_USE_FIFO) { if ((info->state->baud_base / quot) < 2400) fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;#ifdef CONFIG_SERIAL_RSA else if (info->state->type == PORT_RSA) fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;#endif else fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; } if (info->state->type == PORT_16750) fcr |= UART_FCR7_64BYTE; // CTS flow control flag and modem status interrupts info->IER &= ~UART_IER_MSI; if (info->flags & ASYNC_HARDPPS_CD) info->IER |= UART_IER_MSI; if (cflag & CRTSCTS) { info->flags |= ASYNC_CTS_FLOW; info->IER |= UART_IER_MSI; } else info->flags &= ~ASYNC_CTS_FLOW; if (cflag & CLOCAL) info->flags &= ~ASYNC_CHECK_CD; else { info->flags |= ASYNC_CHECK_CD; info->IER |= UART_IER_MSI; } serial_out(info, UART_IER, info->IER);*/ // // Set up parity check flag //#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; if (I_INPCK(info->tty)) info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) info->read_status_mask |= UART_LSR_BI; // // Characters to ignore // info->ignore_status_mask = 0; if (I_IGNPAR(info->tty)) info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; if (I_IGNBRK(info->tty)) { info->ignore_status_mask |= UART_LSR_BI; // // If we're ignore parity and break indicators, ignore // overruns too. (For real raw support). // if (I_IGNPAR(info->tty)) info->ignore_status_mask |= UART_LSR_OE; }#if 0 // breaks serial console during boot stage // // !!! ignore all characters if CREAD is not set // if ((cflag & CREAD) == 0) info->ignore_status_mask |= UART_LSR_DR;#endif save_flags(flags); cli();/* if (uart_config[info->state->type].flags & UART_STARTECH) { serial_outp(info, UART_LCR, 0xBF); serial_outp(info, UART_EFR, (cflag & CRTSCTS) ? UART_EFR_CTS : 0); }*//* serial_outp(info, UART_LCR, cval | UART_LCR_DLAB); // set DLAB serial_outp(info, UART_DLL, quot & 0xff); // LS of divisor serial_outp(info, UART_DLM, quot >> 8); // MS of divisor*//* if (info->state->type == PORT_16750) serial_outp(info, UART_FCR, fcr); // set fcr*/// serial_outp(info, UART_LCR, cval); // reset DLAB info->LCR = cval; // Save LCR/* if (info->state->type != PORT_16750) { if (fcr & UART_FCR_ENABLE_FIFO) { // emulated UARTs (Lucent Venus 167x) need two steps serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); } serial_outp(info, UART_FCR, fcr); // set fcr }*/#if 1 serial_outp (info,COM_LCR, 0x80); /* select divisor latch registers */ div=baudrate_div(baud); serial_outp (info,COM_DLL, div&0xFF); serial_outp (info,COM_DLM, (div>>8)&0xFF); serial_outp (info,COM_LCR, cval); /* none parity, 8 data bits, 1 stop bits */#endif restore_flags(flags);}static void rs_put_char(struct tty_struct *tty, unsigned char ch){ struct async_struct *info = (struct async_struct *)tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->device, "rs_put_char")) return; if (!tty || !info->xmit.buf) return; save_flags(flags); cli(); if (CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) == 0) { restore_flags(flags); return; } info->xmit.buf[info->xmit.head] = ch; info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1); restore_flags(flags);}static void rs_flush_chars(struct tty_struct *tty){ struct async_struct *info = (struct async_struct *)tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->device, "rs_flush_chars")) return; if (info->xmit.head == info->xmit.tail || tty->stopped || tty->hw_stopped || !info->xmit.buf) return; save_flags(flags); cli();/* info->IER |= UART_IER_THRI; serial_out(info, UART_IER, info->IER);*/ enable_uart_tx_interrupt(info->line); restore_flags(flags);}static int rs_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count){ int c, ret = 0; struct async_struct *info = (struct async_struct *)tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->device, "rs_write")) return 0; if (!tty || !info->xmit.buf || !tmp_buf) return 0; save_flags(flags); if (from_user) { down(&tmp_buf_sem); while (1) { int c1; c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); if (count < c) c = count; if (c <= 0) break; c -= copy_from_user(tmp_buf, buf, c); if (!c) { if (!ret) ret = -EFAULT; break; } cli(); c1 = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); if (c1 < c) c = c1; memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c); info->xmit.head = ((info->xmit.head + c) & (SERIAL_XMIT_SIZE-1)); //restore_flags(flags);//clyu buf += c; count -= c; ret += c; restore_flags(flags); } up(&tmp_buf_sem); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -