mcfserial.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,892 行 · 第 1/4 页
C
1,892 行
if (signal_pending(current)) { retval = -ERESTARTSYS; break; }#ifdef SERIAL_DEBUG_OPEN printk("block_til_ready blocking: ttyS%d, count = %d\n", info->line, info->count);#endif schedule(); } current->state = TASK_RUNNING; remove_wait_queue(&info->open_wait, &wait); if (!tty_hung_up_p(filp)) info->count++; info->blocked_open--;#ifdef SERIAL_DEBUG_OPEN printk("block_til_ready after blocking: ttyS%d, count = %d\n", info->line, info->count);#endif if (retval) return retval; info->flags |= ASYNC_NORMAL_ACTIVE; return 0;} /* * This routine is called whenever a serial port is opened. It * enables interrupts for a serial port, linking in its structure into * the IRQ chain. It also performs the serial-specific * initialization for the tty structure. */int mcfrs_open(struct tty_struct *tty, struct file * filp){ struct mcf_serial *info; int retval, line; line = tty->index; if ((line < 0) || (line >= NR_PORTS)) return -ENODEV; info = mcfrs_table + line; if (serial_paranoia_check(info, tty->name, "mcfrs_open")) return -ENODEV;#ifdef SERIAL_DEBUG_OPEN printk("mcfrs_open %s, count = %d\n", tty->name, info->count);#endif info->count++; tty->driver_data = info; info->tty = tty; /* * Start up serial port */ retval = startup(info); if (retval) return retval; retval = block_til_ready(tty, filp, info); if (retval) {#ifdef SERIAL_DEBUG_OPEN printk("mcfrs_open returning after block_til_ready with %d\n", retval);#endif return retval; }#ifdef SERIAL_DEBUG_OPEN printk("mcfrs_open %s successful...\n", tty->name);#endif return 0;}/* * Based on the line number set up the internal interrupt stuff. */static void mcfrs_irqinit(struct mcf_serial *info){#if defined(CONFIG_M5272) volatile unsigned long *icrp; volatile unsigned long *portp; volatile unsigned char *uartp; uartp = info->addr; icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR2); switch (info->line) { case 0: *icrp = 0xe0000000; break; case 1: *icrp = 0x0e000000; break; default: printk("MCFRS: don't know how to handle UART %d interrupt?\n", info->line); return; } /* Enable the output lines for the serial ports */ portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PBCNT); *portp = (*portp & ~0x000000ff) | 0x00000055; portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PDCNT); *portp = (*portp & ~0x000003fc) | 0x000002a8;#elif defined(CONFIG_M5282) volatile unsigned char *icrp, *uartp; volatile unsigned long *imrp; uartp = info->addr; icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 + MCFINTC_ICR0 + MCFINT_UART0 + info->line); *icrp = 0x33; /* UART0 with level 6, priority 3 */ imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 + MCFINTC_IMRL); *imrp &= ~((1 << (info->irq - 64)) | 1);#else volatile unsigned char *icrp, *uartp; switch (info->line) { case 0: icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART1ICR); *icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1; mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1); break; case 1: icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART2ICR); *icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2; mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2); break; default: printk("MCFRS: don't know how to handle UART %d interrupt?\n", info->line); return; } uartp = info->addr; uartp[MCFUART_UIVR] = info->irq;#endif /* Clear mask, so no surprise interrupts. */ uartp[MCFUART_UIMR] = 0; if (request_irq(info->irq, mcfrs_interrupt, SA_INTERRUPT, "ColdFire UART", NULL)) { printk("MCFRS: Unable to attach ColdFire UART %d interrupt " "vector=%d\n", info->line, info->irq); } return;}char *mcfrs_drivername = "ColdFire internal UART serial driver version 1.00\n";/* * Serial stats reporting... */int mcfrs_readproc(char *page, char **start, off_t off, int count, int *eof, void *data){ struct mcf_serial *info; char str[20]; int len, sigs, i; len = sprintf(page, mcfrs_drivername); for (i = 0; (i < NR_PORTS); i++) { info = &mcfrs_table[i]; len += sprintf((page + len), "%d: port:%x irq=%d baud:%d ", i, (unsigned int) info->addr, info->irq, info->baud); if (info->stats.rx || info->stats.tx) len += sprintf((page + len), "tx:%d rx:%d ", info->stats.tx, info->stats.rx); if (info->stats.rxframing) len += sprintf((page + len), "fe:%d ", info->stats.rxframing); if (info->stats.rxparity) len += sprintf((page + len), "pe:%d ", info->stats.rxparity); if (info->stats.rxbreak) len += sprintf((page + len), "brk:%d ", info->stats.rxbreak); if (info->stats.rxoverrun) len += sprintf((page + len), "oe:%d ", info->stats.rxoverrun); str[0] = str[1] = 0; if ((sigs = mcfrs_getsignals(info))) { if (sigs & TIOCM_RTS) strcat(str, "|RTS"); if (sigs & TIOCM_CTS) strcat(str, "|CTS"); if (sigs & TIOCM_DTR) strcat(str, "|DTR"); if (sigs & TIOCM_CD) strcat(str, "|CD"); } len += sprintf((page + len), "%s\n", &str[1]); } return(len);}/* Finally, routines used to initialize the serial driver. */static void show_serial_version(void){ printk(mcfrs_drivername);}static struct tty_operations mcfrs_ops = { .open = mcfrs_open, .close = mcfrs_close, .write = mcfrs_write, .flush_chars = mcfrs_flush_chars, .write_room = mcfrs_write_room, .chars_in_buffer = mcfrs_chars_in_buffer, .flush_buffer = mcfrs_flush_buffer, .ioctl = mcfrs_ioctl, .throttle = mcfrs_throttle, .unthrottle = mcfrs_unthrottle, .set_termios = mcfrs_set_termios, .stop = mcfrs_stop, .start = mcfrs_start, .hangup = mcfrs_hangup, .read_proc = mcfrs_readproc, .wait_until_sent = mcfrs_wait_until_sent, .tiocmget = mcfrs_tiocmget, .tiocmset = mcfrs_tiocmset,};/* mcfrs_init inits the driver */static int __initmcfrs_init(void){ struct mcf_serial *info; unsigned long flags; int i; /* Setup base handler, and timer table. */#ifdef MCFPP_DCD0 init_timer(&mcfrs_timer_struct); mcfrs_timer_struct.function = mcfrs_timer; mcfrs_timer_struct.data = 0; mcfrs_timer_struct.expires = jiffies + HZ/25; add_timer(&mcfrs_timer_struct); mcfrs_ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1);#endif mcfrs_serial_driver = alloc_tty_driver(NR_PORTS); if (!mcfrs_serial_driver) return -ENOMEM; show_serial_version(); /* Initialize the tty_driver structure */ mcfrs_serial_driver->owner = THIS_MODULE; mcfrs_serial_driver->name = "ttyS"; mcfrs_serial_driver->devfs_name = "ttys/"; mcfrs_serial_driver->driver_name = "serial"; mcfrs_serial_driver->major = TTY_MAJOR; mcfrs_serial_driver->minor_start = 64; mcfrs_serial_driver->type = TTY_DRIVER_TYPE_SERIAL; mcfrs_serial_driver->subtype = SERIAL_TYPE_NORMAL; mcfrs_serial_driver->init_termios = tty_std_termios; mcfrs_serial_driver->init_termios.c_cflag = mcfrs_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL; mcfrs_serial_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(mcfrs_serial_driver, &mcfrs_ops); if (tty_register_driver(mcfrs_serial_driver)) { printk("MCFRS: Couldn't register serial driver\n"); put_tty_driver(mcfrs_serial_driver); return(-EBUSY); } local_irq_save(flags); /* * Configure all the attached serial ports. */ for (i = 0, info = mcfrs_table; (i < NR_PORTS); i++, info++) { info->magic = SERIAL_MAGIC; info->line = i; info->tty = 0; info->custom_divisor = 16; info->close_delay = 50; info->closing_wait = 3000; info->x_char = 0; info->event = 0; info->count = 0; info->blocked_open = 0; INIT_WORK(&info->tqueue, mcfrs_offintr, info); INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info); init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); info->imr = 0; mcfrs_setsignals(info, 0, 0); mcfrs_irqinit(info); printk("ttyS%d at 0x%04x (irq = %d)", info->line, (unsigned int) info->addr, info->irq); printk(" is a builtin ColdFire UART\n"); } local_irq_restore(flags); return 0;}module_init(mcfrs_init);/****************************************************************************//* Serial Console *//****************************************************************************//* * Quick and dirty UART initialization, for console output. */void mcfrs_init_console(void){ volatile unsigned char *uartp; unsigned int clk; /* * Reset UART, get it into known state... */ uartp = (volatile unsigned char *) (MCF_MBAR + (mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1)); uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR; /* reset MR pointer */ /* * Set port for defined baud , 8 data bits, 1 stop bit, no parity. */ uartp[MCFUART_UMR] = MCFUART_MR1_PARITYNONE | MCFUART_MR1_CS8; uartp[MCFUART_UMR] = MCFUART_MR2_STOP1; clk = ((MCF_BUSCLK / mcfrs_console_baud) + 16) / 32; /* set baud */ uartp[MCFUART_UBG1] = (clk & 0xff00) >> 8; /* set msb baud */ uartp[MCFUART_UBG2] = (clk & 0xff); /* set lsb baud */ uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER; uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE; mcfrs_console_inited++; return;}/* * Setup for console. Argument comes from the boot command line. */int mcfrs_console_setup(struct console *cp, char *arg){ int i, n = CONSOLE_BAUD_RATE; if (!cp) return(-1); if (!strncmp(cp->name, "ttyS", 4)) mcfrs_console_port = cp->index; else if (!strncmp(cp->name, "cua", 3)) mcfrs_console_port = cp->index; else return(-1); if (arg) n = simple_strtoul(arg,NULL,0); for (i = 0; i < MCFRS_BAUD_TABLE_SIZE; i++) if (mcfrs_baud_table[i] == n) break; if (i < MCFRS_BAUD_TABLE_SIZE) { mcfrs_console_baud = n; mcfrs_console_cbaud = 0; if (i > 15) { mcfrs_console_cbaud |= CBAUDEX; i -= 15; } mcfrs_console_cbaud |= i; } mcfrs_init_console(); /* make sure baud rate changes */ return(0);}static struct tty_driver *mcfrs_console_device(struct console *c, int *index){ *index = c->index; return mcfrs_serial_driver;}/* * Output a single character, using UART polled mode. * This is used for console output. */void mcfrs_put_char(char ch){ volatile unsigned char *uartp; unsigned long flags; int i; uartp = (volatile unsigned char *) (MCF_MBAR + (mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1)); local_irq_save(flags); for (i = 0; (i < 0x10000); i++) { if (uartp[MCFUART_USR] & MCFUART_USR_TXREADY) break; } if (i < 0x10000) { uartp[MCFUART_UTB] = ch; for (i = 0; (i < 0x10000); i++) if (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY) break; } if (i >= 0x10000) mcfrs_init_console(); /* try and get it back */ local_irq_restore(flags); return;}/* * rs_console_write is registered for printk output. */void mcfrs_console_write(struct console *cp, const char *p, unsigned len){ if (!mcfrs_console_inited) mcfrs_init_console(); while (len-- > 0) { if (*p == '\n') mcfrs_put_char('\r'); mcfrs_put_char(*p++); }}/* * declare our consoles */struct console mcfrs_console = { .name = "ttyS", .write = mcfrs_console_write, .device = mcfrs_console_device, .setup = mcfrs_console_setup, .flags = CON_PRINTBUFFER, .index = -1,};static int __init mcfrs_console_init(void){ register_console(&mcfrs_console); return 0;}console_initcall(mcfrs_console_init);/****************************************************************************/
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?