__initfunc(static enum uart check_uart(unsigned int iobase)) { unsigned char b1,b2,b3; enum uart u; enum uart uart_tab[] = { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A }; if (iobase <= 0 || iobase > 0x1000-SER_EXTENT) return c_uart_unknown; if (check_region(iobase, SER_EXTENT)) return c_uart_unknown; b1 = inb(UART_MCR(iobase)); outb(b1 | 0x10, UART_MCR(iobase)); /* loopback mode */ b2 = inb(UART_MSR(iobase)); outb(0x1a, UART_MCR(iobase)); b3 = inb(UART_MSR(iobase)) & 0xf0; outb(b1, UART_MCR(iobase)); /* restore old values */ outb(b2, UART_MSR(iobase)); if (b3 != 0x90) return c_uart_unknown; inb(UART_RBR(iobase)); inb(UART_RBR(iobase)); outb(0x01, UART_FCR(iobase)); /* enable FIFOs */ u = uart_tab[(inb(UART_IIR(iobase)) >> 6) & 3]; if (u == c_uart_16450) { outb(0x5a, UART_SCR(iobase)); b1 = inb(UART_SCR(iobase)); outb(0xa5, UART_SCR(iobase)); b2 = inb(UART_SCR(iobase)); if ((b1 != 0x5a) || (b2 != 0xa5)) u = c_uart_8250; } return u; }
/* * This is the serial driver's generic interrupt routine * Note: Generally it should be attached to general interrupt 10, responsile * for UART0&1 RCV and XMT interrupt, to make sure the invoked interrupt * source, look into bit 10-13 of SIC_ISR(peripheral interrupt status reg. * Finally, to see what can be done about request_irq(......) */ void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct bf535_serial *info; // = &bf535_soft[CONFIG_SERIAL_CONSOLE_PORT]; unsigned short iir; /* Interrupt Identification Register */ unsigned short rx, idx; unsigned int sic_status = SIC_ISR; for (idx = 0; idx < NR_PORTS; idx++){ if (sic_status & (UART_INVOKED << 2*(idx + 5))){ /* test bit 10-11 and 12-13 */ iir = UART_IIR(idx); info = &bf535_soft[idx]; if (!(iir & UART_IIR_NOINT)){ switch (iir & UART_IIR_STATUS){ case UART_IIR_LSR: printk("Line status changed for serial port %d.\n", idx); break; case UART_IIR_RBR: /* Change access to IER & data port */ ACCESS_PORT_IER(idx) if (UART_LSR(idx) & UART_LSR_DR){ rx = UART_RBR(idx); receive_chars(info, regs, rx); } break; case UART_IIR_THR: /* Change access to IER & data port */ ACCESS_PORT_IER(idx) if (UART_LSR(idx) & UART_LSR_THRE){ transmit_chars(info); // do{ // transmit_chars(info); // }while(info->xmit_cnt > 0); } break; case UART_IIR_MSR: printk("Modem status changed for serial port.\n"); } } } }