📄 mxser.c
字号:
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 == 0) quot = 1; } else { quot = 0; } } else if (quot == 0) quot = 1; } else { quot = 0; } if (quot) { info->MCR |= UART_MCR_DTR; save_flags(flags); cli(); outb(info->MCR, info->base + UART_MCR); restore_flags(flags); } else { info->MCR &= ~UART_MCR_DTR; save_flags(flags); cli(); outb(info->MCR, info->base + UART_MCR); restore_flags(flags); return ret; } /* byte size and parity */ switch (cflag & CSIZE) { case CS5: cval = 0x00; break; case CS6: cval = 0x01; break; case CS7: cval = 0x02; break; case CS8: cval = 0x03; break; default: cval = 0x00; break; /* too keep GCC shut... */ } if (cflag & CSTOPB) cval |= 0x04; if (cflag & PARENB) cval |= UART_LCR_PARITY; if (!(cflag & PARODD)) cval |= UART_LCR_EPAR; if ((info->type == PORT_8250) || (info->type == PORT_16450)) { fcr = 0; } else { fcr = UART_FCR_ENABLE_FIFO; switch (info->rx_trigger) { case 1: fcr |= UART_FCR_TRIGGER_1; break; case 4: fcr |= UART_FCR_TRIGGER_4; break; case 8: fcr |= UART_FCR_TRIGGER_8; break; default: fcr |= UART_FCR_TRIGGER_14; } } /* CTS flow control flag and modem status interrupts */ info->IER &= ~UART_IER_MSI; info->MCR &= ~UART_MCR_AFE; if (cflag & CRTSCTS) { info->flags |= ASYNC_CTS_FLOW; info->IER |= UART_IER_MSI; if (info->type == PORT_16550A) info->MCR |= UART_MCR_AFE; } else { info->flags &= ~ASYNC_CTS_FLOW; } outb(info->MCR, info->base + UART_MCR); if (cflag & CLOCAL) info->flags &= ~ASYNC_CHECK_CD; else { info->flags |= ASYNC_CHECK_CD; info->IER |= UART_IER_MSI; } outb(info->IER, info->base + UART_IER); /* * Set up parity check flag */ 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; info->ignore_status_mask = 0;#if 0 /* This should be safe, but for some broken bits of hardware... */ if (I_IGNPAR(info->tty)) { info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; info->read_status_mask |= UART_LSR_PE | UART_LSR_FE; }#endif if (I_IGNBRK(info->tty)) { info->ignore_status_mask |= UART_LSR_BI; info->read_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 | UART_LSR_PE | UART_LSR_FE; info->read_status_mask |= UART_LSR_OE | UART_LSR_PE | UART_LSR_FE; } } save_flags(flags); cli(); outb(cval | UART_LCR_DLAB, info->base + UART_LCR); /* set DLAB */ outb(quot & 0xff, info->base + UART_DLL); /* LS of divisor */ outb(quot >> 8, info->base + UART_DLM); /* MS of divisor */ outb(cval, info->base + UART_LCR); /* reset DLAB */ outb(fcr, info->base + UART_FCR); /* set fcr */ restore_flags(flags); return ret;}/* * ------------------------------------------------------------ * friends of mxser_ioctl() * ------------------------------------------------------------ */static int mxser_get_serial_info(struct mxser_struct *info, struct serial_struct *retinfo){ struct serial_struct tmp; if (!retinfo) return (-EFAULT); memset(&tmp, 0, sizeof(tmp)); tmp.type = info->type; tmp.line = info->port; tmp.port = info->base; tmp.irq = info->irq; tmp.flags = info->flags; tmp.baud_base = info->baud_base; tmp.close_delay = info->close_delay; tmp.closing_wait = info->closing_wait; tmp.custom_divisor = info->custom_divisor; tmp.hub6 = 0; copy_to_user(retinfo, &tmp, sizeof(*retinfo)); return (0);}static int mxser_set_serial_info(struct mxser_struct *info, struct serial_struct *new_info){ struct serial_struct new_serial; unsigned int flags; int retval = 0; if (!new_info || !info->base) return (-EFAULT); copy_from_user(&new_serial, new_info, sizeof(new_serial)); if ((new_serial.irq != info->irq) || (new_serial.port != info->base) || (new_serial.type != info->type) || (new_serial.custom_divisor != info->custom_divisor) || (new_serial.baud_base != info->baud_base)) return (-EPERM); flags = info->flags & ASYNC_SPD_MASK; if (!suser()) { if ((new_serial.baud_base != info->baud_base) || (new_serial.close_delay != info->close_delay) || ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK))) return (-EPERM); info->flags = ((info->flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK)); } else { /* * OK, past this point, all the error checking has been done. * At this point, we start making changes..... */ info->flags = ((info->flags & ~ASYNC_FLAGS) | (new_serial.flags & ASYNC_FLAGS)); info->close_delay = new_serial.close_delay * HZ / 100; info->closing_wait = new_serial.closing_wait * HZ / 100; } if (info->flags & ASYNC_INITIALIZED) { if (flags != (info->flags & ASYNC_SPD_MASK)) { mxser_change_speed(info, 0); } } else retval = mxser_startup(info); return (retval);}/* * mxser_get_lsr_info - get line status register info * * Purpose: Let user call ioctl() to get info when the UART physically * is emptied. On bus types like RS485, the transmitter must * release the bus after transmitting. This must be done when * the transmit shift register is empty, not be done when the * transmit holding register is empty. This functionality * allows an RS485 driver to be written in user space. */static int mxser_get_lsr_info(struct mxser_struct *info, unsigned int *value){ unsigned char status; unsigned int result; unsigned long flags; save_flags(flags); cli(); status = inb(info->base + UART_LSR); restore_flags(flags); result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); put_user(result, value); return (0);}/* * This routine sends a break character out the serial port. */static void mxser_send_break(struct mxser_struct *info, int duration){ unsigned long flags; if (!info->base) return; current->state = TASK_INTERRUPTIBLE; save_flags(flags); cli(); outb(inb(info->base + UART_LCR) | UART_LCR_SBC, info->base + UART_LCR); schedule_timeout(duration); outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC, info->base + UART_LCR); restore_flags(flags);}static int mxser_get_modem_info(struct mxser_struct *info, unsigned int *value){ unsigned char control, status; unsigned int result; unsigned long flags; control = info->MCR; save_flags(flags); cli(); status = inb(info->base + UART_MSR); if (status & UART_MSR_ANY_DELTA) mxser_check_modem_status(info, status); restore_flags(flags); result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); put_user(result, value); return (0);}static int mxser_set_modem_info(struct mxser_struct *info, unsigned int cmd, unsigned int *value){ unsigned int arg; unsigned long flags; if(get_user(arg, value)) return -EFAULT; switch (cmd) { case TIOCMBIS: if (arg & TIOCM_RTS) info->MCR |= UART_MCR_RTS; if (arg & TIOCM_DTR) info->MCR |= UART_MCR_DTR; break; case TIOCMBIC: if (arg & TIOCM_RTS) info->MCR &= ~UART_MCR_RTS; if (arg & TIOCM_DTR) info->MCR &= ~UART_MCR_DTR; break; case TIOCMSET: info->MCR = ((info->MCR & ~(UART_MCR_RTS | UART_MCR_DTR)) | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0)); break; default: return (-EINVAL); } save_flags(flags); cli(); outb(info->MCR, info->base + UART_MCR); restore_flags(flags); return (0);}static int mxser_read_register(int, unsigned short *);static int mxser_program_mode(int);static void mxser_normal_mode(int);static int mxser_get_ISA_conf(int cap, struct mxser_hwconf *hwconf){ int id, i, bits; unsigned short regs[16], irq; unsigned char scratch, scratch2; id = mxser_read_register(cap, regs); if (id == C168_ASIC_ID) hwconf->board_type = MXSER_BOARD_C168_ISA; else if (id == C104_ASIC_ID) hwconf->board_type = MXSER_BOARD_C104_ISA; else if (id == CI104J_ASIC_ID) hwconf->board_type = MXSER_BOARD_CI104J; else return (0); irq = regs[9] & 0x0F; irq = irq | (irq << 4); irq = irq | (irq << 8); if ((irq != regs[9]) || ((id == 1) && (irq != regs[10]))) { return (MXSER_ERR_IRQ_CONFLIT); } if (!irq) { return (MXSER_ERR_IRQ); } for (i = 0; i < 8; i++) hwconf->ioaddr[i] = (int) regs[i + 1] & 0xFFF8; hwconf->irq = (int) (irq & 0x0F); if ((regs[12] & 0x80) == 0) { return (MXSER_ERR_VECTOR); } hwconf->vector = (int) regs[11]; /* interrupt vector */ if (id == 1) hwconf->vector_mask = 0x00FF; else hwconf->vector_mask = 0x000F; for (i = 7, bits = 0x0100; i >= 0; i--, bits <<= 1) { if (regs[12] & bits) hwconf->baud_base[i] = 921600; else hwconf->baud_base[i] = 115200; } scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB); outb(scratch2 | UART_LCR_DLAB, cap + UART_LCR); outb(0, cap + UART_EFR); /* EFR is the same as FCR */ outb(scratch2, cap + UART_LCR); outb(UART_FCR_ENABLE_FIFO, cap + UART_FCR); scratch = inb(cap + UART_IIR); if (scratch & 0xC0) hwconf->uart_type = PORT_16550A; else hwconf->uart_type = PORT_16450; if (id == 1) hwconf->ports = 8; else hwconf->ports = 4; return (hwconf->ports);}#define CHIP_SK 0x01 /* Serial Data Clock in Eprom */#define CHIP_DO 0x02 /* Serial Data Output in Eprom */#define CHIP_CS 0x04 /* Serial Chip Select in Eprom */#define CHIP_DI 0x08 /* Serial Data Input in Eprom */#define EN_CCMD 0x000 /* Chip's command register */#define EN0_RSARLO 0x008 /* Remote start address reg 0 */#define EN0_RSARHI 0x009 /* Remote start address reg 1 */#define EN0_RCNTLO 0x00A /* Remote byte count reg WR */#define EN0_RCNTHI 0x00B /* Remote byte count reg WR */#define EN0_DCFG 0x00E /* Data configuration reg WR */#define EN0_PORT 0x010 /* Rcv missed frame error counter RD */#define ENC_PAGE0 0x000 /* Select page 0 of chip registers */#define ENC_PAGE3 0x0C0 /* Select page 3 of chip registers */static int mxser_read_register(int port, unsigned short *regs){ int i, k, value, id; unsigned int j; id = mxser_program_mode(port); if (id < 0) return (id); for (i = 0; i < 14; i++) { k = (i & 0x3F) | 0x180; for (j = 0x100; j > 0; j >>= 1) { outb(CHIP_CS, port); if (k & j) { outb(CHIP_CS | CHIP_DO, port); outb(CHIP_CS | CHIP_DO | CHIP_SK, port); /* A? bit of read */ } else { outb(CHIP_CS, port); outb(CHIP_CS | CHIP_SK, port); /* A? bit of read */ } } (void) inb(port); value = 0; for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) { outb(CHIP_CS, port); outb(CHIP_CS | CHIP_SK, port); if (inb(port) & CHIP_DI) value |= j; } regs[i] = value; outb(0, port); } mxser_normal_mode(port); return (id);}static int mxser_program_mode(int port){ int id, i, j, n; unsigned long flags; save_flags(flags); cli(); outb(0, port); outb(0, port); outb(0, port); (void) inb(port); (void) inb(port); outb(0, port); (void) inb(port); restore_flags(flags); id = inb(port + 1) & 0x1F; if ((id != C168_ASIC_ID) && (id != C104_ASIC_ID) && (id != CI104J_ASIC_ID)) return (-1); for (i = 0, j = 0; i < 4; i++) { n = inb(port + 2); if (n == 'M') { j = 1; } else if ((j == 1) && (n == 1)) { j = 2; break; } else j = 0; } if (j != 2) id = -2; return (id);}static void mxser_normal_mode(int port){ int i, n; outb(0xA5, port + 1); outb(0x80, port + 3); outb(12, port + 0); /* 9600 bps */ outb(0, port + 1); outb(0x03, port + 3); /* 8 data bits */ outb(0x13, port + 4); /* loop back mode */ for (i = 0; i < 16; i++) { n = inb(port + 5); if ((n & 0x61) == 0x60) break; if ((n & 1) == 1) (void) inb(port); } outb(0x00, port + 4);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -