📄 uart.c
字号:
line = MINOR(tty->device) - tty->driver.minor_start; if ((line < 0) || (line >= NR_PORTS)) return -ENODEV; retval = get_async_struct(line, &info); if (retval) return retval; if (serial_paranoia_check(info, tty->device, "rs_open")) return -ENODEV;#ifdef SERIAL_DEBUG_OPEN printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, info->state->count);#endif tty->driver_data = info; info->tty = tty; /* * Start up serial port */ retval = startup(info); if (retval) return retval; MOD_INC_USE_COUNT; retval = block_til_ready(tty, filp, info); if (retval) {#ifdef SERIAL_DEBUG_OPEN printk("rs_open returning after block_til_ready with %d\n", retval);#endif MOD_DEC_USE_COUNT; return retval; } if ((info->state->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) *tty->termios = info->state->normal_termios; else *tty->termios = info->state->callout_termios; change_speed(info); } info->session = current->session; info->pgrp = current->pgrp;#ifdef SERIAL_DEBUG_OPEN printk("rs_open ttys%d successful...", info->line);#endif return 0;}/* * /proc fs routines.... */static int inline line_info(char *buf, struct serial_state *state){#ifdef notdef struct async_struct *info = state->info, scr_info; char stat_buf[30], control, status;#endif int ret; ret = sprintf(buf, "%d: uart:%s port:%X irq:%d", state->line, (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC", (unsigned int)(state->port), state->irq); if (!state->port || (state->type == PORT_UNKNOWN)) { ret += sprintf(buf+ret, "\n"); return ret; }#ifdef notdef /* * Figure out the current RS-232 lines */ if (!info) { info = &scr_info; /* This is just for serial_{in,out} */ info->magic = SERIAL_MAGIC; info->port = state->port; info->flags = state->flags; info->quot = 0; info->tty = 0; } 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_360_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 my_console_write(int idx, const char *s, unsigned count){ struct serial_state *ser; ser_info_t *info; unsigned i; QUICC_BD *bdp, *bdbase; volatile struct smc_uart_pram *up; volatile u_char *cp; ser = rs_table + idx; /* 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 *)&cpmp->cp_dparam[ser->port]; */ up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u; /* Get the address of the host memory buffer. */ bdp = bdbase = (QUICC_BD *)((uint)pquicc + (uint)up->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->status & BD_SC_READY); /* Send the character out. */ cp = bdp->buf; *cp = *s; bdp->length = 1; bdp->status |= BD_SC_READY; if (bdp->status & BD_SC_WRAP) bdp = bdbase; else bdp++; /* if a LF, also do CR... */ if (*s == 10) { while (bdp->status & BD_SC_READY); /* cp = __va(bdp->buf); */ cp = bdp->buf; *cp = 13; bdp->length = 1; bdp->status |= BD_SC_READY; if (bdp->status & BD_SC_WRAP) { bdp = bdbase; } else { bdp++; } } } /* * Finally, Wait for transmitter & holding register to empty * and restore the IER */ while (bdp->status & BD_SC_READY); if (info) info->tx_cur = (QUICC_BD *)bdp;}static void serial_console_write(struct console *c, const char *s, unsigned count){#ifdef CONFIG_KGDB /* Try to let stub handle output. Returns true if it did. */ if (kgdb_output_string(s, count)) return;#endif my_console_write(c->index, s, count);}/*void console_print_68360(const char *p){ const char *cp = p; int i; for (i=0;cp[i]!=0;i++); serial_console_write (p, i); //Comment this if you want to have a strict interrupt-driven output //rs_fair_output(); return;}*/#ifdef CONFIG_XMONintxmon_360_write(const char *s, unsigned count){ my_console_write(0, s, count); return(count);}#endif#ifdef CONFIG_KGDBvoidputDebugChar(char ch){ my_console_write(0, &ch, 1);}#endif/* * Receive character from the serial port. This only works well * before the port is initialized for real use. */static int my_console_wait_key(int idx, int xmon, char *obuf){ struct serial_state *ser; u_char c, *cp; ser_info_t *info; QUICC_BD *bdp; volatile struct smc_uart_pram *up; int i; ser = rs_table + idx; /* 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 = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase]; */ bdp = (QUICC_BD *)((uint)pquicc + (uint)up->tbase); /* Pointer to UART in parameter ram. */ /* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */ up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u; /* * We need to gracefully shut down the receiver, disable * interrupts, then read the input. * XMON just wants a poll. If no character, return -1, else * return the character. */ if (!xmon) { while (bdp->status & BD_SC_EMPTY); } else { if (bdp->status & BD_SC_EMPTY) return -1; } cp = (char *)bdp->buf; if (obuf) { i = c = bdp->length; while (i-- > 0) *obuf++ = *cp++; } else { c = *cp; } bdp->status |= BD_SC_EMPTY; if (info) { if (bdp->status & BD_SC_WRAP) { bdp = info->rx_bd_base; } else { bdp++; } info->rx_cur = (QUICC_BD *)bdp; } return((int)c);}static int serial_console_wait_key(struct console *co){ return(my_console_wait_key(co->index, 0, NULL));}#ifdef CONFIG_XMONintxmon_360_read_poll(void){ return(my_console_wait_key(0, 1, NULL));}intxmon_360_read_char(void){ return(my_console_wait_key(0, 0, NULL));}#endif#ifdef CONFIG_KGDBstatic char kgdb_buf[RX_BUF_SIZE], *kgdp;static int kgdb_chars;unsigned chargetDebugChar(void){ if (kgdb_chars <= 0) { kgdb_chars = my_console_wait_key(0, 0, kgdb_buf); kgdp = kgdb_buf; } kgdb_chars--; return(*kgdp++);}void kgdb_interruptible(int state){}void kgdb_map_scc(void){ struct serial_state *ser; uint mem_addr; volatile QUICC_BD *bdp; volatile smc_uart_t *up; cpmp = (cpm360_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); /* To avoid data cache CPM DMA coherency problems, allocate a * buffer in the CPM DPRAM. This will work until the CPM and * serial ports are initialized. At that time a memory buffer * will be allocated. * The port is already initialized from the boot procedure, all * we do here is give it a different buffer and make it a FIFO. */ ser = rs_table; /* Right now, assume we are using SMCs. */ up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; /* Allocate space for an input FIFO, plus a few bytes for output. * Allocate bytes to maintain word alignment. */ mem_addr = (uint)(&cpmp->cp_dpmem[0x1000]); /* Set the physical address of the host memory buffers in * the buffer descriptors. */ bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase]; bdp->buf = mem_addr; bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_tbase]; bdp->buf = mem_addr+RX_BUF_SIZE; up->smc_mrblr = RX_BUF_SIZE; /* receive buffer length */ up->smc_maxidl = RX_BUF_SIZE;}#endifstatic kdev_t serial_console_device(struct console *c){ return MKDEV(TTY_MAJOR, 64 + c->index);}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 console_360_init(long kmem_start, long kmem_end){ register_console(&sercons); /*register_console (console_print_68360); - 2.0.38 only required a write function pointer. */ return kmem_start;}#endif/* Index in baud rate table of the default console baud rate.*/static int baud_idx;/* int _
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -