📄 uart.c
字号:
} cli(); status = serial_in(info, UART_MSR); control = info ? info->MCR : serial_in(info, UART_MCR); sti(); stat_buf[0] = 0; stat_buf[1] = 0; if (control & UART_MCR_RTS) strcat(stat_buf, "|RTS"); if (status & UART_MSR_CTS) strcat(stat_buf, "|CTS"); if (control & UART_MCR_DTR) strcat(stat_buf, "|DTR"); if (status & UART_MSR_DSR) strcat(stat_buf, "|DSR"); if (status & UART_MSR_DCD) strcat(stat_buf, "|CD"); if (status & UART_MSR_RI) strcat(stat_buf, "|RI"); if (info->quot) { ret += sprintf(buf+ret, " baud:%d", state->baud_base / info->quot); } ret += sprintf(buf+ret, " tx:%d rx:%d", state->icount.tx, state->icount.rx); if (state->icount.frame) ret += sprintf(buf+ret, " fe:%d", state->icount.frame); if (state->icount.parity) ret += sprintf(buf+ret, " pe:%d", state->icount.parity); if (state->icount.brk) ret += sprintf(buf+ret, " brk:%d", state->icount.brk); if (state->icount.overrun) ret += sprintf(buf+ret, " oe:%d", state->icount.overrun); /* * Last thing is the RS-232 status lines */ ret += sprintf(buf+ret, " %s\n", stat_buf+1);#endif return ret;}int rs_8xx_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ int i, len = 0; off_t begin = 0; len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); for (i = 0; i < NR_PORTS && len < 4000; i++) { len += line_info(page + len, &rs_table[i]); if (len+begin > off+count) goto done; if (len+begin < off) { begin += len; len = 0; } } *eof = 1;done: if (off >= len+begin) return 0; *start = page + (begin-off); return ((count < begin+len-off) ? count : begin+len-off);}/* * --------------------------------------------------------------------- * rs_init() and friends * * rs_init() is called at boot-time to initialize the serial driver. * --------------------------------------------------------------------- *//* * This routine prints out the appropriate serial driver version * number, and identifies which options were configured into this * driver. */static _INLINE_ void show_serial_version(void){ printk(KERN_INFO "%s version %s\n", serial_name, serial_version);}/* * The serial console driver used during boot. Note that these names * clash with those found in "serial.c", so we currently can't support * the 16xxx uarts and these at the same time. I will fix this to become * an indirect function call from tty_io.c (or something). */#ifdef CONFIG_SERIAL_CONSOLE/* * Print a string to the serial port trying not to disturb any possible * real use of the port... */static void serial_console_write(struct console *c, const char *s, unsigned count){ struct serial_state *ser; ser_info_t *info; unsigned i; volatile cbd_t *bdp, *bdbase; volatile smc_uart_t *up; volatile u_char *cp; ser = rs_table + c->index; /* If the port has been initialized for general use, we have * to use the buffer descriptors allocated there. Otherwise, * we simply use the single buffer allocated. */ if ((info = (ser_info_t *)ser->info) != NULL) { bdp = info->tx_cur; bdbase = info->tx_bd_base; } else { /* Pointer to UART in parameter ram. */ up = (smc_uart_t *)&immr->im_dprambase[ser->port]; /* Get the address of the host memory buffer. */ bdp = bdbase = (cbd_t *)&immr->im_dprambase[up->smc_tbase]; } /* * We need to gracefully shut down the transmitter, disable * interrupts, then send our bytes out. */ /* * Now, do each character. This is not as bad as it looks * since this is a holding FIFO and not a transmitting FIFO. * We could add the complexity of filling the entire transmit * buffer, but we would just wait longer between accesses...... */ for (i = 0; i < count; i++, s++) { /* Wait for transmitter fifo to empty. * Ready indicates output is ready, and xmt is doing * that, not that it is ready for us to send. */ while (bdp->cbd_sc & BD_SC_READY); /* Send the character out. */ cp = __va(bdp->cbd_bufaddr); *cp = *s; bdp->cbd_datlen = 1; bdp->cbd_sc |= BD_SC_READY; if (bdp->cbd_sc & BD_SC_WRAP) bdp = bdbase; else bdp++; /* if a LF, also do CR... */ if (*s == 10) { while (bdp->cbd_sc & BD_SC_READY); cp = __va(bdp->cbd_bufaddr); *cp = 13; bdp->cbd_datlen = 1; bdp->cbd_sc |= BD_SC_READY; if (bdp->cbd_sc & BD_SC_WRAP) { bdp = bdbase; } else { bdp++; } } } /* * Finally, Wait for transmitter & holding register to empty * and restore the IER */ while (bdp->cbd_sc & BD_SC_READY); if (info) info->tx_cur = (cbd_t *)bdp;}/* * Receive character from the serial port. This only works well * before the port is initialize for real use. */static int serial_console_wait_key(struct console *co){ struct serial_state *ser; u_char c, *cp; ser_info_t *info; volatile cbd_t *bdp; volatile smc_uart_t *up; ser = rs_table + co->index; /* Pointer to UART in parameter ram. */ up = (smc_uart_t *)&immr->im_dprambase[ser->port]; /* Get the address of the host memory buffer. * If the port has been initialized for general use, we must * use information from the port structure. */ if ((info = (ser_info_t *)ser->info)) bdp = info->rx_cur; else bdp = (cbd_t *)&immr->im_dprambase[up->smc_rbase]; /* * We need to gracefully shut down the receiver, disable * interrupts, then read the input. */ while (bdp->cbd_sc & BD_SC_EMPTY); /* Wait for a character */ cp = __va(bdp->cbd_bufaddr); if (info) { if (bdp->cbd_sc & BD_SC_WRAP) { bdp = info->rx_bd_base; } else { bdp++; } info->rx_cur = (cbd_t *)bdp; } c = *cp; return((int)c);}static kdev_t serial_console_device(struct console *c){ return MKDEV(TTYAUX_MAJOR, 64 + c->index);}static struct console sercons = { name: "ttyS", write: serial_console_write, device: serial_console_device, wait_key: serial_console_wait_key, setup: serial_console_setup, flags: CON_PRINTBUFFER, index: CONFIG_SERIAL_CONSOLE_PORT,};/* * Register console. */long __init console_8xx_init(long kmem_start, long kmem_end){ register_console(&sercons); return kmem_start;}#endif/* Default console baud rate as determined by the board information * structure. */static int baud_idx;/* * The serial driver boot-time initialization code! */int __init rs_8xx_init(void){ struct serial_state * state; ser_info_t *info; uint mem_addr, dp_addr; int i, j, idx; uint page, sblock; volatile cbd_t *bdp; volatile cpm8260_t *cp; volatile smc_t *sp; volatile smc_uart_t *up; volatile scc_t *scp; volatile scc_uart_t *sup; volatile immap_t *immap; volatile iop8260_t *io; init_bh(SERIAL_BH, do_serial_bh); show_serial_version(); /* Initialize the tty_driver structure */ /*memset(&serial_driver, 0, sizeof(struct tty_driver));*/ __clear_user(&serial_driver,sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; serial_driver.driver_name = "serial"; serial_driver.name = "ttyS"; serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64; serial_driver.num = NR_PORTS; serial_driver.type = TTY_DRIVER_TYPE_SERIAL; serial_driver.subtype = SERIAL_TYPE_NORMAL; serial_driver.init_termios = tty_std_termios; serial_driver.init_termios.c_cflag = baud_idx | CS8 | CREAD | HUPCL | CLOCAL; serial_driver.flags = TTY_DRIVER_REAL_RAW; serial_driver.refcount = &serial_refcount; serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; serial_driver.open = rs_8xx_open; serial_driver.close = rs_8xx_close; serial_driver.write = rs_8xx_write; serial_driver.put_char = rs_8xx_put_char; serial_driver.write_room = rs_8xx_write_room; serial_driver.chars_in_buffer = rs_8xx_chars_in_buffer; serial_driver.flush_buffer = rs_8xx_flush_buffer; serial_driver.ioctl = rs_8xx_ioctl; serial_driver.throttle = rs_8xx_throttle; serial_driver.unthrottle = rs_8xx_unthrottle; serial_driver.send_xchar = rs_8xx_send_xchar; serial_driver.set_termios = rs_8xx_set_termios; serial_driver.stop = rs_8xx_stop; serial_driver.start = rs_8xx_start; serial_driver.hangup = rs_8xx_hangup; serial_driver.wait_until_sent = rs_8xx_wait_until_sent; serial_driver.read_proc = rs_8xx_read_proc; /* * The callout device is just like normal device except for * major number and the subtype code. */ callout_driver = serial_driver; callout_driver.name = "cua"; callout_driver.major = TTYAUX_MAJOR; callout_driver.subtype = SERIAL_TYPE_CALLOUT; callout_driver.read_proc = 0; callout_driver.proc_entry = 0; if (tty_register_driver(&serial_driver)) panic("Couldn't register serial driver\n"); if (tty_register_driver(&callout_driver)) panic("Couldn't register callout driver\n"); immap = immr; cp = &immap->im_cpm; io = &immap->im_ioport; /* This should have been done long ago by the early boot code, * but do it again to make sure. */ *(ushort *)(&immap->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1; *(ushort *)(&immap->im_dprambase[PROFF_SMC2_BASE]) = PROFF_SMC2; /* Geeze, here we go....Picking I/O port bits....Lots of * choices. If you don't like mine, pick your own. * Configure SMCs Tx/Rx. SMC1 is only on Port D, SMC2 is * only on Port A. You either pick 'em, or not. */ io->iop_ppard |= 0x00c00000; io->iop_pdird |= 0x00400000; io->iop_pdird &= ~0x00800000; io->iop_psord &= ~0x00c00000;#if USE_SMC2 io->iop_ppara |= 0x00c00000; io->iop_pdira |= 0x00400000; io->iop_pdira &= ~0x00800000; io->iop_psora &= ~0x00c00000;#endif /* Configure SCC2 and SCC3. Be careful about the fine print. * Secondary options are only available when you take away * the primary option. Unless the pins are used for something * else, SCC2 and SCC3 are on Port B. * Port B, 8 - SCC3 TxD * Port B, 12 - SCC2 TxD * Port B, 14 - SCC3 RxD * Port B, 15 - SCC2 RxD */ io->iop_pparb |= 0x008b0000; io->iop_pdirb |= 0x00880000; io->iop_psorb |= 0x00880000; io->iop_pdirb &= ~0x00030000; io->iop_psorb &= ~0x00030000; /* Wire BRG1 to SMC1 and BRG2 to SMC2. */ immap->im_cpmux.cmx_smr = 0; /* Connect SCC2 and SCC3 to NMSI. Connect BRG3 to SCC2 and * BRG4 to SCC3. */ immap->im_cpmux.cmx_scr &= ~0x00ffff00; immap->im_cpmux.cmx_scr |= 0x00121b00; for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { state->magic = SSTATE_MAGIC; state->line = i; state->type = PORT_UNKNOWN; state->custom_divisor = 0; state->close_delay = 5*HZ/10; state->closing_wait = 30*HZ; state->callout_termios = callout_driver.init_termios; state->normal_termios = serial_driver.init_termios; state->icount.cts = state->icount.dsr = state->icount.rng = state->icount.dcd = 0; state->icount.rx = state->icount.tx = 0; state->icount.frame = state->icount.parity = 0; state->icount.overrun = state->icount.brk = 0; printk(KERN_INFO "ttyS%02d at 0x%04x is a %s\n", i, state->port, (state->smc_scc_num < SCC_NUM_BASE) ? "SMC" : "SCC");#ifdef CONFIG_SERIAL_CONSOLE /* If we just printed the message on the console port, and * we are about to initialize it for general use, we have * to wait a couple of character times for the CR/NL to * make it out of the transmit buffer. */ if (i == CONFIG_SERIAL_CONSOLE_PORT) mdelay(2);#endif info = kmalloc(sizeof(ser_info_t), GFP_KERNEL); if (info) { /*memset(info, 0, sizeof(ser_info_t));*/ __clear_user(info,sizeof(ser_info_t)); init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); info->magic = SERIAL_MAGIC; info->flags = state->flags; info->tqueue.routine = do_softint; info->tqueue.data = info; info->tqueue_hangup.routine = do_serial_hangup; info->tqueue_hangup.data = info; info->line = i; info->state = state; state->info = (struct async_struct *)info; /* We need to allocate a transmit and receive buffer * descriptors from dual port ram, and a character * buffer area from host mem. */ dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_NUM_FIFO, 8); /* Allocate space for FIFOs in the host memory. */ mem_addr = m8260_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE, 1); /* Set the physical address of the host memory * buffers in the buffer descriptors, and the * virtual address for us to work with. */ bdp = (cbd_t *)&immap->im_dprambase[dp_addr]; info->rx_cur = info->rx_bd_base = (cbd_t *)bdp; for (j=0; j<(RX_NUM_FIFO-1); j++) { bdp->cbd_bufaddr = __pa(mem_addr); bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT; mem_addr += RX_BUF_SIZE; bdp++; } bdp->cbd_bufaddr = __pa(mem_addr); bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; if ((idx = state->smc_scc_num) < SCC_NUM_BASE) { sp = &immap->im_smc[idx]; up = (smc_uart_t *)&immap->im_dprambase[state->port]; up->smc_rbase = dp_addr; } else { scp = &immap->im_scc[idx - SCC_IDX_BASE]; sup = (scc_uart_t *)&immap->im_dprambase[state->port]; sup->scc_genscc.scc_rbase = dp_addr; } dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_NUM_FIFO, 8); /* Allocate space for FIFOs in the host memory. */ mem_addr = m8260_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE, 1); /* Set the physical address of the host memory * buffers in the buffer descriptors, and the * virtual address for us to work with. */ bdp = (cbd_t *)&immap->im_dprambase[dp_addr]; info->tx_cur = info->tx_bd_base = (cbd_t *)bdp; for (j=0; j<(TX_NUM_FIFO-1); j++) { bdp->cbd_bufaddr = __pa(mem_addr); bdp->cbd_sc = BD_SC_INTRPT; mem_addr += TX_BUF_SIZE; bdp++; } bdp->cbd_bufaddr = __pa(mem_addr); bdp->cbd_sc = (BD_SC_WRAP | BD_SC_INTRPT); if (idx < SCC_NUM_BASE) { up->smc_tbase = dp_addr; /* Set up the uart parameters in the * param
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -