linux-old/drivers/char/sb1250_duart.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2000, 2001, 2002, 2003 Broadcom Corporation
   3 *
   4 * This program is free software; you can redistribute it and/or
   5 * modify it under the terms of the GNU General Public License
   6 * as published by the Free Software Foundation; either version 2
   7 * of the License, or (at your option) any later version.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 * 
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write to the Free Software
  16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  17 */
  18
  19/* 
  20 * Driver support for the on-chip sb1250 dual-channel serial port,
  21 * running in asynchronous mode.  Also, support for doing a serial console
  22 * on one of those ports 
  23 */
  24#include <linux/config.h>
  25#include <linux/types.h>
  26#include <linux/serial.h>
  27#include <linux/module.h>
  28#include <linux/console.h>
  29#include <linux/kdev_t.h>
  30#include <linux/major.h>
  31#include <linux/termios.h>
  32#include <linux/spinlock.h>
  33#include <linux/irq.h>
  34#include <linux/errno.h>
  35#include <linux/tty.h>
  36#include <linux/sched.h>
  37#include <linux/tty_flip.h>
  38#include <linux/timer.h>
  39#include <linux/init.h>
  40#include <linux/mm.h>
  41#include <asm/delay.h>
  42#include <asm/io.h>
  43#include <asm/uaccess.h>
  44#include <asm/sibyte/swarm.h>
  45#include <asm/sibyte/sb1250_regs.h>
  46#include <asm/sibyte/sb1250_uart.h>
  47#include <asm/sibyte/sb1250_int.h>
  48#include <asm/sibyte/sb1250.h>
  49#include <asm/sibyte/64bit.h>
  50#include <asm/war.h>
  51
  52/* Toggle spewing of debugging output */
  53#undef DUART_SPEW
  54
  55#define DEFAULT_CFLAGS          (CS8 | B115200)
  56
  57#define TX_INTEN          1
  58#define DUART_INITIALIZED 2
  59
  60#ifndef MIN
  61#define MIN(a,b)        ((a) < (b) ? (a) : (b))
  62#endif
  63
  64#define DUART_MAX_LINE 2
  65char sb1250_duart_present[DUART_MAX_LINE] = {1,1};
  66
  67/*
  68 * Still not sure what the termios structures set up here are for, 
  69 *  but we have to supply pointers to them to register the tty driver
  70 */
  71static struct tty_driver sb1250_duart_driver, sb1250_duart_callout_driver;
  72static int duart_refcount;
  73static struct tty_struct *duart_table[DUART_MAX_LINE];
  74static struct termios    *duart_termios[DUART_MAX_LINE];
  75static struct termios    *duart_termios_locked[DUART_MAX_LINE];
  76
  77/*
  78 * This lock protects both the open flags for all the uart states as 
  79 * well as the reference count for the module
  80 */
  81static spinlock_t          open_lock = SPIN_LOCK_UNLOCKED;
  82
  83typedef struct { 
  84        unsigned char       outp_buf[SERIAL_XMIT_SIZE];
  85        unsigned int        outp_head;
  86        unsigned int        outp_tail;
  87        unsigned int        outp_count;
  88        spinlock_t          outp_lock;
  89        unsigned int        open;
  90        unsigned int        line;
  91        unsigned int        last_cflags;
  92        unsigned long       flags;
  93        struct tty_struct   *tty;
  94        /* CSR addresses */
  95        u32                 *status;
  96        u32                 *imr;
  97        u32                 *tx_hold;
  98        u32                 *rx_hold;
  99        u32                 *mode_1;
 100        u32                 *mode_2;
 101        u32                 *clk_sel;
 102        u32                 *cmd;
 103} uart_state_t;
 104
 105static uart_state_t uart_states[DUART_MAX_LINE];
 106
 107/*
 108 * Inline functions local to this module 
 109 */
 110
 111/*
 112 * In bug 1956, we get glitches that can mess up uart registers.  This
 113 * "write-mode-1 after any register access" is the accepted
 114 * workaround.
 115 */
 116#if SIBYTE_1956_WAR
 117static unsigned int last_mode1[DUART_MAX_LINE];
 118#endif
 119
 120static inline u32 READ_SERCSR(u32 *addr, int line)
 121{
 122        u32 val = csr_in32(addr);
 123#if SIBYTE_1956_WAR
 124        csr_out32(last_mode1[line], uart_states[line].mode_1);
 125#endif
 126        return val;
 127}
 128
 129static inline void WRITE_SERCSR(u32 val, u32 *addr, int line)
 130{
 131        csr_out32(val, addr);
 132#if SIBYTE_1956_WAR
 133        csr_out32(last_mode1[line], uart_states[line].mode_1);
 134#endif
 135}
 136
 137static void init_duart_port(uart_state_t *port, int line)
 138{
 139        if (!(port->flags & DUART_INITIALIZED)) {
 140                port->line = line;
 141                port->status = (u32 *)(IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_STATUS));
 142                port->imr = (u32 *)(IO_SPACE_BASE | A_DUART_IMRREG(line));
 143                port->tx_hold = (u32 *)(IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_TX_HOLD));
 144                port->rx_hold = (u32 *)(IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_RX_HOLD));
 145                port->mode_1 = (u32 *)(IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_MODE_REG_1));
 146                port->mode_2 = (u32 *)(IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_MODE_REG_2));
 147                port->clk_sel = (u32 *)(IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_CLK_SEL));
 148                port->cmd = (u32 *)(IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_CMD));
 149                port->flags |= DUART_INITIALIZED;
 150        }
 151}
 152
 153/*
 154 * Mask out the passed interrupt lines at the duart level.  This should be
 155 * called while holding the associated outp_lock.
 156 */
 157static inline void duart_mask_ints(unsigned int line, unsigned int mask)
 158{
 159        uart_state_t *port = uart_states + line;
 160        u64 tmp = READ_SERCSR(port->imr, line);
 161        WRITE_SERCSR(tmp & ~mask, port->imr, line);
 162}
 163
 164        
 165/* Unmask the passed interrupt lines at the duart level */
 166static inline void duart_unmask_ints(unsigned int line, unsigned int mask)
 167{
 168        uart_state_t *port = uart_states + line;
 169        u64 tmp = READ_SERCSR(port->imr, line);
 170        WRITE_SERCSR(tmp | mask, port->imr, line);
 171}
 172
 173static inline void transmit_char_pio(uart_state_t *us)
 174{
 175        struct tty_struct *tty = us->tty;
 176        int blocked = 0;
 177
 178        if (spin_trylock(&us->outp_lock)) {
 179                for (;;) {
 180                        if (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_RDY))
 181                                break;
 182                        if (us->outp_count <= 0 || tty->stopped || tty->hw_stopped) {
 183                                break;
 184                        } else {
 185                                WRITE_SERCSR(us->outp_buf[us->outp_head],
 186                                             us->tx_hold, us->line);
 187                                us->outp_head = (us->outp_head + 1) & (SERIAL_XMIT_SIZE-1);
 188                                if (--us->outp_count <= 0)
 189                                        break;
 190                        }
 191                        udelay(10);
 192                }
 193                spin_unlock(&us->outp_lock);
 194        } else {
 195                blocked = 1;
 196        }
 197
 198        if (!us->outp_count || tty->stopped ||
 199            tty->hw_stopped || blocked) {
 200                us->flags &= ~TX_INTEN;
 201                duart_mask_ints(us->line, M_DUART_IMR_TX);
 202        }
 203
 204        if (us->open &&
 205            (us->outp_count < (SERIAL_XMIT_SIZE/2))) {
 206                /*
 207                 * We told the discipline at one point that we had no
 208                 * space, so it went to sleep.  Wake it up when we hit
 209                 * half empty
 210                 */
 211                if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
 212                    tty->ldisc.write_wakeup)
 213                        tty->ldisc.write_wakeup(tty);
 214                wake_up_interruptible(&tty->write_wait);
 215        }
 216}
 217
 218/* 
 219 * Generic interrupt handler for both channels.  dev_id is a pointer
 220 * to the proper uart_states structure, so from that we can derive 
 221 * which port interrupted 
 222 */
 223
 224static void duart_int(int irq, void *dev_id, struct pt_regs *regs)
 225{
 226        uart_state_t *us = (uart_state_t *)dev_id;
 227        struct tty_struct *tty = us->tty;
 228        unsigned int status = READ_SERCSR(us->status, us->line);
 229
 230#ifdef DUART_SPEW
 231        printk("DUART INT\n");
 232#endif
 233
 234        if (status & M_DUART_RX_RDY) {
 235                int counter = 2048;
 236                unsigned int ch;
 237
 238                if (status & M_DUART_OVRUN_ERR)
 239                        tty_insert_flip_char(tty, 0, TTY_OVERRUN);
 240                if (status & M_DUART_PARITY_ERR) {
 241                        printk("Parity error!\n");
 242                } else if (status & M_DUART_FRM_ERR) {
 243                        printk("Frame error!\n");
 244                }
 245
 246                while (counter > 0) {
 247                        if (!(READ_SERCSR(us->status, us->line) & M_DUART_RX_RDY))
 248                                break;
 249                        ch = READ_SERCSR(us->rx_hold, us->line);
 250                        if (tty->flip.count < TTY_FLIPBUF_SIZE) {
 251                                *tty->flip.char_buf_ptr++ = ch;
 252                                *tty->flip.flag_buf_ptr++ = 0;
 253                                tty->flip.count++;
 254                        }
 255                        udelay(1);
 256                        counter--;
 257                }
 258                tty_flip_buffer_push(tty);
 259        }
 260
 261        if (status & M_DUART_TX_RDY) {
 262                transmit_char_pio(us);
 263        }
 264}
 265
 266/*
 267 *  Actual driver functions
 268 */
 269
 270/* Return the number of characters we can accomodate in a write at this instant */
 271static int duart_write_room(struct tty_struct *tty)
 272{
 273        uart_state_t *us = (uart_state_t *) tty->driver_data;
 274        int retval;
 275
 276        retval = SERIAL_XMIT_SIZE - us->outp_count;
 277
 278#ifdef DUART_SPEW
 279        printk("duart_write_room called, returning %i\n", retval);
 280#endif
 281
 282        return retval;
 283}
 284
 285/* memcpy the data from src to destination, but take extra care if the
 286   data is coming from user space */
 287static inline int copy_buf(char *dest, const char *src, int size, int from_user) 
 288{
 289        if (from_user) {
 290                (void) copy_from_user(dest, src, size); 
 291        } else {
 292                memcpy(dest, src, size);
 293        }
 294        return size;
 295}
 296
 297/*
 298 * Buffer up to count characters from buf to be written.  If we don't have
 299 * other characters buffered, enable the tx interrupt to start sending
 300 */
 301static int duart_write(struct tty_struct * tty, int from_user,
 302        const unsigned char *buf, int count)
 303{
 304        uart_state_t *us;
 305        int c, t, total = 0;
 306        unsigned long flags;
 307
 308        if (!tty) return 0;
 309
 310        us = tty->driver_data;
 311        if (!us) return 0;
 312
 313#ifdef DUART_SPEW
 314        printk("duart_write called for %i chars by %i (%s)\n", count, current->pid, current->comm);
 315#endif
 316
 317        spin_lock_irqsave(&us->outp_lock, flags);
 318
 319        for (;;) {
 320                c = count;
 321
 322                t = SERIAL_XMIT_SIZE - us->outp_tail;
 323                if (t < c) c = t;
 324
 325                t = SERIAL_XMIT_SIZE - 1 - us->outp_count;
 326                if (t < c) c = t;
 327
 328                if (c <= 0) break;
 329
 330                if (from_user) {
 331                        if (copy_from_user(us->outp_buf + us->outp_tail, buf, c)) {
 332                                spin_unlock_irqrestore(&us->outp_lock, flags);
 333                                return -EFAULT;
 334                        }
 335                } else {
 336                        memcpy(us->outp_buf + us->outp_tail, buf, c);
 337                }
 338
 339                us->outp_count += c;
 340                us->outp_tail = (us->outp_tail + c) & (SERIAL_XMIT_SIZE - 1);
 341                buf += c;
 342                count -= c;
 343                total += c;
 344        }
 345
 346        spin_unlock_irqrestore(&us->outp_lock, flags);
 347
 348        if (us->outp_count && !tty->stopped && 
 349            !tty->hw_stopped && !(us->flags & TX_INTEN)) {
 350                us->flags |= TX_INTEN;
 351                duart_unmask_ints(us->line, M_DUART_IMR_TX);
 352        }
 353
 354        return total;
 355}
 356
 357
 358/* Buffer one character to be written.  If there's not room for it, just drop
 359   it on the floor.  This is used for echo, among other things */
 360static void duart_put_char(struct tty_struct *tty, u_char ch)
 361{
 362        uart_state_t *us = (uart_state_t *) tty->driver_data;
 363        unsigned long flags;
 364
 365#ifdef DUART_SPEW
 366        printk("duart_put_char called.  Char is %x (%c)\n", (int)ch, ch);
 367#endif
 368
 369        spin_lock_irqsave(&us->outp_lock, flags);
 370
 371        if (us->outp_count == SERIAL_XMIT_SIZE) {
 372                spin_unlock_irqrestore(&us->outp_lock, flags);
 373                return;
 374        }
 375
 376        us->outp_buf[us->outp_tail] = ch;
 377        us->outp_tail = (us->outp_tail + 1) &(SERIAL_XMIT_SIZE-1);
 378        us->outp_count++;
 379
 380        spin_unlock_irqrestore(&us->outp_lock, flags);
 381}
 382
 383static void duart_flush_chars(struct tty_struct * tty)
 384{
 385        uart_state_t *port;
 386
 387        if (!tty) return;
 388
 389        port = tty->driver_data;
 390
 391        if (!port) return;
 392
 393        if (port->outp_count <= 0 || tty->stopped || tty->hw_stopped) {
 394                return;
 395        }
 396
 397        port->flags |= TX_INTEN;
 398        duart_unmask_ints(port->line, M_DUART_IMR_TX);
 399}
 400
 401/* Return the number of characters in the output buffer that have yet to be 
 402   written */
 403static int duart_chars_in_buffer(struct tty_struct *tty)
 404{
 405        uart_state_t *us = (uart_state_t *) tty->driver_data;
 406        int retval;
 407
 408        retval = us->outp_count;
 409
 410#ifdef DUART_SPEW
 411        printk("duart_chars_in_buffer returning %i\n", retval);
 412#endif
 413        return retval;
 414}
 415
 416/* Kill everything we haven't yet shoved into the FIFO.  Turn off the
 417   transmit interrupt since we've nothing more to transmit */
 418static void duart_flush_buffer(struct tty_struct *tty)
 419{
 420        uart_state_t *us = (uart_state_t *) tty->driver_data;
 421        unsigned long flags;
 422
 423#ifdef DUART_SPEW
 424        printk("duart_flush_buffer called\n");
 425#endif
 426        spin_lock_irqsave(&us->outp_lock, flags);
 427        us->outp_head = us->outp_tail = us->outp_count = 0;
 428        spin_unlock_irqrestore(&us->outp_lock, flags);
 429
 430        wake_up_interruptible(&us->tty->write_wait);
 431        if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
 432            tty->ldisc.write_wakeup)
 433                tty->ldisc.write_wakeup(tty);
 434}
 435
 436
 437/* See sb1250 user manual for details on these registers */
 438static inline void duart_set_cflag(unsigned int line, unsigned int cflag)
 439{
 440        unsigned int mode_reg1 = 0, mode_reg2 = 0;
 441        unsigned int clk_divisor;
 442        uart_state_t *port = uart_states + line;
 443
 444        switch (cflag & CSIZE) {
 445        case CS7:
 446                mode_reg1 |= V_DUART_BITS_PER_CHAR_7;
 447                
 448        default:
 449                /* We don't handle CS5 or CS6...is there a way we're supposed to flag this? 
 450                   right now we just force them to CS8 */
 451                mode_reg1 |= 0x0;
 452                break;
 453        }
 454        if (cflag & CSTOPB) {
 455                mode_reg2 |= M_DUART_STOP_BIT_LEN_2;
 456        }
 457        if (!(cflag & PARENB)) {
 458                mode_reg1 |= V_DUART_PARITY_MODE_NONE;
 459        }
 460        if (cflag & PARODD) {
 461                mode_reg1 |= M_DUART_PARITY_TYPE_ODD;
 462        }
 463        
 464        /* Formula for this is (5000000/baud)-1, but we saturate
 465           at 12 bits, which means we can't actually do anything less
 466           that 1200 baud */
 467        switch (cflag & CBAUD) {
 468        case B200:      
 469        case B300:      
 470        case B1200:     clk_divisor = 4095;             break;
 471        case B1800:     clk_divisor = 2776;             break;
 472        case B2400:     clk_divisor = 2082;             break;
 473        case B4800:     clk_divisor = 1040;             break;
 474        default:
 475        case B9600:     clk_divisor = 519;              break;
 476        case B19200:    clk_divisor = 259;              break;
 477        case B38400:    clk_divisor = 129;              break;
 478        case B57600:    clk_divisor = 85;               break;
 479        case B115200:   clk_divisor = 42;               break;
 480        }
 481        WRITE_SERCSR(mode_reg1, port->mode_1, port->line);
 482        WRITE_SERCSR(mode_reg2, port->mode_2, port->line);
 483        WRITE_SERCSR(clk_divisor, port->clk_sel, port->line);
 484        port->last_cflags = cflag;
 485}
 486
 487
 488/* Handle notification of a termios change.  */
 489static void duart_set_termios(struct tty_struct *tty, struct termios *old)
 490{
 491        uart_state_t *us = (uart_state_t *) tty->driver_data;
 492
 493#ifdef DUART_SPEW 
 494        printk("duart_set_termios called by %i (%s)\n", current->pid, current->comm);
 495#endif
 496        if (old && tty->termios->c_cflag == old->c_cflag)
 497                return;
 498        duart_set_cflag(us->line, tty->termios->c_cflag);
 499}
 500
 501static int duart_ioctl(struct tty_struct *tty, struct file * file,
 502                       unsigned int cmd, unsigned long arg)
 503{
 504/*      if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
 505        return -ENODEV;*/
 506        switch (cmd) {
 507        case TIOCMGET:
 508                printk("Ignoring TIOCMGET\n");
 509                break;
 510        case TIOCMBIS:
 511                printk("Ignoring TIOCMBIS\n");
 512                break;
 513        case TIOCMBIC:
 514                printk("Ignoring TIOCMBIC\n");
 515                break;
 516        case TIOCMSET:
 517                printk("Ignoring TIOCMSET\n");
 518                break;
 519        case TIOCGSERIAL:
 520                printk("Ignoring TIOCGSERIAL\n");
 521                break;
 522        case TIOCSSERIAL:
 523                printk("Ignoring TIOCSSERIAL\n");
 524                break;
 525        case TIOCSERCONFIG:
 526                printk("Ignoring TIOCSERCONFIG\n");
 527                break;
 528        case TIOCSERGETLSR: /* Get line status register */
 529                printk("Ignoring TIOCSERGETLSR\n");
 530                break;
 531        case TIOCSERGSTRUCT:
 532                printk("Ignoring TIOCSERGSTRUCT\n");
 533                break;
 534        case TIOCMIWAIT:
 535                printk("Ignoring TIOCMIWAIT\n");
 536                break;
 537        case TIOCGICOUNT:
 538                printk("Ignoring TIOCGICOUNT\n");
 539                break;
 540        case TIOCSERGWILD:
 541                printk("Ignoring TIOCSERGWILD\n");
 542                break;
 543        case TIOCSERSWILD:
 544                printk("Ignoring TIOCSERSWILD\n");
 545                break;
 546        default:
 547                break;
 548        }
 549//      printk("Ignoring IOCTL %x from pid %i (%s)\n", cmd, current->pid, current->comm);
 550        return -ENOIOCTLCMD;
 551#if 0
 552        if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
 553            (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
 554            (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
 555                if (tty->flags & (1 << TTY_IO_ERROR))
 556                        return -EIO;
 557        }
 558        
 559        switch (cmd) {
 560        case TIOCMGET:
 561        case TIOCMBIS:
 562        case TIOCMBIC:
 563        case TIOCMSET:
 564        case TIOCGSERIAL:
 565        case TIOCSSERIAL:
 566        case TIOCSERCONFIG:
 567        case TIOCSERGETLSR: /* Get line status register */
 568        case TIOCSERGSTRUCT:
 569        case TIOCMIWAIT:
 570        case TIOCGICOUNT:
 571        case TIOCSERGWILD:
 572        case TIOCSERSWILD:
 573                /* XXX Implement me! */
 574                printk("IOCTL needs implementing: %x\n", cmd);
 575                
 576        default:
 577                printk("Unknown ioctl: %x\n", cmd);
 578        }
 579#endif
 580        return 0;
 581}
 582
 583/* XXXKW locking? */
 584static void duart_start(struct tty_struct *tty)
 585{
 586        uart_state_t *us = (uart_state_t *) tty->driver_data;
 587
 588#ifdef DUART_SPEW
 589        printk("duart_start called\n");
 590#endif
 591
 592        if (us->outp_count && !(us->flags & TX_INTEN)) {
 593                us->flags |= TX_INTEN;
 594                duart_unmask_ints(us->line, M_DUART_IMR_TX);
 595        }
 596}
 597
 598/* XXXKW locking? */
 599static void duart_stop(struct tty_struct *tty)
 600{
 601        uart_state_t *us = (uart_state_t *) tty->driver_data;
 602
 603#ifdef DUART_SPEW
 604        printk("duart_stop called\n");
 605#endif
 606
 607        if (us->outp_count && (us->flags & TX_INTEN)) {
 608                us->flags &= ~TX_INTEN;
 609                duart_mask_ints(us->line, M_DUART_IMR_TX);
 610        }
 611}
 612
 613/* Not sure on the semantics of this; are we supposed to wait until the stuff
 614   already in the hardware FIFO drains, or are we supposed to wait until 
 615   we've drained the output buffer, too?  I'm assuming the former, 'cause thats
 616   what the other drivers seem to assume 
 617*/
 618
 619static void duart_wait_until_sent(struct tty_struct *tty, int timeout)
 620{
 621        uart_state_t *us = (uart_state_t *) tty->driver_data;
 622        unsigned long orig_jiffies;
 623
 624        orig_jiffies = jiffies;
 625#ifdef DUART_SPEW
 626        printk("duart_wait_until_sent(%d)+\n", timeout);
 627#endif
 628        while (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_EMT)) {
 629                set_current_state(TASK_INTERRUPTIBLE);
 630                schedule_timeout(1);
 631                if (signal_pending(current))
 632                        break;
 633                if (timeout && time_after(jiffies, orig_jiffies + timeout))
 634                        break;
 635        }
 636#ifdef DUART_SPEW
 637        printk("duart_wait_until_sent()-\n");
 638#endif
 639}
 640
 641/*
 642 * duart_hangup() --- called by tty_hangup() when a hangup is signaled.
 643 */
 644static void duart_hangup(struct tty_struct *tty)
 645{
 646        uart_state_t *us = (uart_state_t *) tty->driver_data;
 647
 648        duart_flush_buffer(tty);
 649        us->open = 0;
 650        us->tty = 0;
 651}
 652
 653/*
 654 * Open a tty line.  Note that this can be called multiple times, so ->open can
 655 * be >1.  Only set up the tty struct if this is a "new" open, e.g. ->open was
 656 * zero
 657 */
 658static int duart_open(struct tty_struct *tty, struct file *filp)
 659{
 660        uart_state_t *us;
 661        unsigned int line = MINOR(tty->device) - tty->driver.minor_start;
 662        unsigned long flags;
 663
 664        MOD_INC_USE_COUNT;
 665
 666        if ((line < 0) || (line >= DUART_MAX_LINE) || !sb1250_duart_present[line]) {
 667                MOD_DEC_USE_COUNT;
 668                return -ENODEV;
 669        }
 670
 671#ifdef DUART_SPEW
 672        printk("duart_open called by %i (%s), tty is %p, rw is %p, ww is %p\n",
 673               current->pid, current->comm, tty, tty->read_wait,
 674               tty->write_wait);
 675#endif
 676
 677        us = uart_states + line;
 678        tty->driver_data = us;
 679
 680        spin_lock_irqsave(&open_lock, flags);
 681        if (!us->open) {
 682                us->tty = tty;
 683                us->tty->termios->c_cflag = us->last_cflags;
 684        }
 685        us->open++;
 686        us->flags &= ~TX_INTEN;
 687        duart_unmask_ints(line, M_DUART_IMR_RX);
 688        spin_unlock_irqrestore(&open_lock, flags);
 689
 690        return 0;
 691}
 692
 693
 694/*
 695 * Close a reference count out.  If reference count hits zero, null the
 696 * tty, kill the interrupts.  The tty_io driver is responsible for making
 697 * sure we've cleared out our internal buffers before calling close()
 698 */
 699static void duart_close(struct tty_struct *tty, struct file *filp)
 700{
 701        uart_state_t *us = (uart_state_t *) tty->driver_data;
 702        unsigned long flags;
 703
 704#ifdef DUART_SPEW
 705        printk("duart_close called by %i (%s)\n", current->pid, current->comm);
 706#endif
 707
 708        if (!us || !us->open)
 709                return;
 710
 711        spin_lock_irqsave(&open_lock, flags);
 712        if (tty_hung_up_p(filp)) {
 713                MOD_DEC_USE_COUNT;
 714                spin_unlock_irqrestore(&open_lock, flags);
 715                return;
 716        }
 717
 718        if (--us->open < 0) {
 719                us->open = 0;
 720                printk(KERN_ERR "duart: bad open count: %d\n", us->open);
 721        }
 722        if (us->open) {
 723                spin_unlock_irqrestore(&open_lock, flags);
 724                return;
 725        }
 726
 727        spin_unlock_irqrestore(&open_lock, flags);
 728
 729        tty->closing = 1;
 730
 731        /* Stop accepting input */
 732        duart_mask_ints(us->line, M_DUART_IMR_RX);
 733        /* Wait for FIFO to drain */
 734        while (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_EMT))
 735                ;
 736
 737        if (tty->driver.flush_buffer)
 738                tty->driver.flush_buffer(tty);
 739        if (tty->ldisc.flush_buffer)
 740                tty->ldisc.flush_buffer(tty);
 741        tty->closing = 0;
 742
 743        MOD_DEC_USE_COUNT;
 744}
 745
 746
 747/* Set up the driver and register it, register the 2 1250 UART interrupts.  This
 748   is called from tty_init, or as a part of the module init */
 749static int __init sb1250_duart_init(void) 
 750{
 751        int i;
 752
 753        sb1250_duart_driver.magic            = TTY_DRIVER_MAGIC;
 754        sb1250_duart_driver.driver_name      = "serial";
 755#ifdef CONFIG_DEVFS_FS
 756        sb1250_duart_driver.name             = "tts/%d";
 757#else
 758        sb1250_duart_driver.name             = "ttyS";
 759#endif
 760        sb1250_duart_driver.major            = TTY_MAJOR;
 761        sb1250_duart_driver.minor_start      = SB1250_DUART_MINOR_BASE;
 762        sb1250_duart_driver.num              = DUART_MAX_LINE;
 763        sb1250_duart_driver.type             = TTY_DRIVER_TYPE_SERIAL;
 764        sb1250_duart_driver.subtype          = SERIAL_TYPE_NORMAL;
 765        sb1250_duart_driver.init_termios     = tty_std_termios;
 766        sb1250_duart_driver.flags            = TTY_DRIVER_REAL_RAW;
 767        sb1250_duart_driver.refcount         = &duart_refcount;
 768        sb1250_duart_driver.table            = duart_table;
 769        sb1250_duart_driver.termios          = duart_termios;
 770        sb1250_duart_driver.termios_locked   = duart_termios_locked;
 771
 772        sb1250_duart_driver.open             = duart_open;
 773        sb1250_duart_driver.close            = duart_close;
 774        sb1250_duart_driver.write            = duart_write;
 775        sb1250_duart_driver.put_char         = duart_put_char;
 776        sb1250_duart_driver.write_room       = duart_write_room;
 777        sb1250_duart_driver.flush_chars      = duart_flush_chars;
 778        sb1250_duart_driver.chars_in_buffer  = duart_chars_in_buffer;
 779        sb1250_duart_driver.flush_buffer     = duart_flush_buffer;
 780        sb1250_duart_driver.ioctl            = duart_ioctl;
 781        sb1250_duart_driver.set_termios      = duart_set_termios;
 782        sb1250_duart_driver.stop             = duart_stop;
 783        sb1250_duart_driver.start            = duart_start;
 784        sb1250_duart_driver.hangup           = duart_hangup;
 785        sb1250_duart_driver.wait_until_sent  = duart_wait_until_sent;
 786
 787        sb1250_duart_callout_driver          = sb1250_duart_driver;
 788#ifdef CONFIG_DEVFS_FS
 789        sb1250_duart_callout_driver.name     = "cua/%d";
 790#else
 791        sb1250_duart_callout_driver.name     = "cua";
 792#endif
 793        sb1250_duart_callout_driver.major    = TTYAUX_MAJOR;
 794        sb1250_duart_callout_driver.subtype  = SERIAL_TYPE_CALLOUT;
 795
 796        for (i=0; i<DUART_MAX_LINE; i++) {
 797                uart_state_t *port = uart_states + i;
 798
 799                if (!sb1250_duart_present[i])
 800                        continue;
 801
 802                init_duart_port(port, i);
 803                spin_lock_init(&port->outp_lock);
 804                duart_mask_ints(i, M_DUART_IMR_ALL);
 805                if (request_irq(K_INT_UART_0+i, duart_int, 0, "uart", port)) {
 806                        panic("Couldn't get uart0 interrupt line");
 807                }
 808                out64(M_DUART_RX_EN|M_DUART_TX_EN,
 809                      IO_SPACE_BASE | A_DUART_CHANREG(i, R_DUART_CMD));
 810                duart_set_cflag(i, DEFAULT_CFLAGS);
 811        }
 812
 813        /* Interrupts are now active, our ISR can be called. */
 814
 815        if (tty_register_driver(&sb1250_duart_driver)) {
 816                printk(KERN_ERR "Couldn't register sb1250 duart serial driver\n");
 817        }
 818        if (tty_register_driver(&sb1250_duart_callout_driver)) {
 819                printk(KERN_ERR "Couldn't register sb1250 duart callout driver\n");
 820        }
 821        return 0;
 822}
 823
 824/* Unload the driver.  Unregister stuff, get ready to go away */
 825static void __exit sb1250_duart_fini(void)
 826{
 827        unsigned long flags;
 828        int i;
 829        int ret;
 830
 831        save_and_cli(flags);
 832        ret = tty_unregister_driver(&sb1250_duart_callout_driver);
 833        if (ret) {
 834                printk(KERN_ERR "Unable to unregister sb1250 duart callout driver (%d)\n", ret);
 835        }
 836        ret = tty_unregister_driver(&sb1250_duart_driver);
 837        if (ret) {
 838                printk(KERN_ERR "Unable to unregister sb1250 duart serial driver (%d)\n", ret);
 839        }
 840        for (i=0; i<DUART_MAX_LINE; i++) {
 841                if (!sb1250_duart_present[i])
 842                        continue;
 843                free_irq(K_INT_UART_0+i, &uart_states[i]);
 844                disable_irq(K_INT_UART_0+i);
 845        }
 846        restore_flags(flags);
 847}
 848
 849module_init(sb1250_duart_init);
 850module_exit(sb1250_duart_fini);
 851MODULE_DESCRIPTION("SB1250 Duart serial driver");
 852MODULE_AUTHOR("Justin Carlson, Broadcom Corp.");
 853
 854#ifdef CONFIG_SIBYTE_SB1250_DUART_CONSOLE
 855
 856/*
 857 * Serial console stuff.  Very basic, polling driver for doing serial
 858 * console output.  The console_sem is held by the caller, so we
 859 * shouldn't be interrupted for more console activity.
 860 * XXXKW What about getting interrupted by uart driver activity?
 861 */
 862
 863void serial_outc(unsigned char c, int line)
 864{
 865        uart_state_t *port = uart_states + line;
 866        while (!(READ_SERCSR(port->status, line) & M_DUART_TX_RDY)) ;
 867        WRITE_SERCSR(c, port->tx_hold, line);
 868        while (!(READ_SERCSR(port->status, port->line) & M_DUART_TX_EMT)) ;
 869}
 870
 871static void ser_console_write(struct console *cons, const char *s,
 872        unsigned int count)
 873{
 874        int line = cons->index;
 875        uart_state_t *port = uart_states + line;
 876        u32 imr;
 877
 878        imr = READ_SERCSR(port->imr, line);
 879        WRITE_SERCSR(0, port->imr, line);
 880        while (count--) {
 881                if (*s == '\n')
 882                        serial_outc('\r', line);
 883                serial_outc(*s++, line);
 884        }
 885        WRITE_SERCSR(imr, port->imr, line);
 886}
 887
 888static kdev_t ser_console_device(struct console *c)
 889{
 890        return MKDEV(TTY_MAJOR, SB1250_DUART_MINOR_BASE + c->index);
 891}
 892
 893static int ser_console_setup(struct console *cons, char *str)
 894{
 895        int i;
 896
 897        for (i=0; i<DUART_MAX_LINE; i++) {
 898                uart_state_t *port = uart_states + i;
 899
 900                if (!sb1250_duart_present[i])
 901                        continue;
 902
 903                init_duart_port(port, i);
 904#if SIBYTE_1956_WAR
 905                last_mode1[i] = V_DUART_PARITY_MODE_NONE|V_DUART_BITS_PER_CHAR_8;
 906#endif
 907                WRITE_SERCSR(V_DUART_PARITY_MODE_NONE|V_DUART_BITS_PER_CHAR_8,
 908                             port->mode_1, i);
 909                WRITE_SERCSR(M_DUART_STOP_BIT_LEN_1,
 910                             port->mode_2, i);
 911                WRITE_SERCSR(V_DUART_BAUD_RATE(115200),
 912                             port->clk_sel, i);
 913                WRITE_SERCSR(M_DUART_RX_EN|M_DUART_TX_EN,
 914                             port->cmd, i);
 915        }
 916        return 0;
 917}
 918
 919static struct console sb1250_ser_cons = {
 920        name:           "duart",
 921        write:          ser_console_write,
 922        device:         ser_console_device,
 923        setup:          ser_console_setup,
 924        flags:          CON_PRINTBUFFER,
 925        index:          -1,
 926};
 927
 928void __init sb1250_serial_console_init(void)
 929{
 930        register_console(&sb1250_ser_cons);
 931}
 932
 933#endif /* CONFIG_SIBYTE_SB1250_DUART_CONSOLE */
 934
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.