root/kernel/chr_drv/serial.c

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

DEFINITIONS

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

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