!C99Shell v. 1.0 pre-release build #13!

Software: Apache/2.0.54 (Unix) mod_perl/1.99_09 Perl/v5.8.0 mod_ssl/2.0.54 OpenSSL/0.9.7l DAV/2 FrontPage/5.0.2.2635 PHP/4.4.0 mod_gzip/2.0.26.1a 

uname -a: Linux snow.he.net 4.4.276-v2-mono-1 #1 SMP Wed Jul 21 11:21:17 PDT 2021 i686 

uid=99(nobody) gid=98(nobody) groups=98(nobody) 

Safe-mode: OFF (not secure)

/usr/src/linux-2.4.18-xfs-1.1/drivers/char/   drwxr-xr-x
Free 318.38 GB of 458.09 GB (69.5%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     sh-sci.c (30.28 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/* $Id: sh-sci.c,v 1.40 2000/04/15 06:57:29 gniibe Exp $
 *
 *  linux/drivers/char/sh-sci.c
 *
 *  SuperH on-chip serial module support.  (SCI with no FIFO / with FIFO)
 *  Copyright (C) 1999, 2000  Niibe Yutaka
 *  Copyright (C) 2000  Sugioka Toshinobu
 *  Modified to support multiple serial ports. Stuart Menefy (May 2000).
 *
 * TTY code is based on sx.c (Specialix SX driver) by:
 *
 *   (C) 1998 R.E.Wolff@BitWizard.nl
 *
 */

#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/delay.h>
#ifdef CONFIG_SERIAL_CONSOLE
#include <linux/console.h>
#endif

#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>

#include <linux/generic_serial.h>

#ifdef CONFIG_SH_STANDARD_BIOS
#include <asm/sh_bios.h>
#endif

#include "sh-sci.h"

#ifdef CONFIG_SERIAL_CONSOLE
static struct console sercons;
static struct sci_port* sercons_port=0;
static int sercons_baud;
#endif

/* Function prototypes */
static void sci_init_pins_sci(struct sci_port* port, unsigned int cflag);
#ifndef SCI_ONLY
static void sci_init_pins_scif(struct sci_port* port, unsigned int cflag);
#if defined(__sh3__)
static void sci_init_pins_irda(struct sci_port* port, unsigned int cflag);
#endif
#endif
static void sci_disable_tx_interrupts(void *ptr);
static void sci_enable_tx_interrupts(void *ptr);
static void sci_disable_rx_interrupts(void *ptr);
static void sci_enable_rx_interrupts(void *ptr);
static int  sci_get_CD(void *ptr);
static void sci_shutdown_port(void *ptr);
static int sci_set_real_termios(void *ptr);
static void sci_hungup(void *ptr);
static void sci_close(void *ptr);
static int sci_chars_in_buffer(void *ptr);
static int sci_request_irq(struct sci_port *port);
static void sci_free_irq(struct sci_port *port);
static int sci_init_drivers(void);

static struct tty_driver sci_driver, sci_callout_driver;

static struct sci_port sci_ports[SCI_NPORTS] = SCI_INIT;
static struct tty_struct *sci_table[SCI_NPORTS] = { NULL, };
static struct termios *sci_termios[SCI_NPORTS];
static struct termios *sci_termios_locked[SCI_NPORTS];

static int sci_refcount;
static int sci_debug = 0;

#ifdef MODULE
MODULE_PARM(sci_debug, "i");
#endif

#define dprintk(x...) do { if (sci_debug) printk(x); } while(0)

#ifdef CONFIG_SERIAL_CONSOLE
static void put_char(struct sci_port *port, char c)
{
    unsigned long flags;
    unsigned short status;

    save_and_cli(flags);

    do
        status = sci_in(port, SCxSR);
    while (!(status & SCxSR_TDxE(port)));
    
    sci_out(port, SCxTDR, c);
    sci_in(port, SCxSR);            /* Dummy read */
    sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));

    restore_flags(flags);
}
#endif

#ifdef CONFIG_SH_STANDARD_BIOS

static void handle_error(struct sci_port *port)
{                /* Clear error flags */
    sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
}

static int get_char(struct sci_port *port)
{
    unsigned long flags;
    unsigned short status;
    int c;

    save_and_cli(flags);
        do {
        status = sci_in(port, SCxSR);
        if (status & SCxSR_ERRORS(port)) {
            handle_error(port);
            continue;
        }
    } while (!(status & SCxSR_RDxF(port)));
    c = sci_in(port, SCxRDR);
    sci_in(port, SCxSR);            /* Dummy read */
    sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
    restore_flags(flags);

    return c;
}

/* Taken from sh-stub.c of GDB 4.18 */
static const char hexchars[] = "0123456789abcdef";

static __inline__ char highhex(int  x)
{
    return hexchars[(x >> 4) & 0xf];
}

static __inline__ char lowhex(int  x)
{
    return hexchars[x & 0xf];
}

#endif

/*
 * Send the packet in buffer.  The host gets one chance to read it.
 * This routine does not wait for a positive acknowledge.
 */

#ifdef CONFIG_SERIAL_CONSOLE
static void put_string(struct sci_port *port, const char *buffer, int count)
{
    int i;
    const unsigned char *p = buffer;
#ifdef CONFIG_SH_STANDARD_BIOS
    int checksum;

        /* This call only does a trap the first time it is
     * called, and so is safe to do here unconditionally
     */
    if (sh_bios_in_gdb_mode()) {
        /*  $<packet info>#<checksum>. */
        do {
        unsigned char c;
        put_char(port, '$');
        put_char(port, 'O'); /* 'O'utput to console */
        checksum = 'O';

        for (i=0; i<count; i++) { /* Don't use run length encoding */
            int h, l;

            c = *p++;
            h = highhex(c);
            l = lowhex(c);
            put_char(port, h);
            put_char(port, l);
            checksum += h + l;
        }
        put_char(port, '#');
        put_char(port, highhex(checksum));
        put_char(port, lowhex(checksum));
        } while  (get_char(port) != '+');
    } else
#endif
    for (i=0; i<count; i++) {
        if (*p == 10)
            put_char(port, '\r');
        put_char(port, *p++);
    }
}
#endif


static struct real_driver sci_real_driver = {
    sci_disable_tx_interrupts,
    sci_enable_tx_interrupts,
    sci_disable_rx_interrupts,
    sci_enable_rx_interrupts,
    sci_get_CD,
    sci_shutdown_port,
    sci_set_real_termios,
    sci_chars_in_buffer,
    sci_close,
    sci_hungup,
    NULL
};

#if defined(SCI_ONLY) || defined(SCI_AND_SCIF)
static void sci_init_pins_sci(struct sci_port* port, unsigned int cflag)
{
}
#endif

#if defined(SCIF_ONLY) || defined(SCI_AND_SCIF)
#if defined(__sh3__)
/* For SH7707, SH7709, SH7709A, SH7729 */
static void sci_init_pins_scif(struct sci_port* port, unsigned int cflag)
{
    unsigned int fcr_val = 0;

    {
        unsigned short data;

        /* We need to set SCPCR to enable RTS/CTS */
        data = ctrl_inw(SCPCR);
        /* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/
        ctrl_outw(data&0x0fcf, SCPCR);
    }
    if (cflag & CRTSCTS)
        fcr_val |= SCFCR_MCE;
    else {
        unsigned short data;

        /* We need to set SCPCR to enable RTS/CTS */
        data = ctrl_inw(SCPCR);
        /* Clear out SCP7MD1,0, SCP4MD1,0,
           Set SCP6MD1,0 = {01} (output)  */
        ctrl_outw((data&0x0fcf)|0x1000, SCPCR);

        data = ctrl_inb(SCPDR);
        /* Set /RTS2 (bit6) = 0 */
        ctrl_outb(data&0xbf, SCPDR);
    }
    sci_out(port, SCFCR, fcr_val);
}

static void sci_init_pins_irda(struct sci_port* port, unsigned int cflag)
{
    unsigned int fcr_val = 0;

    if (cflag & CRTSCTS)
        fcr_val |= SCFCR_MCE;

    sci_out(port, SCFCR, fcr_val);
}

#else

/* For SH7750 */
static void sci_init_pins_scif(struct sci_port* port, unsigned int cflag)
{
    unsigned int fcr_val = 0;

    if (cflag & CRTSCTS) {
        fcr_val |= SCFCR_MCE;
    } else {
        ctrl_outw(0x0080, SCSPTR2); /* Set RTS = 1 */
    }
    sci_out(port, SCFCR, fcr_val);
}

#endif
#endif /* SCIF_ONLY || SCI_AND_SCIF */

static void sci_setsignals(struct sci_port *port, int dtr, int rts)
{
    /* This routine is used for seting signals of: DTR, DCD, CTS/RTS */
    /* We use SCIF's hardware for CTS/RTS, so don't need any for that. */
    /* If you have signals for DTR and DCD, please implement here. */
    ;
}

static int sci_getsignals(struct sci_port *port)
{
    /* This routine is used for geting signals of: DTR, DCD, DSR, RI,
       and CTS/RTS */

    return TIOCM_DTR|TIOCM_RTS|TIOCM_DSR;
/*
    (((o_stat & OP_DTR)?TIOCM_DTR:0) |
     ((o_stat & OP_RTS)?TIOCM_RTS:0) |
     ((i_stat & IP_CTS)?TIOCM_CTS:0) |
     ((i_stat & IP_DCD)?TIOCM_CAR:0) |
     ((i_stat & IP_DSR)?TIOCM_DSR:0) |
     ((i_stat & IP_RI) ?TIOCM_RNG:0)
*/
}

static void sci_set_baud(struct sci_port *port, int baud)
{
    int t;

    switch (baud) {
    case 0:
        t = -1;
        break;
    case 2400:
        t = BPS_2400;
        break;
    case 4800:
        t = BPS_4800;
        break;
    case 9600:
        t = BPS_9600;
        break;
    case 19200:
        t = BPS_19200;
        break;
    case 38400:
        t = BPS_38400;
        break;
    case 57600:
        t = BPS_57600;
        break;
    default:
        printk(KERN_INFO "sci: unsupported baud rate: %d, using 115200 instead.\n", baud);
    case 115200:
        t = BPS_115200;
        break;
    }

    if (t > 0) {
        sci_setsignals (port, 1, -1);
        if(t >= 256) {
            sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1);
            t >>= 2;
        } else {
            sci_out(port, SCSMR, sci_in(port, SCSMR) & ~3);
        }
        sci_out(port, SCBRR, t);
        udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */
    } else {
        sci_setsignals (port, 0, -1);
    }
}

static void sci_set_termios_cflag(struct sci_port *port, int cflag, int baud)
{
    unsigned int status;
    unsigned int smr_val;

    do
        status = sci_in(port, SCxSR);
    while (!(status & SCxSR_TEND(port)));

    sci_out(port, SCSCR, 0x00);    /* TE=0, RE=0, CKE1=0 */

    if (port->type == PORT_SCIF) {
        sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
    }

    smr_val = sci_in(port, SCSMR) & 3;
    if ((cflag & CSIZE) == CS7)
        smr_val |= 0x40;
    if (cflag & PARENB)
        smr_val |= 0x20;
    if (cflag & PARODD)
        smr_val |= 0x10;
    if (cflag & CSTOPB)
        smr_val |= 0x08;
    sci_out(port, SCSMR, smr_val);
    sci_set_baud(port, baud);

    port->init_pins(port, cflag);
    sci_out(port, SCSCR, SCSCR_INIT(port));
}

static int sci_set_real_termios(void *ptr)
{
    struct sci_port *port = ptr;

    if (port->old_cflag != port->gs.tty->termios->c_cflag) {
        port->old_cflag = port->gs.tty->termios->c_cflag;
        sci_set_termios_cflag(port, port->old_cflag, port->gs.baud);
        sci_enable_rx_interrupts(port);
    }

    /* Tell line discipline whether we will do input cooking */
    if (I_OTHER(port->gs.tty))
        clear_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);
    else
        set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);

/* Tell line discipline whether we will do output cooking.
 * If OPOST is set and no other output flags are set then we can do output
 * processing.  Even if only *one* other flag in the O_OTHER group is set
 * we do cooking in software.
 */
    if (O_OPOST(port->gs.tty) && !O_OTHER(port->gs.tty))
        set_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
    else
        clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);

    return 0;
}

/* ********************************************************************** *
 *                   the interrupt related routines                       *
 * ********************************************************************** */

/*
 * This routine is used by the interrupt handler to schedule
 * processing in the software interrupt portion of the driver.
 */
static inline void sci_sched_event(struct sci_port *port, int event)
{
    port->event |= 1 << event;
    queue_task(&port->tqueue, &tq_immediate);
    mark_bh(IMMEDIATE_BH);
}

static void sci_transmit_chars(struct sci_port *port)
{
    int count, i;
    int txroom;
    unsigned long flags;
    unsigned short status;
    unsigned short ctrl;
    unsigned char c;

    status = sci_in(port, SCxSR);
    if (!(status & SCxSR_TDxE(port))) {
        save_and_cli(flags);
        ctrl = sci_in(port, SCSCR);
        if (port->gs.xmit_cnt == 0) {
            ctrl &= ~SCI_CTRL_FLAGS_TIE;
            port->gs.flags &= ~GS_TX_INTEN;
        } else
            ctrl |= SCI_CTRL_FLAGS_TIE;
        sci_out(port, SCSCR, ctrl);
        restore_flags(flags);
        return;
    }

    while (1) {
        count = port->gs.xmit_cnt;
        if (port->type == PORT_SCIF) {
            txroom = 16 - (sci_in(port, SCFDR)>>8);
        } else {
            txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0;
        }
        if (count > txroom)
            count = txroom;

        /* Don't copy pas the end of the source buffer */
        if (count > SERIAL_XMIT_SIZE - port->gs.xmit_tail)
                    count = SERIAL_XMIT_SIZE - port->gs.xmit_tail;

        /* If for one reason or another, we can't copy more data, we're done! */
        if (count == 0)
            break;

        for (i=0; i<count; i++) {
            c = port->gs.xmit_buf[port->gs.xmit_tail + i];
            sci_out(port, SCxTDR, c);
        }
        sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));

        port->icount.tx += count;

        /* Update the kernel buffer end */
        port->gs.xmit_tail = (port->gs.xmit_tail + count) & (SERIAL_XMIT_SIZE-1);

        /* This one last. (this is essential)
           It would allow others to start putting more data into the buffer! */
        port->gs.xmit_cnt -= count;
    }

    if (port->gs.xmit_cnt <= port->gs.wakeup_chars)
        sci_sched_event(port, SCI_EVENT_WRITE_WAKEUP);

    save_and_cli(flags);
    ctrl = sci_in(port, SCSCR);
    if (port->gs.xmit_cnt == 0) {
        ctrl &= ~SCI_CTRL_FLAGS_TIE;
        port->gs.flags &= ~GS_TX_INTEN;
    } else {
        if (port->type == PORT_SCIF) {
            sci_in(port, SCxSR); /* Dummy read */
            sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
        }
        ctrl |= SCI_CTRL_FLAGS_TIE;
    }
    sci_out(port, SCSCR, ctrl);
    restore_flags(flags);
}

static inline void sci_receive_chars(struct sci_port *port)
{
    int i, count;
    struct tty_struct *tty;
    int copied=0;
    unsigned short status;

    status = sci_in(port, SCxSR);
    if (!(status & SCxSR_RDxF(port)))
        return;

    tty = port->gs.tty;
    while (1) {
        if (port->type == PORT_SCIF) {
            count = sci_in(port, SCFDR)&0x001f;
        } else {
            count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0;
        }

        /* Don't copy more bytes than there is room for in the buffer */
        if (tty->flip.count + count > TTY_FLIPBUF_SIZE)
            count = TTY_FLIPBUF_SIZE - tty->flip.count;

        /* If for one reason or another, we can't copy more data, we're done! */
        if (count == 0)
            break;

        if (port->type == PORT_SCI) {
            tty->flip.char_buf_ptr[0] = sci_in(port, SCxRDR);
            tty->flip.flag_buf_ptr[0] = TTY_NORMAL;
        } else {
            for (i=0; i<count; i++) {
                tty->flip.char_buf_ptr[i] = sci_in(port, SCxRDR);
                status = sci_in(port, SCxSR);
                if (status&SCxSR_FER(port)) {
                    tty->flip.flag_buf_ptr[i] = TTY_FRAME;
                    dprintk("sci: frame error\n");
                } else if (status&SCxSR_PER(port)) {
                    tty->flip.flag_buf_ptr[i] = TTY_PARITY;
                    dprintk("sci: parity error\n");
                } else {
                    tty->flip.flag_buf_ptr[i] = TTY_NORMAL;
                }
            }
        }

        sci_in(port, SCxSR); /* dummy read */
        sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));

        /* Update the kernel buffer end */
        tty->flip.count += count;
        tty->flip.char_buf_ptr += count;
        tty->flip.flag_buf_ptr += count;

        copied += count;
        port->icount.rx += count;
    }

    if (copied)
        /* Tell the rest of the system the news. New characters! */
        tty_flip_buffer_push(tty);
}

static inline int sci_handle_errors(struct sci_port *port)
{
    int copied = 0;
    unsigned short status = sci_in(port, SCxSR);
    struct tty_struct *tty = port->gs.tty;

    if (status&SCxSR_ORER(port) && tty->flip.count<TTY_FLIPBUF_SIZE) {
        /* overrun error */
        copied++;
        *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
        dprintk("sci: overrun error\n");
    }

    if (status&SCxSR_FER(port) && tty->flip.count<TTY_FLIPBUF_SIZE) {
        if (sci_rxd_in(port) == 0) {
            /* Notify of BREAK */
            copied++;
            *tty->flip.flag_buf_ptr++ = TTY_BREAK;
            dprintk("sci: BREAK detected\n");
        }
        else {
            /* frame error */
            copied++;
            *tty->flip.flag_buf_ptr++ = TTY_FRAME;
            dprintk("sci: frame error\n");
        }
    }

    if (status&SCxSR_PER(port) && tty->flip.count<TTY_FLIPBUF_SIZE) {
        /* parity error */
        copied++;
        *tty->flip.flag_buf_ptr++ = TTY_PARITY;
        dprintk("sci: parity error\n");
    }

    if (copied) {
        tty->flip.count += copied;
        tty_flip_buffer_push(tty);
    }

    return copied;
}

static inline int sci_handle_breaks(struct sci_port *port)
{
    int copied = 0;
    unsigned short status = sci_in(port, SCxSR);
    struct tty_struct *tty = port->gs.tty;

    if (status&SCxSR_BRK(port) && tty->flip.count<TTY_FLIPBUF_SIZE) {
        /* Notify of BREAK */
        copied++;
        *tty->flip.flag_buf_ptr++ = TTY_BREAK;
        dprintk("sci: BREAK detected\n");
    }

#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_ST40STB1)
    /* XXX: Handle SCIF overrun error */
    if (port->type == PORT_SCIF && (sci_in(port, SCLSR) & SCIF_ORER) != 0) {
        sci_out(port, SCLSR, 0);
        if(tty->flip.count<TTY_FLIPBUF_SIZE) {
            copied++;
            *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
            dprintk("sci: overrun error\n");
        }
    }
#endif

    if (copied) {
        tty->flip.count += copied;
        tty_flip_buffer_push(tty);
    }

    return copied;
}

static void sci_rx_interrupt(int irq, void *ptr, struct pt_regs *regs)
{
    struct sci_port *port = ptr;

    if (port->gs.flags & GS_ACTIVE)
        if (!(port->gs.flags & SCI_RX_THROTTLE)) {
            sci_receive_chars(port);
            return;
        }
    sci_disable_rx_interrupts(port);
}

static void sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs)
{
    struct sci_port *port = ptr;

    if (port->gs.flags & GS_ACTIVE)
        sci_transmit_chars(port);
    else {
        sci_disable_tx_interrupts(port);
    }
}

static void sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs)
{
    struct sci_port *port = ptr;

    /* Handle errors */
    if (port->type == PORT_SCI) {
        if(sci_handle_errors(port)) {
            /* discard character in rx buffer */
            sci_in(port, SCxSR);
            sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
        }
    }
    else
        sci_rx_interrupt(irq, ptr, regs);
        
    sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));

    /* Kick the transmission */
    sci_tx_interrupt(irq, ptr, regs);
}

static void sci_br_interrupt(int irq, void *ptr, struct pt_regs *regs)
{
    struct sci_port *port = ptr;

    /* Handle BREAKs */
    sci_handle_breaks(port);
    sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
}

static void do_softint(void *private_)
{
    struct sci_port *port = (struct sci_port *) private_;
    struct tty_struct    *tty;
    
    tty = port->gs.tty;
    if (!tty)
        return;

    if (test_and_clear_bit(SCI_EVENT_WRITE_WAKEUP, &port->event)) {
        if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
            tty->ldisc.write_wakeup)
            (tty->ldisc.write_wakeup)(tty);
        wake_up_interruptible(&tty->write_wait);
    }
}

/* ********************************************************************** *
 *                Here are the routines that actually                     *
 *              interface with the generic_serial driver                  *
 * ********************************************************************** */

static void sci_disable_tx_interrupts(void *ptr)
{
    struct sci_port *port = ptr;
    unsigned long flags;
    unsigned short ctrl;

    /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
    save_and_cli(flags);
    ctrl = sci_in(port, SCSCR);
    ctrl &= ~SCI_CTRL_FLAGS_TIE;
    sci_out(port, SCSCR, ctrl);
    restore_flags(flags);
}

static void sci_enable_tx_interrupts(void *ptr)
{
    struct sci_port *port = ptr; 

    disable_irq(port->irqs[SCIx_TXI_IRQ]);
    sci_transmit_chars(port);
    enable_irq(port->irqs[SCIx_TXI_IRQ]);
}

static void sci_disable_rx_interrupts(void * ptr)
{
    struct sci_port *port = ptr;
    unsigned long flags;
    unsigned short ctrl;

    /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */
    save_and_cli(flags);
    ctrl = sci_in(port, SCSCR);
    ctrl &= ~SCI_CTRL_FLAGS_RIE;
    sci_out(port, SCSCR, ctrl);
    restore_flags(flags);
}

static void sci_enable_rx_interrupts(void * ptr)
{
    struct sci_port *port = ptr;
    unsigned long flags;
    unsigned short ctrl;

    /* Set RIE (Receive Interrupt Enable) bit in SCSCR */
    save_and_cli(flags);
    ctrl = sci_in(port, SCSCR);
    ctrl |= SCI_CTRL_FLAGS_RIE;
    sci_out(port, SCSCR, ctrl);
    restore_flags(flags);
}

static int sci_get_CD(void * ptr)
{
    /* If you have signal for CD (Carrier Detect), please change here. */
    return 1;
}

static int sci_chars_in_buffer(void * ptr)
{
    struct sci_port *port = ptr;

    if (port->type == PORT_SCIF) {
        return (sci_in(port, SCFDR) >> 8) + ((sci_in(port, SCxSR) & SCxSR_TEND(port))? 0: 1);
    } else {
        return (sci_in(port, SCxSR) & SCxSR_TEND(port))? 0: 1;
    }
}

static void sci_shutdown_port(void * ptr)
{
    struct sci_port *port = ptr; 

    port->gs.flags &= ~ GS_ACTIVE;
    if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL)
        sci_setsignals(port, 0, 0);
    sci_free_irq(port);
}

/* ********************************************************************** *
 *                Here are the routines that actually                     *
 *               interface with the rest of the system                    *
 * ********************************************************************** */

static int sci_open(struct tty_struct * tty, struct file * filp)
{
    struct sci_port *port;
    int retval, line;

    line = MINOR(tty->device) - SCI_MINOR_START;

    if ((line < 0) || (line >= SCI_NPORTS))
        return -ENODEV;

    port = &sci_ports[line];

    tty->driver_data = port;
    port->gs.tty = tty;
    port->gs.count++;

    port->event = 0;
    port->tqueue.routine = do_softint;
    port->tqueue.data = port;

    /*
     * Start up serial port
     */
    retval = gs_init_port(&port->gs);
    if (retval) {
        goto failed_1;
    }

    port->gs.flags |= GS_ACTIVE;
    sci_setsignals(port, 1,1);

    if (port->gs.count == 1) {
        MOD_INC_USE_COUNT;

        retval = sci_request_irq(port);
        if (retval) {
            goto failed_2;
        }
    }

    retval = gs_block_til_ready(port, filp);

    if (retval) {
        goto failed_3;
    }

    if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) {
        if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
            *tty->termios = port->gs.normal_termios;
        else 
            *tty->termios = port->gs.callout_termios;
        sci_set_real_termios(port);
    }

#ifdef CONFIG_SERIAL_CONSOLE
    if (sercons.cflag && sercons.index == line) {
        tty->termios->c_cflag = sercons.cflag;
        port->gs.baud = sercons_baud;
        sercons.cflag = 0;
        sci_set_real_termios(port);
    }
#endif

    sci_enable_rx_interrupts(port);

    port->gs.session = current->session;
    port->gs.pgrp = current->pgrp;

    return 0;

failed_3:
    sci_free_irq(port);
failed_2:
    MOD_DEC_USE_COUNT;
failed_1:
    port->gs.count--;
    return retval;
}

static void sci_hungup(void *ptr)
{
    MOD_DEC_USE_COUNT;
}

static void sci_close(void *ptr)
{
    MOD_DEC_USE_COUNT;
}

static int sci_ioctl(struct tty_struct * tty, struct file * filp, 
                     unsigned int cmd, unsigned long arg)
{
    int rc;
    struct sci_port *port = tty->driver_data;
    int ival;

    rc = 0;
    switch (cmd) {
    case TIOCGSOFTCAR:
        rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
                      (unsigned int *) arg);
        break;
    case TIOCSSOFTCAR:
        if ((rc = get_user(ival, (unsigned int *) arg)) == 0)
            tty->termios->c_cflag =
                (tty->termios->c_cflag & ~CLOCAL) |
                (ival ? CLOCAL : 0);
        break;
    case TIOCGSERIAL:
        if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
                              sizeof(struct serial_struct))) == 0)
            rc = gs_getserial(&port->gs, (struct serial_struct *) arg);
        break;
    case TIOCSSERIAL:
        if ((rc = verify_area(VERIFY_READ, (void *) arg,
                              sizeof(struct serial_struct))) == 0)
            rc = gs_setserial(&port->gs,
                      (struct serial_struct *) arg);
        break;
    case TIOCMGET:
        ival = sci_getsignals(port);
        rc = put_user(ival, (unsigned int *) arg);
        break;
    case TIOCMBIS:
        if ((rc = get_user(ival, (unsigned int *) arg)) == 0)
            sci_setsignals(port, ((ival & TIOCM_DTR) ? 1 : -1),
                                 ((ival & TIOCM_RTS) ? 1 : -1));
        break;
    case TIOCMBIC:
        if ((rc = get_user(ival, (unsigned int *) arg)) == 0)
            sci_setsignals(port, ((ival & TIOCM_DTR) ? 0 : -1),
                                 ((ival & TIOCM_RTS) ? 0 : -1));
        break;
    case TIOCMSET:
        if ((rc = get_user(ival, (unsigned int *)arg)) == 0)
            sci_setsignals(port, ((ival & TIOCM_DTR) ? 1 : 0),
                                 ((ival & TIOCM_RTS) ? 1 : 0));
        break;

    default:
        rc = -ENOIOCTLCMD;
        break;
    }

    return rc;
}

static void sci_throttle(struct tty_struct * tty)
{
    struct sci_port *port = (struct sci_port *)tty->driver_data;

    /* If the port is using any type of input flow
     * control then throttle the port.
     */
    if ((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty)) )
        port->gs.flags |= SCI_RX_THROTTLE;
}

static void sci_unthrottle(struct tty_struct * tty)
{
    struct sci_port *port = (struct sci_port *)tty->driver_data;

    /* Always unthrottle even if flow control is not enabled on
     * this port in case we disabled flow control while the port
     * was throttled
     */
    port->gs.flags &= ~SCI_RX_THROTTLE;
    return;
}

#ifdef CONFIG_PROC_FS
static int sci_read_proc(char *page, char **start, off_t off, int count,
             int *eof, void *data)
{
    int i;
    struct sci_port *port;
    int len = 0;
    
        len += sprintf(page, "sciinfo:0.1\n");
    for (i = 0; i < SCI_NPORTS && len < 4000; i++) {
        port = &sci_ports[i];
        len += sprintf(page+len, "%d: uart:%s address: %08x", i,
                   (port->type == PORT_SCI) ? "SCI" : "SCIF",
                   port->base);
        len += sprintf(page+len, " baud:%d", port->gs.baud);
        len += sprintf(page+len, " tx:%d rx:%d",
                   port->icount.tx, port->icount.rx);

        if (port->icount.frame)
            len += sprintf(page+len, " fe:%d", port->icount.frame);
        if (port->icount.parity)
            len += sprintf(page+len, " pe:%d", port->icount.parity);
        if (port->icount.brk)
            len += sprintf(page+len, " brk:%d", port->icount.brk);
        if (port->icount.overrun)
            len += sprintf(page+len, " oe:%d", port->icount.overrun);
        len += sprintf(page+len, "\n");
    }
    return len;
}
#endif

/* ********************************************************************** *
 *                    Here are the initialization routines.               *
 * ********************************************************************** */

static int sci_init_drivers(void)
{
    int error;
    struct sci_port *port;

    memset(&sci_driver, 0, sizeof(sci_driver));
    sci_driver.magic = TTY_DRIVER_MAGIC;
    sci_driver.driver_name = "sci";
#ifdef CONFIG_DEVFS_FS
    sci_driver.name = "ttsc/%d";
#else
    sci_driver.name = "ttySC";
#endif
    sci_driver.major = SCI_MAJOR;
    sci_driver.minor_start = SCI_MINOR_START;
    sci_driver.num = SCI_NPORTS;
    sci_driver.type = TTY_DRIVER_TYPE_SERIAL;
    sci_driver.subtype = SERIAL_TYPE_NORMAL;
    sci_driver.init_termios = tty_std_termios;
    sci_driver.init_termios.c_cflag =
        B9600 | CS8 | CREAD | HUPCL | CLOCAL | CRTSCTS;
    sci_driver.flags = TTY_DRIVER_REAL_RAW;
    sci_driver.refcount = &sci_refcount;
    sci_driver.table = sci_table;
    sci_driver.termios = sci_termios;
    sci_driver.termios_locked = sci_termios_locked;

    sci_driver.open    = sci_open;
    sci_driver.close = gs_close;
    sci_driver.write = gs_write;
    sci_driver.put_char = gs_put_char;
    sci_driver.flush_chars = gs_flush_chars;
    sci_driver.write_room = gs_write_room;
    sci_driver.chars_in_buffer = gs_chars_in_buffer;
    sci_driver.flush_buffer = gs_flush_buffer;
    sci_driver.ioctl = sci_ioctl;
    sci_driver.throttle = sci_throttle;
    sci_driver.unthrottle = sci_unthrottle;
    sci_driver.set_termios = gs_set_termios;
    sci_driver.stop = gs_stop;
    sci_driver.start = gs_start;
    sci_driver.hangup = gs_hangup;
#ifdef CONFIG_PROC_FS
    sci_driver.read_proc = sci_read_proc;
#endif

    sci_callout_driver = sci_driver;
#ifdef CONFIG_DEVFS_FS
    sci_callout_driver.name = "cusc/%d";
#else
    sci_callout_driver.name = "cusc";
#endif
    sci_callout_driver.major = SCI_MAJOR+1;
    sci_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
    sci_callout_driver.read_proc = NULL;

    if ((error = tty_register_driver(&sci_driver))) {
        printk(KERN_ERR "sci: Couldn't register SCI driver, error = %d\n",
               error);
        return 1;
    }
    if ((error = tty_register_driver(&sci_callout_driver))) {
        tty_unregister_driver(&sci_driver);
        printk(KERN_ERR "sci: Couldn't register SCI callout driver, error = %d\n",
               error);
        return 1;
    }

    for (port = &sci_ports[0]; port < &sci_ports[SCI_NPORTS]; port++) {
        port->gs.callout_termios = sci_callout_driver.init_termios;
        port->gs.normal_termios    = sci_driver.init_termios;
        port->gs.magic = SCI_MAGIC;
        port->gs.close_delay = HZ/2;
        port->gs.closing_wait = 30 * HZ;
        port->gs.rd = &sci_real_driver;
        init_waitqueue_head(&port->gs.open_wait);
        init_waitqueue_head(&port->gs.close_wait);
        port->old_cflag = 0;
        port->icount.cts = port->icount.dsr = 
            port->icount.rng = port->icount.dcd = 0;
        port->icount.rx = port->icount.tx = 0;
        port->icount.frame = port->icount.parity = 0;
        port->icount.overrun = port->icount.brk = 0;
    }

    return 0;
}

static int sci_request_irq(struct sci_port *port)
{
    int i;
    void (*handlers[4])(int irq, void *ptr, struct pt_regs *regs) = {
        sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt,
        sci_br_interrupt,
    };

    for (i=0; i<4; i++) {
        if (!port->irqs[i]) continue;
        if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT,
                "sci", port)) {
            printk(KERN_ERR "sci: Cannot allocate irq.\n");
            return -ENODEV;
        }
    }
    return 0;
}

static void sci_free_irq(struct sci_port *port)
{
    int i;

    for (i=0; i<4; i++) {
        if (!port->irqs[i]) continue;
        free_irq(port->irqs[i], port);
    }
}

static char banner[] __initdata =
    KERN_INFO "SuperH SCI(F) driver initialized\n";

int __init sci_init(void)
{
    struct sci_port *port;
    int j;

    printk("%s", banner);

    for (j=0; j<SCI_NPORTS; j++) {
        port = &sci_ports[j];
        printk(KERN_INFO "ttySC%d at 0x%08x is a %s\n", j, port->base,
               (port->type == PORT_SCI) ? "SCI" : "SCIF");
    }

    sci_init_drivers();

#ifdef CONFIG_SH_STANDARD_BIOS
    sh_bios_gdb_detach();
#endif
    return 0;        /* Return -EIO when not detected */
}

module_init(sci_init);

#ifdef MODULE
#undef func_enter
#undef func_exit

void cleanup_module(void)
{
    tty_unregister_driver(&sci_driver);
    tty_unregister_driver(&sci_callout_driver);
}

#include "generic_serial.c"
#endif

#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 *co, const char *s,
                 unsigned count)
{
    put_string(sercons_port, s, count);
}

/*
 *    Receive character from the serial port
 */
static int serial_console_wait_key(struct console *co)
{
    /* Not implemented yet */
    return 0;
}

static kdev_t serial_console_device(struct console *c)
{
    return MKDEV(SCI_MAJOR, SCI_MINOR_START + c->index);
}

/*
 *    Setup initial baud/bits/parity. We do two things here:
 *    - construct a cflag setting for the first rs_open()
 *    - initialize the serial port
 *    Return non-zero if we didn't find a serial port.
 */
static int __init serial_console_setup(struct console *co, char *options)
{
    int    baud = 9600;
    int    bits = 8;
    int    parity = 'n';
    int    cflag = CREAD | HUPCL | CLOCAL;
    char    *s;

    sercons_port = &sci_ports[co->index];

    if (options) {
        baud = simple_strtoul(options, NULL, 10);
        s = options;
        while(*s >= '0' && *s <= '9')
            s++;
        if (*s) parity = *s++;
        if (*s) bits   = *s - '0';
    }

    /*
     *    Now construct a cflag setting.
     */
    switch (baud) {
        case 19200:
            cflag |= B19200;
            break;
        case 38400:
            cflag |= B38400;
            break;
        case 57600:
            cflag |= B57600;
            break;
        case 115200:
            cflag |= B115200;
            break;
        case 9600:
        default:
            cflag |= B9600;
            baud = 9600;
            break;
    }
    switch (bits) {
        case 7:
            cflag |= CS7;
            break;
        default:
        case 8:
            cflag |= CS8;
            break;
    }
    switch (parity) {
        case 'o': case 'O':
            cflag |= PARODD;
            break;
        case 'e': case 'E':
            cflag |= PARENB;
            break;
    }

    co->cflag = cflag;
    sercons_baud = baud;

    sci_set_termios_cflag(sercons_port, cflag, baud);
    sercons_port->old_cflag = cflag;

    return 0;
}

static struct console sercons = {
    name:        "ttySC",
    write:        serial_console_write,
    device:        serial_console_device,
    wait_key:    serial_console_wait_key,
    setup:        serial_console_setup,
    flags:        CON_PRINTBUFFER,
    index:        -1,
};

/*
 *    Register console.
 */

#ifdef CONFIG_SH_EARLY_PRINTK
extern void sh_console_unregister (void);
#endif

void __init sci_console_init(void)
{
    register_console(&sercons);
#ifdef CONFIG_SH_EARLY_PRINTK
    /* Now that the real console is available, unregister the one we
     * used while first booting.
     */
    sh_console_unregister();
#endif
}
#endif /* CONFIG_SERIAL_CONSOLE */

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 1.0 pre-release build #13 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.0121 ]--