root/kernel/chr_drv/serial.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. send_break
  2. rs_sched_event
  3. UART_ISR_proc
  4. send_intr
  5. receive_intr
  6. line_status_intr
  7. modem_status_intr
  8. UART_ISR_proc
  9. FourPort_ISR_proc
  10. rs_interrupt
  11. rs_probe
  12. rs_timer
  13. rs_write
  14. rs_throttle
  15. rs_close
  16. startup
  17. shutdown
  18. change_speed
  19. get_serial_info
  20. set_serial_info
  21. get_modem_info
  22. set_modem_info
  23. rs_ioctl
  24. rs_open
  25. show_serial_version
  26. init
  27. rs_init

   1 /*
   2  *  linux/kernel/serial.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  *
   6  *  Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92.  Now
   7  *  much more extensible to support other serial cards based on the
   8  *  16450/16550A UART's.  Added support for the AST FourPort and the
   9  *  Accent Async board.  We use the async_ISR structure to allow
  10  *  multiple ports (or boards, if the hardware permits) to share a
  11  *  single IRQ channel.
  12  *
  13  *  set_serial_info fixed to set the flags, custom divisor, and uart
  14  *      type fields.  Fix suggested by Michael K. Johnson 12/12/92.
  15  *
  16  * This module exports the following rs232 io functions:
  17  *
  18  *      long rs_init(long);
  19  *      int  rs_open(struct tty_struct * tty, struct file * filp)
  20  *      void change_speed(unsigned int line)
  21  */
  22 
  23 #include <linux/errno.h>
  24 #include <linux/signal.h>
  25 #include <linux/sched.h>
  26 #include <linux/timer.h>
  27 #include <linux/tty.h>
  28 #include <linux/serial.h>
  29 #include <linux/config.h>
  30 
  31 #include <asm/system.h>
  32 #include <asm/io.h>
  33 #include <asm/segment.h>
  34 #include <asm/bitops.h>
  35 
  36 /*
  37  * Serial driver configuration section.  Here are the various options:
  38  *
  39  * CONFIG_AUTO_IRQ
  40  *              Enables automatic IRQ detection.  I've put in some
  41  *              fixes to this which should make this work much more
  42  *              cleanly than it used to in 0.98pl2-6.  It should be
  43  *              much less vulnerable to false IRQ's now.
  44  * 
  45  * NEW_INTERRUPT_ROUTINE
  46  *              Enables the new interrupt routine, which is faster
  47  *              (which is better on slow CPU's), and handles parity
  48  *              errors, break conditions, and hardware handshaking.
  49  *              People were having problems with it earlier, but I
  50  *              believe they have been fixed now, so there should
  51  *              hopefully be no reason to #undef this option.
  52  * 
  53  * CONFIG_AST_FOURPORT
  54  *              Enables support for the AST Fourport serial port.
  55  * 
  56  * CONFIG_ACCENT_ASYNC
  57  *              Enables support for the Accent Async 4 port serial
  58  *              port.
  59  * 
  60  */
  61         
  62 #undef NEW_INTERRUPT_ROUTINE
  63         
  64 #define WAKEUP_CHARS (3*TTY_BUF_SIZE/4)
  65 
  66 /*
  67  * rs_event             - Bitfield of serial lines that events pending
  68  *                              to be processed at the next clock tick.
  69  * rs_write_active      - Bitfield of serial lines that are actively
  70  *                              transmitting (and therefore have a
  71  *                              write timeout pending, in case the
  72  *                              THRE interrupt gets lost.)
  73  * IRQ_ISR[]            - Array to store the head of the ISR linked list
  74  *                              for each IRQ.
  75  */
  76 static unsigned long rs_event = 0;
  77 static unsigned long rs_write_active = 0;
  78 
  79 static async_ISR IRQ_ISR[16];
  80 
  81 static void UART_ISR_proc(async_ISR ISR, int line);
  82 
  83 struct struct_ISR COM1_ISR = { 4, 0x3f8, UART_ISR_proc, 0, };
  84 struct struct_ISR COM2_ISR = { 3, 0x2f8, UART_ISR_proc, 0, };
  85 struct struct_ISR COM3_ISR = { 4, 0x3e8, UART_ISR_proc, 0, };
  86 struct struct_ISR COM4_ISR = { 3, 0x2e8, UART_ISR_proc, 0, };
  87 
  88 #ifdef CONFIG_AST_FOURPORT
  89 static void FourPort_ISR_proc(async_ISR ISR, int line);
  90 
  91 struct struct_ISR FourPort1_ISR = { 2, 0x1bf, FourPort_ISR_proc, 0, };
  92 struct struct_ISR FourPort2_ISR = { 5, 0x2bf, FourPort_ISR_proc, 0, };
  93 #endif
  94 
  95 #ifdef CONFIG_ACCENT_ASYNC
  96 struct struct_ISR Accent3_ISR = { 4, 0x330, UART_ISR_proc, 0, };
  97 struct struct_ISR Accent4_ISR = { 4, 0x338, UART_ISR_proc, 0, };
  98 #endif
  99 
 100 /*
 101  * This assumes you have a 1.8432 MHz clock for your UART.
 102  *
 103  * It'd be nice if someone built a serial card with a 24.576 MHz
 104  * clock, since the 16550A is capable of handling a top speed of 1.5
 105  * megabits/second; but this requires the faster clock.
 106  */
 107 #define BASE_BAUD ( 1843200 / 16 ) 
 108 
 109 struct async_struct rs_table[] = {
 110         { BASE_BAUD, 0x3F8, &COM1_ISR, 0, },
 111         { BASE_BAUD, 0x2F8, &COM2_ISR, 0, },
 112         { BASE_BAUD, 0x3E8, &COM3_ISR, 0, },
 113         { BASE_BAUD, 0x2E8, &COM4_ISR, 0, },
 114 #ifdef CONFIG_AST_FOURPORT
 115         { BASE_BAUD, 0x1A0, &FourPort1_ISR, ASYNC_FOURPORT },
 116         { BASE_BAUD, 0x1A8, &FourPort1_ISR, ASYNC_FOURPORT },
 117         { BASE_BAUD, 0x1B0, &FourPort1_ISR, ASYNC_FOURPORT },
 118         { BASE_BAUD, 0x1B8, &FourPort1_ISR, ASYNC_FOURPORT | ASYNC_NOSCRATCH },
 119 
 120         { BASE_BAUD, 0x2A0, &FourPort2_ISR, ASYNC_FOURPORT },
 121         { BASE_BAUD, 0x2A8, &FourPort2_ISR, ASYNC_FOURPORT },
 122         { BASE_BAUD, 0x2B0, &FourPort2_ISR, ASYNC_FOURPORT },
 123         { BASE_BAUD, 0x2B8, &FourPort2_ISR, ASYNC_FOURPORT | ASYNC_NOSCRATCH },
 124 #else /* CONFIG_AST_FOURPORT */
 125         { BASE_BAUD, 0x000 }, 
 126         { BASE_BAUD, 0x000 }, 
 127         { BASE_BAUD, 0x000 },
 128         { BASE_BAUD, 0x000 }, 
 129 
 130         { BASE_BAUD, 0x000 },
 131         { BASE_BAUD, 0x000 }, 
 132         { BASE_BAUD, 0x000 },
 133         { BASE_BAUD, 0x000 },
 134 #endif /* CONFIG_AST_FOURPORT */
 135         
 136 #ifdef CONFIG_ACCENT_ASYNC
 137         { BASE_BAUD, 0x330, &Accent3_ISR, 0 },
 138         { BASE_BAUD, 0x338, &Accent4_ISR, 0 },
 139 #else /* CONFIG_ACCENT_ASYNC */
 140         { BASE_BAUD, 0x000 },
 141         { BASE_BAUD, 0x000 },
 142 #endif /* CONFIG_ACCENT_ASYNC */
 143         { BASE_BAUD, 0x000 },
 144         { BASE_BAUD, 0x000 },
 145         
 146 };
 147 
 148 #define NR_PORTS        (sizeof(rs_table)/sizeof(struct async_struct))
 149 
 150 /*
 151  * This is used to figure out the divsor speeds and the timeouts
 152  */
 153 static int baud_table[] = {
 154         0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
 155         9600, 19200, 38400, 56000, 115200, 0 };
 156 
 157 static void startup(struct async_struct * info);
 158 static void shutdown(struct async_struct * info);
 159 static void rs_throttle(struct tty_struct * tty, int status);
 160 
 161 static void send_break( struct async_struct * info)
     /* [previous][next][first][last][top][bottom][index][help] */
 162 {
 163         unsigned short port;
 164 
 165         if (!(port = info->port))
 166                 return;
 167         port += UART_LCR;
 168         current->state = TASK_INTERRUPTIBLE;
 169         current->timeout = jiffies + 25;
 170         outb_p(inb_p(port) | UART_LCR_SBC, port);
 171         schedule();
 172         outb(inb_p(port) & ~UART_LCR_SBC, port);
 173 }
 174 
 175 static inline void rs_sched_event(int line,
     /* [previous][next][first][last][top][bottom][index][help] */
 176                                   struct async_struct *info,
 177                                   int event)
 178 {
 179         info->event |= 1 << event;
 180         rs_event |= 1 << line;
 181         timer_table[RS_TIMER].expires = 0;
 182         timer_active |= 1 << RS_TIMER;
 183 }
 184 
 185 #ifdef NEW_INTERRUPT_ROUTINE
 186 /*
 187  * This ISR handles the COM1-4 8250, 16450, and 16550A UART's.  It is
 188  * also called by the FourPort ISR, since the FourPort also uses the
 189  * same National Semiconduct UART's, with some interrupt multiplexing
 190  * thrown in.
 191  * 
 192  * This routine assumes nobody else will be mucking with the tty
 193  * queues its working on.  It should be called with the interrupts
 194  * disabled, since it is not reentrant, and it assumes it doesn't need
 195  * to worry about other routines mucking about its data structures
 196  * while it keeps copies of critical pointers in registers.
 197  */
 198 static void UART_ISR_proc(async_ISR ISR, int line)
     /* [previous][next][first][last][top][bottom][index][help] */
 199 {
 200         unsigned char status;
 201         struct async_struct * info = rs_table + line;
 202         struct tty_queue * queue;
 203         int head, tail, count, ch;
 204         int cflag, iflag;
 205         
 206         /*
 207          * Just like the LEFT(x) macro, except it uses the loal tail
 208          * and head variables.
 209          */
 210 #define VLEFT ((tail-head-1)&(TTY_BUF_SIZE-1))
 211 
 212         if (!info || !info->tty || !info->port)
 213                 return;
 214         cflag = info->tty->termios->c_cflag;
 215         iflag = info->tty->termios->c_iflag;
 216         
 217         do {
 218         restart:
 219                 status = inb_p(UART_LSR + info->port);
 220                 if (status & UART_LSR_DR) {
 221                         queue = &info->tty->read_q;
 222                         head = queue->head;
 223                         tail = queue->tail;
 224                         do {
 225                                 ch = inb(UART_RX + info->port);
 226                                 /*
 227                                  * There must be at least 3 characters
 228                                  * free in the queue; otherwise we punt.
 229                                  */
 230                                 if (VLEFT < 3)
 231                                         continue;
 232                                 if (status & (UART_LSR_BI |
 233                                               UART_LSR_FE |
 234                                               UART_LSR_PE)) {
 235                                         if (status & (UART_LSR_BI)) {
 236                                                 if (info->flags & ASYNC_SAK)
 237                         rs_sched_event(line, info, RS_EVENT_DO_SAK);
 238                                                 else if (iflag & IGNBRK)
 239                                                         continue;
 240                                                 else if (iflag & BRKINT) 
 241                         rs_sched_event(line, info, RS_EVENT_BREAK_INT);
 242                                                 else
 243                                                         ch = 0;
 244                                         } else if (iflag & IGNPAR)
 245                                                 continue;
 246                                         if (iflag & PARMRK) {
 247                                                 queue->buf[head++] = 0xff;
 248                                                 head &= TTY_BUF_SIZE-1;
 249                                                 queue->buf[head++] = 0;
 250                                                 head &= TTY_BUF_SIZE-1;
 251                                         } else
 252                                                 ch = 0;
 253                                 } else if ((iflag & PARMRK) && (ch == 0xff)) {
 254                                         queue->buf[head++] = 0xff;
 255                                         head &= TTY_BUF_SIZE-1;
 256                                 }
 257                                 queue->buf[head++] = ch;
 258                                 head &= TTY_BUF_SIZE-1;
 259                         } while ((status = inb_p(UART_LSR + info->port)) &
 260                                  UART_LSR_DR);
 261                         queue->head = head;
 262                         if ((VLEFT < RQ_THRESHOLD_LW)
 263                             && !set_bit(TTY_RQ_THROTTLED, &info->tty->flags)) 
 264                                 rs_throttle(info->tty, TTY_THROTTLE_RQ_FULL);
 265                         rs_sched_event(line, info, RS_EVENT_READ_PROCESS);
 266                 }
 267                 if ((status & UART_LSR_THRE) &&
 268                     !info->tty->stopped) {
 269                         queue = &info->tty->write_q;
 270                         head = queue->head;
 271                         tail = queue->tail;
 272                         if (head==tail && !info->x_char)
 273                                 goto no_xmit;
 274                         if (info->x_char) {
 275                                 outb_p(info->x_char, UART_TX + info->port);
 276                                 info->x_char = 0;
 277                         } else {
 278                                 count = info->xmit_fifo_size;
 279                                 while (count--) {
 280                                         if (tail == head)
 281                                                 break;
 282                                         outb_p(queue->buf[tail++],
 283                                                UART_TX + info->port);
 284                                         tail &= TTY_BUF_SIZE-1;
 285                                 }
 286                         }
 287                         queue->tail = tail;
 288                         if (VLEFT > WAKEUP_CHARS)
 289                                 rs_sched_event(line, info,
 290                                                RS_EVENT_WRITE_WAKEUP);
 291                         info->timer = jiffies + info->timeout;
 292                         if (info->timer < timer_table[RS_TIMER].expires)
 293                                 timer_table[RS_TIMER].expires = info->timer;
 294 #ifdef i386
 295                         rs_write_active |= 1 << line;
 296 #else
 297                         set_bit(line, &rs_write_active);
 298 #endif
 299                         timer_active |= 1 << RS_TIMER;
 300                 }
 301         no_xmit:
 302                 status = inb(UART_MSR + info->port);
 303                 
 304                 if (!(cflag & CLOCAL) && (status & UART_MSR_DDCD)) {
 305                         if (!(status & UART_MSR_DCD))
 306                                 rs_sched_event(line, info, RS_EVENT_HUP_PGRP);
 307                 }
 308                 /*
 309                  * Because of the goto statement, this block must be
 310                  * last.  We have to skip the do/while test condition
 311                  * because the THRE interrupt has probably been lost.
 312                  */
 313                 if (cflag & CRTSCTS) {
 314                         if (info->tty->stopped) {
 315                                 if (status & UART_MSR_CTS) {
 316                                         info->tty->stopped = 0;
 317                                         goto restart;
 318                                 }
 319                         } else 
 320                                 info->tty->stopped = !(status & UART_MSR_CTS);
 321                 }
 322         } while (!(inb_p(UART_IIR + info->port) & UART_IIR_NO_INT));
 323 }
 324 #else /* NEW_INTERRUPT_ROUTINE */
 325 /*
 326  * There are several races here: we avoid most of them by disabling
 327  * timer_active for the crucial part of the process.. That's a good
 328  * idea anyway. 
 329  *
 330  * The problem is that we have to output characters /both/ from interrupts
 331  * and from the normal write: the latter to be sure the interrupts start up
 332  * again. With serial lines, the interrupts can happen so often that the
 333  * races actually are noticeable.
 334  */
 335 static void send_intr(struct async_struct * info)
     /* [previous][next][first][last][top][bottom][index][help] */
 336 {
 337         unsigned short port = info->port;
 338         int line = info->line;
 339         struct tty_queue * queue = &info->tty->write_q;
 340         int c, count = 0;
 341 
 342         if (info->tty->stopped)
 343                 return;
 344 
 345         if (info->type == PORT_16550A)
 346                 count = 16;     
 347         else
 348                 count = 1;
 349         
 350         rs_write_active &= ~(1 << line);
 351 
 352         if (inb_p(UART_LSR + info->port) & UART_LSR_THRE) {
 353                 while (count-- && !info->tty->stopped) {
 354                         if (queue->tail == queue->head)
 355                                 goto end_send;
 356                         c = queue->buf[queue->tail];
 357                         queue->tail++;
 358                         queue->tail &= TTY_BUF_SIZE-1;
 359                         outb(c, UART_TX + port);
 360                 }
 361         }
 362         info->timer = jiffies + info->timeout;
 363         if (info->timer < timer_table[RS_TIMER].expires)
 364                 timer_table[RS_TIMER].expires = info->timer;
 365         rs_write_active |= 1 << line;
 366         timer_active |= 1 << RS_TIMER;
 367 end_send:
 368         if (LEFT(queue) > WAKEUP_CHARS)
 369                 wake_up(&queue->proc_list);
 370 }
 371 
 372 static void receive_intr(struct async_struct * info)
     /* [previous][next][first][last][top][bottom][index][help] */
 373 {
 374         unsigned short port = info->port;
 375         struct tty_queue * queue = &info->tty->read_q;
 376         int head = queue->head;
 377         int maxhead = (queue->tail-1) & (TTY_BUF_SIZE-1);
 378         int count = 0;
 379 
 380         do {
 381                 count++;
 382                 queue->buf[head] = inb(UART_TX + port);
 383                 if (head != maxhead) {
 384                         head++;
 385                         head &= TTY_BUF_SIZE-1;
 386                 }
 387         } while (inb(UART_LSR + port) & UART_LSR_DR);
 388         queue->head = head;
 389         rs_sched_event(info->line, info, RS_EVENT_READ_PROCESS);
 390 }
 391 
 392 static void line_status_intr(struct async_struct * info)
     /* [previous][next][first][last][top][bottom][index][help] */
 393 {
 394         unsigned char status = inb(UART_LSR + info->port);
 395 
 396 /*      printk("line status: %02x\n",status);  */
 397 }
 398 
 399 static void modem_status_intr(struct async_struct * info)
     /* [previous][next][first][last][top][bottom][index][help] */
 400 {
 401         unsigned char status = inb(UART_MSR + info->port);
 402 
 403         if (!(info->tty->termios->c_cflag & CLOCAL)) {
 404                 if ((status & (UART_MSR_DCD|UART_MSR_DDCD)) == UART_MSR_DDCD)
 405                         tty_hangup(info->tty);
 406 
 407                 if (info->tty->termios->c_cflag & CRTSCTS)
 408                         info->tty->stopped = !(status & UART_MSR_CTS);
 409 
 410                 if (!info->tty->stopped)
 411                         send_intr(info);
 412         }
 413 }
 414 
 415 static void (*jmp_table[4])(struct async_struct *) = {
 416         modem_status_intr,
 417         send_intr,
 418         receive_intr,
 419         line_status_intr
 420 };
 421 
 422 /*
 423  * This ISR handles the COM1-4 8250, 16450, and 16550A UART's.  It is
 424  * also called by the FourPort ISR, since the FourPort also uses the
 425  * same National Semiconduct UART's, with some interrupt multiplexing
 426  * thrown in.
 427  */
 428 static void UART_ISR_proc(async_ISR ISR, int line)
     /* [previous][next][first][last][top][bottom][index][help] */
 429 {
 430         unsigned char ident;
 431         struct async_struct * info = rs_table + line;
 432 
 433         if (!info || !info->tty || !info->port)
 434                   return;
 435         while (1) {
 436                 ident = inb(UART_IIR + info->port) & 7;
 437                 if (ident & 1)
 438                         return;
 439                 ident = ident >> 1;
 440                 jmp_table[ident](info);
 441         }
 442 }
 443 #endif /* NEW_INTERRUPT_ROUTINE */
 444 
 445 #ifdef CONFIG_AST_FOURPORT
 446 /*
 447  * Here is the fourport ISR
 448  */
 449 static void FourPort_ISR_proc(async_ISR ISR, int line)
     /* [previous][next][first][last][top][bottom][index][help] */
 450 {
 451         int             i;
 452         unsigned char ivec;
 453 
 454         ivec = ~inb(ISR->port) & 0x0F;
 455         do {
 456                 for (i = line; ivec; i++) {
 457                         if (ivec & 1)
 458                                 UART_ISR_proc(ISR, i);
 459                         ivec = ivec >> 1;
 460                 }
 461                 ivec = ~inb(ISR->port) & 0x0F;
 462         } while (ivec);
 463 }
 464 #endif /* CONFIG_AST_FOURPORT */
 465 
 466 /*
 467  * This is the serial driver's generic interrupt routine
 468  */
 469 static void rs_interrupt(int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 470 {
 471         async_ISR p = IRQ_ISR[irq];
 472 
 473         while (p) {
 474                 (p->ISR_proc)(p, p->line);
 475                 p = p->next_ISR;
 476         }
 477 }
 478 
 479 #ifdef CONFIG_AUTO_IRQ
 480 /*
 481  * This is the serial driver's interrupt routine while we are probing
 482  * for submarines.
 483  */
 484 static volatile int rs_irq_triggered;
 485 static volatile int rs_triggered;
 486 
 487 static void rs_probe(int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 488 {
 489         rs_irq_triggered = irq;
 490         rs_triggered |= 1 << irq;
 491         return;
 492 }
 493 #endif
 494 
 495 /*
 496  * This subroutine handles all of the timer functionality required for
 497  * the serial ports.
 498  */
 499 
 500 #define END_OF_TIME 0xffffffff
 501 static void rs_timer(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 502 {
 503         unsigned long           mask;
 504         struct async_struct     *info;
 505         unsigned long           next_timeout;
 506 
 507         info = rs_table;
 508         next_timeout = END_OF_TIME;
 509         for (mask = 1 ; mask ; info++, mask <<= 1) {
 510                 if ((mask > rs_event) &&
 511                     (mask > rs_write_active))
 512                         break;
 513                 if (!info->tty) {       /* check that we haven't closed it.. */
 514                         rs_event &= ~mask;
 515                         rs_write_active &= ~mask;
 516                         continue;
 517                 }
 518                 if (mask & rs_event) {
 519                         if (!clear_bit(RS_EVENT_READ_PROCESS, &info->event)) {
 520                                 TTY_READ_FLUSH(info->tty);
 521                         }
 522                         if (!clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
 523                                 wake_up_interruptible(&info->tty->write_q.proc_list);
 524                         }
 525                         if (!clear_bit(RS_EVENT_HUP_PGRP, &info->event))
 526                                 tty_hangup(info->tty);
 527                         if (!clear_bit(RS_EVENT_BREAK_INT, &info->event)) {
 528                                 flush_input(info->tty);
 529                                 flush_output(info->tty);
 530                                 if (info->tty->pgrp > 0)
 531                                         kill_pg(info->tty->pgrp,SIGINT,1);
 532                         }
 533                         if (!clear_bit(RS_EVENT_DO_SAK, &info->event)) {
 534                                 do_SAK(info->tty);
 535                         }
 536                         cli();
 537                         if (info->event) 
 538                                 next_timeout = 0;
 539                         else
 540                                 rs_event &= ~mask;
 541                         sti();
 542                 }
 543                 if (mask & rs_write_active) {
 544                         if (info->timer <= jiffies) {
 545 #ifdef i386
 546                                 rs_write_active &= ~mask;
 547 #else
 548                                 clear_bit(info->line, &rs_write_active);
 549 #endif
 550                                 rs_write(info->tty);
 551                         }
 552                         if ((mask & rs_write_active) &&
 553                             (info->timer < next_timeout))
 554                                 next_timeout = info->timer;
 555                 }
 556         }
 557         if (next_timeout != END_OF_TIME) {
 558                 timer_table[RS_TIMER].expires = next_timeout;
 559 #ifdef i386
 560                 /*
 561                  * This must compile to a single, atomic instruction.
 562                  * It does using 386 with GCC; if you're not sure, use
 563                  * the set_bit function, which is supposed to be atomic.
 564                  */
 565                 timer_active |= 1 << RS_TIMER;
 566 #else
 567                 set_bit(RS_TIMER, &timer_active);
 568 #endif
 569         }
 570 }
 571 
 572 /*
 573  * This routine gets called when tty_write has put something into
 574  * the write_queue. It calls UART_ISR_proc to simulate an interrupt,
 575  * which gets things going.
 576  */
 577 void rs_write(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 578 {
 579         struct async_struct *info;
 580 
 581         if (!tty || tty->stopped || EMPTY(&tty->write_q))
 582                 return;
 583         info = rs_table + DEV_TO_SL(tty->line);
 584         if (!test_bit(info->line, &rs_write_active)) {
 585                 cli();
 586 #ifdef NEW_INTERRUPT_ROUTINE
 587                 UART_ISR_proc(info->ISR, info->line);
 588 #else
 589                 send_intr(info);
 590 #endif
 591                 sti();
 592         }
 593         
 594 }
 595 
 596 static void rs_throttle(struct tty_struct * tty, int status)
     /* [previous][next][first][last][top][bottom][index][help] */
 597 {
 598         struct async_struct *info;
 599         unsigned char mcr;
 600 
 601 #ifdef notdef
 602         printk("throttle tty%d: %d (%d, %d)....\n", DEV_TO_SL(tty->line),
 603                status, LEFT(&tty->read_q), LEFT(&tty->secondary));
 604 #endif
 605         switch (status) {
 606         case TTY_THROTTLE_RQ_FULL:
 607                 info = rs_table + DEV_TO_SL(tty->line);
 608                 if (tty->termios->c_iflag & IXOFF) {
 609                         info->x_char = STOP_CHAR(tty);
 610                 } else {
 611                         mcr = inb_p(UART_MCR + info->port);
 612                         mcr &= ~UART_MCR_RTS;
 613                         outb(mcr, UART_MCR + info->port);
 614                 }
 615                 break;
 616         case TTY_THROTTLE_RQ_AVAIL:
 617                 info = rs_table + DEV_TO_SL(tty->line);
 618                 if (tty->termios->c_iflag & IXOFF) {
 619                         cli();
 620                         if (info->x_char)
 621                                 info->x_char = 0;
 622                         else
 623                                 info->x_char = START_CHAR(tty);
 624                         sti();
 625                 } else {
 626                         mcr = inb(UART_MCR + info->port);
 627                         mcr |= UART_MCR_RTS;
 628                         outb_p(mcr, UART_MCR + info->port);
 629                 }
 630                 break;
 631         }
 632 }
 633 
 634 /*
 635  * This routine is called when the serial port gets closed.  First, we
 636  * wait for the last remaining data to be sent.  Then, we unlink its
 637  * ISR from the interrupt chain if necessary, and we free that IRQ if
 638  * nothing is left in the chain.
 639  */
 640 static void rs_close(struct tty_struct *tty, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 641 {
 642         struct async_struct * info;
 643         async_ISR               ISR;
 644         int irq, line;
 645 
 646         line = DEV_TO_SL(tty->line);
 647         if ((line < 0) || (line >= NR_PORTS))
 648                 return;
 649         tty->stopped = 0;               /* Force flush to succeed */
 650         wait_until_sent(tty);
 651         info = rs_table + line;
 652         if (!info->port)
 653                 return;
 654         shutdown(info);
 655 #ifdef i386
 656         rs_write_active &= ~(1 << line);
 657         rs_event &= ~(1 << line);
 658 #else
 659         clear_bit(line, &rs_write_active);
 660         clear_bit(line, &rs_event);
 661 #endif
 662         info->event = 0;
 663         info->tty = 0;
 664         ISR = info->ISR;
 665         irq = ISR->irq;
 666         if (irq == 2)
 667                 irq = 9;
 668         if (--ISR->refcnt == 0) {
 669                 if (ISR->next_ISR)
 670                         ISR->next_ISR->prev_ISR = ISR->prev_ISR;
 671                 if (ISR->prev_ISR)
 672                         ISR->prev_ISR->next_ISR = ISR->next_ISR;
 673                 else
 674                         IRQ_ISR[irq] = ISR->next_ISR;
 675                 if (!IRQ_ISR[irq])
 676                         free_irq(irq);
 677         }
 678 }
 679 
 680 static void startup(struct async_struct * info)
     /* [previous][next][first][last][top][bottom][index][help] */
 681 {
 682         unsigned short port = info->port;
 683         unsigned short ICP;
 684 
 685         /*
 686          * First, clear the FIFO buffers and disable them
 687          */
 688         if (info->type == PORT_16550A)
 689                 outb_p(UART_FCR_CLEAR_CMD, UART_FCR + port);
 690 
 691         /*
 692          * Next, clear the interrupt registers.
 693          */
 694         (void)inb_p(UART_LSR + port);
 695         (void)inb_p(UART_RX + port);
 696         (void)inb_p(UART_IIR + port);
 697         (void)inb_p(UART_MSR + port);
 698 
 699         /*
 700          * Now, initialize the UART 
 701          */
 702         outb_p(UART_LCR_WLEN8, UART_LCR + port);        /* reset DLAB */
 703         if (info->flags & ASYNC_FOURPORT) 
 704                 outb_p(UART_MCR_DTR | UART_MCR_RTS, 
 705                        UART_MCR + port);
 706         else
 707                 outb_p(UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2, 
 708                        UART_MCR + port);
 709         
 710         /*
 711          * Enable FIFO's if necessary
 712          */
 713         if (info->type == PORT_16550A) {
 714                 outb_p(UART_FCR_SETUP_CMD, UART_FCR + port);
 715                 info->xmit_fifo_size = 16;
 716         } else {
 717                 info->xmit_fifo_size = 1;
 718         }
 719 
 720         /*
 721          * Finally, enable interrupts
 722          */
 723         outb_p(0x0f,UART_IER + port);   /* enable all intrs */
 724         if (info->flags & ASYNC_FOURPORT) {
 725                 /* Enable interrupts on the AST Fourport board */
 726                 ICP = (port & 0xFE0) | 0x01F;
 727                 outb_p(0x80, ICP);
 728                 (void) inb(ICP);
 729         }
 730 
 731         /*
 732          * And clear the interrupt registers again for luck.
 733          */
 734         (void)inb_p(UART_LSR + port);
 735         (void)inb_p(UART_RX + port);
 736         (void)inb_p(UART_IIR + port);
 737         (void)inb_p(UART_MSR + port);
 738 }
 739 
 740 static void shutdown(struct async_struct * info)
     /* [previous][next][first][last][top][bottom][index][help] */
 741 {
 742         unsigned short port = info->port;
 743         
 744         outb_p(0x00,            UART_IER + port);       /* disable all intrs */
 745         if (info->tty && !(info->tty->termios->c_cflag & HUPCL))
 746                 outb_p(UART_MCR_DTR, UART_MCR + port);
 747         else
 748                 /* reset DTR,RTS,OUT_2 */               
 749                 outb_p(0x00,            UART_MCR + port);
 750         outb_p(UART_FCR_CLEAR_CMD, UART_FCR + info->port); /* disable FIFO's */
 751         (void)inb(UART_RX + port);     /* read data port to reset things */
 752 }
 753 
 754 void change_speed(unsigned int line)
     /* [previous][next][first][last][top][bottom][index][help] */
 755 {
 756         struct async_struct * info;
 757         unsigned short port;
 758         int     quot = 0;
 759         unsigned cflag,cval,mcr;
 760         int     i;
 761 
 762         if (line >= NR_PORTS)
 763                 return;
 764         info = rs_table + line;
 765         if (!info->tty || !info->tty->termios)
 766                 return;
 767         cflag = info->tty->termios->c_cflag;
 768         if (!(port = info->port))
 769                 return;
 770         i = cflag & CBAUD;
 771         if (i == 15) {
 772                 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
 773                         i += 1;
 774                 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
 775                         i += 2;
 776                 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
 777                         quot = info->custom_divisor;
 778         }
 779         if (quot) {
 780                 info->timeout = ((info->xmit_fifo_size*HZ*15*quot) /
 781                                  info->baud_base) + 2;
 782         } else if (baud_table[i] == 134) {
 783                 quot = (2*info->baud_base / 269);
 784                 info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
 785         } else if (baud_table[i]) {
 786                 quot = info->baud_base / baud_table[i];
 787                 info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2;
 788         } else {
 789                 quot = 0;
 790                 info->timeout = 0;
 791         }
 792         mcr = inb(UART_MCR + port);
 793         if (quot) 
 794                 outb(mcr | UART_MCR_DTR, UART_MCR + port);
 795         else {
 796                 outb(mcr & ~UART_MCR_DTR, UART_MCR + port);
 797                 return;
 798         }
 799         /* byte size and parity */
 800         cval = cflag & (CSIZE | CSTOPB);
 801         cval >>= 4;
 802         if (cflag & PARENB)
 803                 cval |= 8;
 804         if (!(cflag & PARODD))
 805                 cval |= 16;
 806         cli();
 807         outb_p(cval | UART_LCR_DLAB, UART_LCR + port);  /* set DLAB */
 808         outb_p(quot & 0xff, UART_DLL + port);   /* LS of divisor */
 809         outb_p(quot >> 8, UART_DLM + port);     /* MS of divisor */
 810         outb(cval, UART_LCR + port);            /* reset DLAB */
 811         sti();
 812 }
 813 
 814 static int get_serial_info(struct async_struct * info,
     /* [previous][next][first][last][top][bottom][index][help] */
 815                            struct serial_struct * retinfo)
 816 {
 817         struct serial_struct tmp;
 818   
 819         if (!retinfo)
 820                 return -EFAULT;
 821         tmp.type = info->type;
 822         tmp.line = info->line;
 823         tmp.port = info->port;
 824         tmp.irq = info->ISR->irq;
 825 /*      tmp.flags = info->flags; */
 826         memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));
 827         return 0;
 828 }
 829 
 830 static int set_serial_info(struct async_struct * info,
     /* [previous][next][first][last][top][bottom][index][help] */
 831                            struct serial_struct * new_info)
 832 {
 833         struct serial_struct tmp;
 834         async_ISR               ISR;
 835         unsigned int            new_port;
 836         unsigned int            irq,new_irq;
 837         int                     retval;
 838         struct                  sigaction sa;
 839 
 840         if (!suser())
 841                 return -EPERM;
 842         if (!new_info)
 843                 return -EFAULT;
 844         memcpy_fromfs(&tmp,new_info,sizeof(tmp));
 845 
 846         info->flags = tmp.flags & ASYNC_FLAGS;
 847         
 848         if ( (tmp.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
 849                 info->custom_divisor = tmp.custom_divisor;
 850         
 851         if ((tmp.type >= PORT_UNKNOWN) && (tmp.type <= PORT_MAX))
 852                 info->type = tmp.type;
 853         
 854         new_port = tmp.port;
 855         new_irq = tmp.irq;
 856         if (new_irq > 15 || new_port > 0xffff)
 857                 return -EINVAL;
 858         if (new_irq == 2)
 859                 new_irq = 9;
 860         ISR = info->ISR;
 861         irq = ISR->irq;
 862         if (irq == 2)
 863                 irq = 9;
 864         if (irq != new_irq) {
 865                 /*
 866                  * We need to change the IRQ for this board.  OK, if
 867                  * necessary, first we try to grab the new IRQ for
 868                  * serial interrupts.
 869                  */
 870                 if (!IRQ_ISR[new_irq]) {
 871                         sa.sa_handler = rs_interrupt;
 872                         sa.sa_flags = (SA_INTERRUPT);
 873                         sa.sa_mask = 0;
 874                         sa.sa_restorer = NULL;
 875                         retval = irqaction(new_irq,&sa);
 876                         if (retval)
 877                                 return retval;
 878                 }
 879 
 880                 /*
 881                  * If the new IRQ is OK, now we unlink the ISR from
 882                  * the existing interrupt chain.
 883                  */
 884                 if (ISR->next_ISR)
 885                         ISR->next_ISR->prev_ISR = ISR->prev_ISR;
 886                 if (ISR->prev_ISR)
 887                         ISR->prev_ISR->next_ISR = ISR->next_ISR;
 888                 else
 889                         IRQ_ISR[irq] = ISR->next_ISR;
 890                 if (!IRQ_ISR[irq])
 891                         free_irq(irq);
 892 
 893                 /*
 894                  * Now link in the interrupt to the new interrupt chain.
 895                  */
 896                 ISR->prev_ISR = 0;
 897                 ISR->next_ISR = IRQ_ISR[new_irq];
 898                 if (ISR->next_ISR)
 899                         ISR->next_ISR->prev_ISR = ISR;
 900                 IRQ_ISR[new_irq] = ISR;
 901                 ISR->irq = new_irq;
 902         }
 903         cli();
 904         if (new_port != info->port) {
 905                 shutdown(info);
 906                 info->port = new_port;
 907                 startup(info);
 908                 change_speed(info->line);
 909         }
 910         sti();
 911         return 0;
 912 }
 913 
 914 static int get_modem_info(struct async_struct * info, unsigned int *value)
     /* [previous][next][first][last][top][bottom][index][help] */
 915 {
 916         unsigned port;
 917         unsigned char control, status;
 918         unsigned int result;
 919 
 920         port = info->port;
 921         control = inb(UART_MCR + port);
 922         status = inb(UART_MSR + port);
 923         result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
 924                 | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
 925                 | ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
 926                 | ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
 927                 | ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
 928                 | ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
 929         put_fs_long(result,(unsigned long *) value);
 930         return 0;
 931 }
 932 
 933 static int set_modem_info(struct async_struct * info, unsigned int cmd,
     /* [previous][next][first][last][top][bottom][index][help] */
 934                           unsigned int *value)
 935 {
 936         unsigned port;
 937         unsigned char control;
 938         unsigned int arg = get_fs_long((unsigned long *) value);
 939         
 940         port = info->port;
 941         control = inb(UART_MCR + port);
 942 
 943         switch (cmd) {
 944                 case TIOCMBIS:
 945                         if (arg & TIOCM_RTS)
 946                                 control |= UART_MCR_RTS;
 947                         if (arg & TIOCM_DTR)
 948                                 control |= UART_MCR_DTR;
 949                         break;
 950                 case TIOCMBIC:
 951                         if (arg & TIOCM_RTS)
 952                                 control &= ~UART_MCR_RTS;
 953                         if (arg & TIOCM_DTR)
 954                                 control &= ~UART_MCR_DTR;
 955                         break;
 956                 case TIOCMSET:
 957                         control = (control & ~0x03)
 958                                 | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
 959                                 | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0);
 960                         break;
 961                 default:
 962                         return -EINVAL;
 963         }
 964         outb(control, UART_MCR + port);
 965         return 0;
 966 }
 967 
 968 static int rs_ioctl(struct tty_struct *tty, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 969                     unsigned int cmd, unsigned int arg)
 970 {
 971         int     line;
 972         struct async_struct * info;
 973 
 974         line = DEV_TO_SL(tty->line);
 975         if (line < 0 || line >= NR_PORTS)
 976                 return -ENODEV;
 977         info = rs_table + line;
 978         
 979         switch (cmd) {
 980                 case TCSBRK:
 981                         wait_until_sent(tty);
 982                         if (!arg)
 983                                 send_break(info);
 984                         return 0;
 985                 case TIOCMGET:
 986                         verify_area((void *) arg,sizeof(unsigned int *));
 987                         return get_modem_info(info, (unsigned int *) arg);
 988                 case TIOCMBIS:
 989                 case TIOCMBIC:
 990                 case TIOCMSET:
 991                         return set_modem_info(info, cmd, (unsigned int *) arg);
 992                 case TIOCGSERIAL:
 993                         verify_area((void *) arg,sizeof(struct serial_struct));
 994                         return get_serial_info(info,
 995                                                (struct serial_struct *) arg);
 996                 case TIOCSSERIAL:
 997                         return set_serial_info(info,
 998                                                (struct serial_struct *) arg);
 999                 
1000         default:
1001                 return -EINVAL;
1002         }
1003         return 0;
1004 }       
1005 
1006 /*
1007  * This routine is called whenever a serial port is opened.  It
1008  * enables interrupts for a serial port, linking in its interrupt into
1009  * the ISR chain.   It also performs the serial-speicific
1010  * initalization for the tty structure.
1011  */
1012 int rs_open(struct tty_struct *tty, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
1013 {
1014         struct async_struct     *info;
1015         async_ISR               ISR;
1016         int                     irq, retval, line;
1017         struct sigaction        sa;
1018 
1019         if (!tty)
1020                 return -ENODEV;
1021         if (tty->count > 1)
1022                 return 0;               /* We've already been initialized */
1023         line = DEV_TO_SL(tty->line);
1024         if ((line < 0) || (line >= NR_PORTS))
1025                 return -ENODEV;
1026         info = rs_table + line;
1027         if (!info->port || !info->ISR->irq)
1028                 return -ENODEV;
1029         info->tty = tty;
1030         tty->write = rs_write;
1031         tty->close = rs_close;
1032         tty->ioctl = rs_ioctl;
1033         tty->throttle = rs_throttle;
1034         ISR = info->ISR;
1035         irq = ISR->irq;
1036         if (irq == 2)
1037                 irq = 9;
1038         if (!IRQ_ISR[irq]) {
1039                 sa.sa_handler = rs_interrupt;
1040                 sa.sa_flags = (SA_INTERRUPT);
1041                 sa.sa_mask = 0;
1042                 sa.sa_restorer = NULL;
1043                 retval = irqaction(irq,&sa);
1044                 if (retval)
1045                         return retval;
1046         }
1047         if (!ISR->refcnt++) {
1048                 /*
1049                  * If this is the first time we're using this ISR,
1050                  * link it in.
1051                  */
1052                 ISR->prev_ISR = 0;
1053                 ISR->next_ISR = IRQ_ISR[irq];
1054                 if (ISR->next_ISR)
1055                         ISR->next_ISR->prev_ISR = ISR;
1056                 IRQ_ISR[irq] = ISR;
1057         }
1058         startup(info);
1059         change_speed(info->line);
1060         return 0;
1061 }
1062 
1063 static void show_serial_version()
     /* [previous][next][first][last][top][bottom][index][help] */
1064 {
1065         printk("Serial driver version 3.1 with");
1066 #ifdef CONFIG_AST_FOURPORT
1067         printk(" AST_FOURPORT");
1068 #define SERIAL_OPT
1069 #endif
1070 #ifdef CONFIG_ACCENT_ASYNC
1071         printk(" ACCENT_ASYNC");
1072 #define SERIAL_OPT
1073 #endif
1074 #ifdef CONFIG_AUTO_IRQ
1075         printk (" AUTO_IRQ");
1076 #define SERIAL_OPT
1077 #endif
1078 #ifdef NEW_INTERRUPT_ROUTINE
1079         printk(" NEW_INTERRUPT_ROUTINE");
1080 #define SERIAL_OPT
1081 #endif
1082 #ifdef SERIAL_OPT
1083         printk(" enabled\n");
1084 #else
1085         printk(" no serial options enabled\n");
1086 #endif
1087 #undef SERIAL_OPT
1088 }
1089 
1090 
1091 static void init(struct async_struct * info)
     /* [previous][next][first][last][top][bottom][index][help] */
1092 {
1093 #ifdef CONFIG_AUTO_IRQ
1094         unsigned char status1, status2, scratch, save_ICP=0;
1095         unsigned short ICP=0, port = info->port;
1096         unsigned long timeout;
1097 
1098         /*
1099          * Enable interrupts and see who answers
1100          */
1101         rs_irq_triggered = 0;
1102         scratch = inb_p(UART_IER + port);
1103         status1 = inb_p(UART_MCR + port);
1104         if (info->flags & ASYNC_FOURPORT)  {
1105                 outb_p(UART_MCR_DTR | UART_MCR_RTS, UART_MCR + port);
1106                 outb_p(0x0f,UART_IER + port);   /* enable all intrs */
1107                 ICP = (port & 0xFE0) | 0x01F;
1108                 save_ICP = inb_p(ICP);
1109                 outb_p(0x80, ICP);
1110                 (void) inb(ICP);
1111         } else {
1112                 outb_p(UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2, 
1113                        UART_MCR + port);
1114                 outb_p(0x0f,UART_IER + port);   /* enable all intrs */
1115         }
1116         /*
1117          * Next, clear the interrupt registers.
1118          */
1119         (void)inb_p(UART_LSR + port);
1120         (void)inb_p(UART_RX + port);
1121         (void)inb_p(UART_IIR + port);
1122         (void)inb_p(UART_MSR + port);
1123         timeout = jiffies+2;
1124         while (timeout >= jiffies) {
1125                 if (rs_irq_triggered)
1126                         break;
1127         }
1128         /*
1129          * Now check to see if we got any business, and clean up.
1130          */
1131         if (rs_irq_triggered) {
1132                 outb_p(0, UART_IER + port);
1133                 info->ISR->irq = rs_irq_triggered;
1134         } else {
1135                 outb_p(scratch, UART_IER + port);
1136                 outb_p(status1, UART_MCR + port);
1137                 if (info->flags & ASYNC_FOURPORT)
1138                         outb_p(save_ICP, ICP);
1139                 info->type = PORT_UNKNOWN;
1140                 return;
1141         }
1142 #else /* CONFIG_AUTO_IRQ */
1143         unsigned char status1, status2, scratch, scratch2;
1144         unsigned short port = info->port;
1145 
1146         /* 
1147          * Check to see if a UART is really there.  
1148          */
1149         scratch = inb_p(UART_MCR + port);
1150         outb_p(UART_MCR_LOOP | scratch, UART_MCR + port);
1151         scratch2 = inb_p(UART_MSR + port);
1152         outb_p(UART_MCR_LOOP | 0x0A, UART_MCR + port);
1153         status1 = inb_p(UART_MSR + port) & 0xF0;
1154         outb_p(scratch, UART_MCR + port);
1155         outb_p(scratch2, UART_MSR + port);
1156         if (status1 != 0x90) {
1157                 info->type = PORT_UNKNOWN;
1158                 return;
1159         }
1160 #endif /* CONFIG_AUTO_IRQ */
1161         
1162         if (!(info->flags & ASYNC_NOSCRATCH)) {
1163                 scratch = inb(UART_SCR + port);
1164                 outb_p(0xa5, UART_SCR + port);
1165                 status1 = inb(UART_SCR + port);
1166                 outb_p(0x5a, UART_SCR + port);
1167                 status2 = inb(UART_SCR + port);
1168                 outb_p(scratch, UART_SCR + port);
1169         } else {
1170                 status1 = 0xa5;
1171                 status2 = 0x5a;
1172         }
1173         if (status1 == 0xa5 && status2 == 0x5a) {
1174                 outb_p(UART_FCR_ENABLE_FIFO, UART_FCR + port);
1175                 scratch = inb(UART_IIR + port) >> 6;
1176                 info->xmit_fifo_size = 1;
1177                 switch (scratch) {
1178                         case 0:
1179                                 info->type = PORT_16450;
1180                                 break;
1181                         case 1:
1182                                 info->type = PORT_UNKNOWN;
1183                                 break;
1184                         case 2:
1185                                 info->type = PORT_16550;
1186                                 break;
1187                         case 3:
1188                                 info->type = PORT_16550A;
1189                                 info->xmit_fifo_size = 16;
1190                                 break;
1191                 }
1192         } else
1193                 info->type = PORT_8250;
1194         shutdown(info);
1195 }
1196 
1197 long rs_init(long kmem_start)
     /* [previous][next][first][last][top][bottom][index][help] */
1198 {
1199         int i;
1200         struct async_struct * info;
1201 #ifdef CONFIG_AUTO_IRQ
1202         int irq_lines = 0;
1203         struct sigaction sa;
1204         unsigned long timeout;
1205         
1206         /*
1207          *  We will be auto probing for irq's, so turn on interrupts now!
1208          */
1209         sti();
1210         
1211         rs_triggered = 0;
1212         sa.sa_handler = rs_probe;
1213         sa.sa_flags = (SA_INTERRUPT);
1214         sa.sa_mask = 0;
1215         sa.sa_restorer = NULL;
1216 #endif  
1217         timer_table[RS_TIMER].fn = rs_timer;
1218         timer_table[RS_TIMER].expires = 0;
1219         
1220         for (i = 0; i < 16; i++) {
1221                 IRQ_ISR[i] = 0;
1222 #ifdef CONFIG_AUTO_IRQ
1223                 if (!irqaction(i, &sa))
1224                         irq_lines |= 1 << i;
1225 #endif
1226         }
1227 #ifdef CONFIG_AUTO_IRQ
1228         timeout = jiffies+5;
1229         while (timeout >= jiffies)
1230                 ;
1231         for (i = 0; i < 16; i++) {
1232                 if ((rs_triggered & (1 << i)) &&
1233                     (irq_lines & (1 << i))) {
1234                         irq_lines &= ~(1 << i);
1235                         printk("Wild interrupt?  (IRQ %d)\n", i);
1236                         free_irq(i);
1237                 }
1238         }
1239 #endif
1240         show_serial_version();
1241         for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
1242                 if (!info->port)
1243                         continue;
1244                 info->line = i;
1245                 info->tty = 0;
1246                 info->type = PORT_UNKNOWN;
1247                 info->timer = 0;
1248                 info->custom_divisor = 0;
1249                 info->x_char = 0;
1250                 info->event = 0;
1251                 if (!info->ISR->line) {
1252                         info->ISR->line = i;
1253                         info->ISR->refcnt = 0;
1254                         info->ISR->next_ISR = 0;
1255                         info->ISR->prev_ISR = 0;
1256                 }
1257                 init(info);
1258                 if (info->type == PORT_UNKNOWN)
1259                         continue;
1260                 printk("ttys%d%s at 0x%04x (irq = %d)", info->line, 
1261                        (info->flags & ASYNC_FOURPORT) ? " FourPort" : "",
1262                        info->port, info->ISR->irq);
1263                 switch (info->type) {
1264                         case PORT_8250:
1265                                 printk(" is a 8250\n");
1266                                 break;
1267                         case PORT_16450:
1268                                 printk(" is a 16450\n");
1269                                 break;
1270                         case PORT_16550:
1271                                 printk(" is a 16550\n");
1272                                 break;
1273                         case PORT_16550A:
1274                                 printk(" is a 16550A\n");
1275                                 break;
1276                         default:
1277                                 printk("\n");
1278                                 break;
1279                 }
1280         }
1281 #ifdef CONFIG_AUTO_IRQ
1282         /*
1283          * Turn interrupts back off, since they were off when we
1284          * started this.  See start_kernel() in init/main.c.
1285          */
1286         cli();
1287         for (i = 0; i < 16; i++) {
1288                 if (irq_lines & (1 << i))
1289                         free_irq(i);
1290         }
1291 #endif
1292         return kmem_start;
1293 }
1294 

/* [previous][next][first][last][top][bottom][index][help] */