⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serial_sicc.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
    /*     * If the transmitter hasn't cleared in twice the approximate     * amount of time to send the entire FIFO, it probably won't     * ever clear.  This assumes the UART isn't doing flow     * control, which is currently the case.  Hence, if it ever     * takes longer than info->timeout, this is probably due to a     * UART bug of some kind.  So, we clamp the timeout parameter at     * 2*info->timeout.     */    if (!timeout || timeout > 2 * info->timeout)        timeout = 2 * info->timeout;    expire = jiffies + timeout;    pr_debug("siccuart_wait_until_sent(%d), jiff=%lu, expire=%lu  char_time=%lu...\n",           tty->index, jiffies,           expire, char_time);    while ((readb(info->port->uart_base + BL_SICC_LSR) & _LSR_TX_ALL) != _LSR_TX_ALL) {        set_current_state(TASK_INTERRUPTIBLE);        schedule_timeout(char_time);        if (signal_pending(current))            break;        if (timeout && time_after(jiffies, expire))            break;    }    set_current_state(TASK_RUNNING);}static void siccuart_hangup(struct tty_struct *tty){    struct SICC_info *info = tty->driver_data;    struct SICC_state *state = info->state;    siccuart_flush_buffer(tty);    if (info->flags & ASYNC_CLOSING)        return;    siccuart_shutdown(info);    info->event = 0;    state->count = 0;    info->flags &= ~ASYNC_NORMAL_ACTIVE;    info->tty = NULL;    wake_up_interruptible(&info->open_wait);}static int block_til_ready(struct tty_struct *tty, struct file *filp,               struct SICC_info *info){    DECLARE_WAITQUEUE(wait, current);    struct SICC_state *state = info->state;    unsigned long flags;    int do_clocal = 0, extra_count = 0, retval;    /*     * If the device is in the middle of being closed, then block     * until it's done, and then try again.     */    if (tty_hung_up_p(filp) ||        (info->flags & ASYNC_CLOSING)) {        if (info->flags & ASYNC_CLOSING)            interruptible_sleep_on(&info->close_wait);        return (info->flags & ASYNC_HUP_NOTIFY) ?            -EAGAIN : -ERESTARTSYS;    }    /*     * If non-blocking mode is set, or the port is not enabled,     * then make the check up front and then exit.     */    if ((filp->f_flags & O_NONBLOCK) ||        (tty->flags & (1 << TTY_IO_ERROR))) {        info->flags |= ASYNC_NORMAL_ACTIVE;        return 0;    }    if (tty->termios->c_cflag & CLOCAL)	do_clocal = 1;    /*     * Block waiting for the carrier detect and the line to become     * free (i.e., not in use by the callout).  While we are in     * this loop, state->count is dropped by one, so that     * rs_close() knows when to free things.  We restore it upon     * exit, either normal or abnormal.     */    retval = 0;    add_wait_queue(&info->open_wait, &wait);    save_flags(flags); cli();    if (!tty_hung_up_p(filp)) {        extra_count = 1;        state->count--;    }    restore_flags(flags);    info->blocked_open++;    while (1) {        save_flags(flags); cli();        if (tty->termios->c_cflag & CBAUD) {            info->mctrl = TIOCM_DTR | TIOCM_RTS;            info->port->set_mctrl(info->port, info->mctrl);        }        restore_flags(flags);        set_current_state(TASK_INTERRUPTIBLE);        if (tty_hung_up_p(filp) ||            !(info->flags & ASYNC_INITIALIZED)) {            if (info->flags & ASYNC_HUP_NOTIFY)                retval = -EAGAIN;            else                retval = -ERESTARTSYS;            break;        }        if (!(info->flags & ASYNC_CLOSING) &&            (do_clocal /*|| (UART_GET_FR(info->port) & SICC_UARTFR_DCD)*/))            break;        if (signal_pending(current)) {            retval = -ERESTARTSYS;            break;        }        schedule();    }    set_current_state(TASK_RUNNING);    remove_wait_queue(&info->open_wait, &wait);    if (extra_count)        state->count++;    info->blocked_open--;    if (retval)        return retval;    info->flags |= ASYNC_NORMAL_ACTIVE;    return 0;}static struct SICC_info *siccuart_get(int line){    struct SICC_info *info;    struct SICC_state *state = sicc_state + line;    state->count++;    if (state->info)        return state->info;    info = kmalloc(sizeof(struct SICC_info), GFP_KERNEL);    if (info) {        memset(info, 0, sizeof(struct SICC_info));        init_waitqueue_head(&info->open_wait);        init_waitqueue_head(&info->close_wait);        init_waitqueue_head(&info->delta_msr_wait);        info->flags = state->flags;        info->state = state;        info->port  = sicc_ports + line;        tasklet_init(&info->tlet, siccuart_tasklet_action,                 (unsigned long)info);    }    if (state->info) {        kfree(info);        return state->info;    }    state->info = info;    return info;}static int siccuart_open(struct tty_struct *tty, struct file *filp){    struct SICC_info *info;    int retval, line = tty->index;    // is this a line that we've got?    if (line >= SERIAL_SICC_NR) {        return -ENODEV;    }    info = siccuart_get(line);    if (!info)        return -ENOMEM;    tty->driver_data = info;    info->tty = tty;    info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;    /*     * Make sure we have the temporary buffer allocated     */    if (!tmp_buf) {        unsigned long page = get_zeroed_page(GFP_KERNEL);        if (tmp_buf)            free_page(page);        else if (!page) {            return -ENOMEM;        }        tmp_buf = (u_char *)page;    }    /*     * If the port is in the middle of closing, bail out now.     */    if (tty_hung_up_p(filp) ||        (info->flags & ASYNC_CLOSING)) {        if (info->flags & ASYNC_CLOSING)            interruptible_sleep_on(&info->close_wait);        return -EAGAIN;    }    /*     * Start up the serial port     */    retval = siccuart_startup(info);    if (retval) {        return retval;    }    retval = block_til_ready(tty, filp, info);    if (retval) {        return retval;    }#ifdef CONFIG_SERIAL_SICC_CONSOLE    if (siccuart_cons.cflag && siccuart_cons.index == line) {        tty->termios->c_cflag = siccuart_cons.cflag;        siccuart_cons.cflag = 0;        siccuart_change_speed(info, NULL);    }#endif    return 0;}static struct tty_operations sicc_ops = {	.open = siccuart_open,	.close = siccuart_close,	.write = siccuart_write,	.put_char = siccuart_put_char,	.flush_chars = siccuart_flush_chars,	.write_room = siccuart_write_room,	.chars_in_buffer = siccuart_chars_in_buffer,	.flush_buffer  = siccuart_flush_buffer,	.ioctl = siccuart_ioctl,	.throttle = siccuart_throttle,	.unthrottle = siccuart_unthrottle,	.send_xchar = siccuart_send_xchar,	.set_termios = siccuart_set_termios,	.stop = siccuart_stop,	.start = siccuart_start,	.hangup = siccuart_hangup,	.break_ctl = siccuart_break_ctl,	.wait_until_sent = siccuart_wait_until_sent,};int __init siccuart_init(void){    int i;    siccnormal_driver = alloc_tty_driver(SERIAL_SICC_NR);    if (!siccnormal_driver)	return -ENOMEM;    printk("IBM Vesta SICC serial port driver V 0.1 by Yudong Yang and Yi Ge / IBM CRL .\n");    siccnormal_driver->driver_name = "serial_sicc";    siccnormal_driver->owner = THIS_MODULE;    siccnormal_driver->name = SERIAL_SICC_NAME;    siccnormal_driver->major = SERIAL_SICC_MAJOR;    siccnormal_driver->minor_start = SERIAL_SICC_MINOR;    siccnormal_driver->type = TTY_DRIVER_TYPE_SERIAL;    siccnormal_driver->subtype = SERIAL_TYPE_NORMAL;    siccnormal_driver->init_termios = tty_std_termios;    siccnormal_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;    siccnormal_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;    tty_set_operations(siccnormal_driver, &sicc_ops);    if (tty_register_driver(siccnormal_driver))        panic("Couldn't register SICC serial driver\n");    for (i = 0; i < SERIAL_SICC_NR; i++) {        struct SICC_state *state = sicc_state + i;        state->line     = i;        state->close_delay  = 5 * HZ / 10;        state->closing_wait = 30 * HZ;    }    return 0;}__initcall(siccuart_init);#ifdef CONFIG_SERIAL_SICC_CONSOLE/************** console driver *****************//* * This code is currently never used; console->read is never called. * Therefore, although we have an implementation, we don't use it. * FIXME: the "const char *s" should be fixed to "char *s" some day. * (when the definition in include/linux/console.h is also fixed) */#ifdef used_and_not_const_char_pointerstatic int siccuart_console_read(struct console *co, const char *s, u_int count){    struct SICC_port *port = &sicc_ports[co->index];    unsigned int status;    char *w;    int c;    pr_debug("siccuart_console_read() called\n");    c = 0;    w = s;    while (c < count) {        if(readb(port->uart_base +  BL_SICC_LSR) & _LSR_RBR_FULL) {            *w++ = readb(port->uart_base +  BL_SICC_RBR);            c++;        } else {            // nothing more to get, return            return c;        }    }    // return the count    return c;}#endif/* *  Print a string to the serial port trying not to disturb *  any possible real use of the port... * *  The console_lock must be held when we get here. */static void siccuart_console_write(struct console *co, const char *s, u_int count){    struct SICC_port *port = &sicc_ports[co->index];    unsigned int old_cr;    int i;    /*     *  First save the CR then disable the interrupts     */    old_cr = readb(port->uart_base +  BL_SICC_TxCR);    writeb(old_cr & ~_TxCR_DME_MASK, port->uart_base +  BL_SICC_TxCR);    /*     *  Now, do each character     */    for (i = 0; i < count; i++) {        while ((readb(port->uart_base +  BL_SICC_LSR)&_LSR_TX_ALL) != _LSR_TX_ALL);        writeb(s[i], port->uart_base +  BL_SICC_TBR);        if (s[i] == '\n') {            while ((readb(port->uart_base +  BL_SICC_LSR)&_LSR_TX_ALL) != _LSR_TX_ALL);            writeb('\r', port->uart_base +  BL_SICC_TBR);        }    }    /*     *  Finally, wait for transmitter to become empty     *  and restore the TCR     */    while ((readb(port->uart_base +  BL_SICC_LSR)&_LSR_TX_ALL) != _LSR_TX_ALL);    writeb(old_cr, port->uart_base +  BL_SICC_TxCR);}/* *  Receive character from the serial port */static int siccuart_console_wait_key(struct console *co){    struct SICC_port *port = &sicc_ports[co->index];    int c;    while(!(readb(port->uart_base +  BL_SICC_LSR) & _LSR_RBR_FULL));    c = readb(port->uart_base +  BL_SICC_RBR);    return c;}static struct tty_driver *siccuart_console_device(struct console *c, int *index){	*index = c->index;	return siccnormal_driver;}static int __init siccuart_console_setup(struct console *co, char *options){    struct SICC_port *port;    int baud = 9600;    int bits = 8;    int parity = 'n';    u_int cflag = CREAD | HUPCL | CLOCAL;    u_int lcr_h, quot;    if (co->index >= SERIAL_SICC_NR)        co->index = 0;    port = &sicc_ports[co->index];    if (port->uart_base == 0)	port->uart_base = (int)ioremap(port->uart_base_phys, PAGE_SIZE);    if (options) {        char *s = options;        baud = simple_strtoul(s, NULL, 10);        while (*s >= '0' && *s <= '9')            s++;        if (*s) parity = *s++;        if (*s) bits = *s - '0';    }    /*     *    Now construct a cflag setting.     */    switch (baud) {    case 1200:  cflag |= B1200;         break;    case 2400:  cflag |= B2400;         break;    case 4800:  cflag |= B4800;         break;    default:    cflag |= B9600;   baud = 9600;  break;    case 19200: cflag |= B19200;        break;    case 38400: cflag |= B38400;        break;    case 57600: cflag |= B57600;        break;    case 115200:    cflag |= B115200;       break;    }    switch (bits) {    case 7:   cflag |= CS7; lcr_h = _LCR_PE_DISABLE | _LCR_DB_7_BITS | _LCR_SB_1_BIT;   break;    default:  cflag |= CS8; lcr_h = _LCR_PE_DISABLE | _LCR_DB_8_BITS | _LCR_SB_1_BIT;   break;    }    switch (parity) {    case 'o':    case 'O': cflag |= PARODD; lcr_h |= _LCR_PTY_ODD;   break;    case 'e':    case 'E': cflag |= PARENB; lcr_h |= _LCR_PE_ENABLE |  _LCR_PTY_ODD; break;    }    co->cflag = cflag;       {           // a copy of is inserted here ppc403SetBaud(com_port, (int)9600);           unsigned long divisor, clockSource, temp;           unsigned int rate = baud;          /* Ensure CICCR[7] is 0 to select Internal Baud Clock */          powerpcMtcic_cr((unsigned long)(powerpcMfcic_cr() & 0xFEFFFFFF));          /* Determine Internal Baud Clock Frequency */          /* powerpcMfclkgpcr() reads DCR 0x120 - the*/          /* SCCR (Serial Clock Control Register) on Vesta */          temp = powerpcMfclkgpcr();          if(temp & 0x00000080) {              clockSource = 324000000;          }          else {              clockSource = 216000000;          }          clockSource = clockSource/(unsigned long)((temp&0x00FC0000)>>18);          divisor = clockSource/(16*rate) - 1;          /* divisor has only 12 bits of resolution */          if(divisor>0x00000FFF){               divisor=0x00000FFF;          }          quot = divisor;       }    writeb((quot & 0x00000F00)>>8, port->uart_base + BL_SICC_BRDH );    writeb( quot & 0x00000FF,      port->uart_base   + BL_SICC_BRDL );    /* Set CTL2 reg to use external clock (ExtClk) and enable FIFOs. */    /* For now, do NOT use FIFOs since 403 UART did not have this    */    /* capability and this driver was inherited from 403UART.        */    writeb(_CTL2_EXTERN, port->uart_base  + BL_SICC_CTL2);    writeb(lcr_h, port->uart_base + BL_SICC_LCR);    writeb(_RCR_ER_ENABLE | _RCR_PME_HARD, port->uart_base + BL_SICC_RCR);    writeb( _TxCR_ET_ENABLE , port->uart_base + BL_SICC_TxCR);    // writeb(, info->port->uart_base + BL_SICC_RCR );    /*     * Transmitter Command Register: Transmitter enabled & DMA + TBR interrupt     * + Transmitter Empty interrupt + Transmitter error interrupt disabled &     * Stop mode when CTS active enabled & Transmit Break + Pattern Generation     * mode disabled.     */    writeb( 0x00, port->uart_base + BL_SICC_IrCR );  // disable IrDA    readb(port->uart_base + BL_SICC_RBR);    writeb(0xf8, port->uart_base + BL_SICC_LSR);   /* reset bits 0-4 of LSR */    /* we will enable the port as we need it */    return 0;}static struct console siccuart_cons ={    .name =     SERIAL_SICC_NAME,    .write =    siccuart_console_write,#ifdef used_and_not_const_char_pointer    .read =     siccuart_console_read,#endif    .device =   siccuart_console_device,    .wait_key = siccuart_console_wait_key,    .setup =    siccuart_console_setup,    .flags =    CON_PRINTBUFFER,    .index =    -1,};void __init sicc_console_init(void){    register_console(&siccuart_cons);}#endif /* CONFIG_SERIAL_SICC_CONSOLE */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -