lkml.org 
[lkml]   [1998]   [Oct]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectNS PC87338 support
    Hi!

    This is support for National Semiconductors PC87338. It allows serial
    to operate at speeds up-to 1500000bps. I wonder if something like this
    has chance to make it into mainstream kernel?

    Pavel

    PS: On my Thinkpad, I have to run attached program before trying to insert
    module for ttyS0 to be detected properly. Seems like it is disabled by
    default.

    PPS: Are there known bugs in serial.c's usage counts? I've seen really
    strange things like module usage cound == -1.

    --- clean//drivers/char/serial.c Fri Sep 11 20:54:24 1998
    +++ linux/drivers/char/serial.c Fri Oct 16 17:48:27 1998
    @@ -32,6 +32,8 @@
    * 4/98: Added changes to support the ARM architecture proposed by
    * Russell King
    *
    + * 10/98: Added support for NS PC87338. Pavel Machek <pavel@ucw.cz>
    + *
    * This module exports the following rs232 io functions:
    *
    * int rs_init(void);
    @@ -182,6 +185,7 @@
    static void autoconfig(struct serial_state * info);
    static void change_speed(struct async_struct *info);
    static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
    +static void pc87338_bank(struct async_struct *info, int bank);

    /*
    * Here we define the default xmit fifo size used for each type of
    @@ -194,10 +198,12 @@
    { "16550", 1, 0 },
    { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO },
    { "cirrus", 1, 0 },
    - { "ST16650", 1, UART_CLEAR_FIFO |UART_STARTECH },
    + { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH },
    { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
    UART_STARTECH },
    { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
    + { "startech/reserved", 1, 0 },
    + { "PC87338", 16, UART_CLEAR_FIFO | UART_USE_FIFO},
    { 0, 0}
    };

    @@ -1356,8 +1377,13 @@
    (cflag & CRTSCTS) ? UART_EFR_CTS : 0);
    }
    serial_outp(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
    + if (info->state->type == PORT_PC87338) /* Use alternate registers in bank 2 */
    + pc87338_bank(info, 2);
    serial_outp(info, UART_DLL, quot & 0xff); /* LS of divisor */
    serial_outp(info, UART_DLM, quot >> 8); /* MS of divisor */
    + if (info->state->type == PORT_PC87338) /* And return back to bank 0 */
    + pc87338_bank(info, 0);
    +
    if (info->state->type == PORT_16750)
    serial_outp(info, UART_FCR, fcr); /* set fcr */
    serial_outp(info, UART_LCR, cval); /* reset DLAB */
    @@ -2876,6 +2902,55 @@
    return (irq > 0)? irq : 0;
    }

    +static void pc87338_bank(struct async_struct *info, int bank)
    +{
    + if (bank>=2)
    + serial_out(info, 3, 0xe0 + ((bank-2) << 2));
    + else {
    + if (bank==1)
    + printk( "must not happen\n" );
    + else {
    + int i;
    +
    + pc87338_bank(info, 3);
    + i = serial_in(info, 1);
    + if (i&0x80)
    + printk( "hopefully can not happen\n" );
    + serial_out(info, 3, i);
    + }
    + }
    +}
    +
    +int pc87338_detect(struct async_struct *info)
    +{
    + int i, j;
    + /* Detect PC87338 */
    +
    + serial_out(info, 0xff);
    +
    + pc87338_bank(info, 3);
    + i = serial_in(info, 0);
    + if ((i & 0xf0) == 0x20) {
    + printk( "revision %d", i&0x0f);
    + } else return 0;
    + printk( "." );
    + pc87338_bank(info, 2);
    + serial_out(info, 2, 0x40); /* 41==extended mode, 40==nonextended mode */
    + if (0 != (i=serial_in(info, 2))) {
    + printk( "%x", i );
    + return 0;
    + }
    +
    + printk( "-" );
    + pc87338_bank(info, 2);
    + serial_out(info, 4, j = 0x35 ); /* TXSIZE=RXSIZE=32, Prescale=1.0, noLOCK */
    + if (j != (i=serial_in(info, 4)))
    + printk( "only 16 bytes FIFO?" );
    + printk( "." );
    + pc87338_bank(info, 0);
    + return 1;
    +}
    +
    /*
    * This routine is called by rs_init() to initialize a specific serial
    * port. It determines what type of UART chip this serial port is
    @@ -3002,14 +3108,21 @@
    if ((status1 != 0xa5) || (status2 != 0x5a))
    state->type = PORT_8250;
    }
    - state->xmit_fifo_size = uart_config[state->type].dfl_xmit_fifo_size;
    -
    + if ((state->type == PORT_16550A) || (state->type == PORT_8250)) {
    + printk( "Detecting PC87338 at %x: ", info->port );
    + if (pc87338_detect(info)) {
    + state->type = PORT_PC87338;
    + state->baud_base = 1500000;
    + }
    + printk( "\n" );
    + }
    if (state->type == PORT_UNKNOWN) {
    restore_flags(flags);
    return;
    }

    request_region(info->port,8,"serial(auto)");
    + state->xmit_fifo_size = uart_config[state->type].dfl_xmit_fifo_size;

    /*
    * Reset the UART.
    --- clean//include/linux/serial.h Sat Apr 18 21:44:46 1998
    +++ linux/include/linux/serial.h Wed Oct 14 22:25:41 1998
    @@ -47,7 +47,8 @@
    #define PORT_16650V2 7
    #define PORT_16750 8
    #define PORT_STARTECH 9
    -#define PORT_MAX 9
    +#define PORT_PC87338 10
    +#define PORT_MAX 10

    struct serial_uart_config {
    char *name;
    @@ -91,7 +92,7 @@
    #define ASYNC_USR_MASK 0x3430 /* Legal flags that non-privileged
    * users can set or reset */

    -/* Internal flags used only by kernel/chr_drv/serial.c */
    +/* Internal flags used only by drivers/char/serial.c */
    #define ASYNC_INITIALIZED 0x80000000 /* Serial port was initialized */
    #define ASYNC_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
    #define ASYNC_NORMAL_ACTIVE 0x20000000 /* Normal device is active */

    --
    I'm really pavel@atrey.karlin.mff.cuni.cz. Pavel
    Look at http://atrey.karlin.mff.cuni.cz/~pavel/ ;-).#include <asm/io.h>

    void
    main(void)
    {
    int i,j;
    iopl(3);
    outb(0x08,0x2e);
    printf( "08: %x - ", i = inb(0x2f));
    if ((i & 0xf8) == 0xb0)
    printf( "we have PCxxxxx\n" );
    else printf( "PCxxxxx not detected\n" );

    #if 0
    outb(0x00,0x2e);
    outb(0x00,0x2f);

    outb(0x01,0x2e);
    outb(0x10,0x2f);

    outb(0x01,0x2e);
    printf( "01: %x ", i = inb(0x2f));
    printf( "parport at %x, ttyS0 at %x, ttyS1 at %x\n", i & 3, (i >> 2) & 3, (i >> 4) & 3 );

    outb(0x00,0x2e);
    printf( "00: %x ", i = inb(0x2f));
    if (i & 1) printf( "parport enabled, " );
    if (i & 2) printf( "ttyS0 enabled, " );
    if (i & 4) printf( "ttyS1 enabled, " );
    if (i & 8) printf( "FDC enabled, " );
    if (i & 16) printf( "FDC fourport, " );
    if (i & 32) printf( "FDC secondary, " );
    printf( "\n" );

    outb(0x00,0x2e);
    outb(0xcf,0x2f);

    outb(0x00,0x2e);
    printf( "00: %x ", i = inb(0x2f));
    if (i & 1) printf( "parport enabled, " );
    if (i & 2) printf( "ttyS0 enabled, " );
    if (i & 4) printf( "ttyS1 enabled, " );
    if (i & 8) printf( "FDC enabled, " );
    if (i & 16) printf( "FDC fourport, " );
    if (i & 32) printf( "FDC secondary, " );
    printf( "\n" );
    #endif
    #if 0
    outb(0x44,0x2e); i = inb(0x2f);
    outb(0x45,0x2e); j = inb(0x2f);
    printf( "44,45: %x <- location of ttyS0\n", (j << 8) | i );

    outb(0x46,0x2e); i = inb(0x2f);
    outb(0x47,0x2e); j = inb(0x2f);
    printf( "46,47: %x <- location of ttyS1\n", (j << 8) | i );
    #endif

    #if 1
    outb(0x40,0x2e); /* THIS IS MAGIC COMBINATION! */
    outb(0xbc,0x2f);
    #endif
    outb(0x40,0x2e);
    printf( "40: %x - ", i = inb(0x2f));
    if (i & 0x10) printf( "ttyS0 bank select enable, " );
    if (i & 0x20) printf( "ttyS1 normal power, " );
    if (i & 0x40) printf( "ttyS1 busy, " );
    if (i & 0x80) printf( "ttyS1 bank select enable, " );
    printf("\n");

    outb(0x08,0x2e);
    printf( "08: %x - ", i = inb(0x2f));
    if ((i & 0xf8) == 0xb0)
    printf( "we have PCxxxxx\n" );
    else printf( "PCxxxxx not detected\n" );
    }
    \
     
     \ /
      Last update: 2005-03-22 13:45    [W:0.031 / U:29.004 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site