📄 68360serial.c
字号:
* 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 struct tty_struct *serial_console_device(struct console *c, int *index){ *index = c->index; return serial_driver;}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;static const struct tty_operations rs_360_ops = { .owner = THIS_MODULE, .open = rs_360_open, .close = rs_360_close, .write = rs_360_write, .put_char = rs_360_put_char, .write_room = rs_360_write_room, .chars_in_buffer = rs_360_chars_in_buffer, .flush_buffer = rs_360_flush_buffer, .ioctl = rs_360_ioctl, .throttle = rs_360_throttle, .unthrottle = rs_360_unthrottle, /* .send_xchar = rs_360_send_xchar, */ .set_termios = rs_360_set_termios, .stop = rs_360_stop, .start = rs_360_start, .hangup = rs_360_hangup, /* .wait_until_sent = rs_360_wait_until_sent, */ /* .read_proc = rs_360_read_proc, */ .tiocmget = rs_360_tiocmget, .tiocmset = rs_360_tiocmset,};static int __init rs_360_init(void){ struct serial_state * state; ser_info_t *info; void *mem_addr; uint dp_addr, iobits; int i, j, idx; ushort chan; QUICC_BD *bdp; volatile QUICC *cp; volatile struct smc_regs *sp; volatile struct smc_uart_pram *up; volatile struct scc_regs *scp; volatile struct uart_pram *sup; /* volatile immap_t *immap; */ serial_driver = alloc_tty_driver(NR_PORTS); if (!serial_driver) return -1; show_serial_version(); serial_driver->name = "ttyS"; serial_driver->major = TTY_MAJOR; serial_driver->minor_start = 64; 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; tty_set_operations(serial_driver, &rs_360_ops); if (tty_register_driver(serial_driver)) panic("Couldn't register serial driver\n"); cp = pquicc; /* Get pointer to Communication Processor */ /* immap = (immap_t *)IMAP_ADDR; */ /* and to internal registers */ /* Configure SCC2, SCC3, and SCC4 instead of port A parallel I/O. */ /* The "standard" configuration through the 860. *//* immap->im_ioport.iop_papar |= 0x00fc; *//* immap->im_ioport.iop_padir &= ~0x00fc; *//* immap->im_ioport.iop_paodr &= ~0x00fc; */ cp->pio_papar |= 0x00fc; cp->pio_padir &= ~0x00fc; /* cp->pio_paodr &= ~0x00fc; */ /* Since we don't yet do modem control, connect the port C pins * as general purpose I/O. This will assert CTS and CD for the * SCC ports. */ /* FIXME: see 360um p.7-365 and 860um p.34-12 * I can't make sense of these bits - mleslie*//* immap->im_ioport.iop_pcdir |= 0x03c6; *//* immap->im_ioport.iop_pcpar &= ~0x03c6; *//* cp->pio_pcdir |= 0x03c6; *//* cp->pio_pcpar &= ~0x03c6; */ /* Connect SCC2 and SCC3 to NMSI. Connect BRG3 to SCC2 and * BRG4 to SCC3. */ cp->si_sicr &= ~0x00ffff00; cp->si_sicr |= 0x001b1200;#ifdef CONFIG_PP04 /* Frequentis PP04 forced to RS-232 until we know better. * Port C 12 and 13 low enables RS-232 on SCC3 and SCC4. */ immap->im_ioport.iop_pcdir |= 0x000c; immap->im_ioport.iop_pcpar &= ~0x000c; immap->im_ioport.iop_pcdat &= ~0x000c; /* This enables the TX driver. */ cp->cp_pbpar &= ~0x6000; cp->cp_pbdat &= ~0x6000;#endif 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->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%d at irq 0x%02x is an %s\n", i, (unsigned int)(state->irq), (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC");#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(8);/* idx = PORT_NUM(info->state->smc_scc_num); *//* if (info->state->smc_scc_num & NUM_IS_SCC) *//* chan = scc_chan_map[idx]; *//* else *//* chan = smc_chan_map[idx]; *//* cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG; *//* while (cp->cp_cr & CPM_CR_FLG); */#endif /* info = kmalloc(sizeof(ser_info_t), GFP_KERNEL); */ info = &quicc_ser_info[i]; if (info) { memset (info, 0, sizeof(ser_info_t)); info->magic = SERIAL_MAGIC; info->line = i; info->flags = state->flags; INIT_WORK(&info->tqueue, do_softint, info); INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info); init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); 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 = m360_cpm_dpalloc(sizeof(QUICC_BD) * RX_NUM_FIFO); /* Allocate space for FIFOs in the host memory. * (for now this is from a static array of buffers :( */ /* mem_addr = m360_cpm_hostalloc(RX_NUM_FIFO * R
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -