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

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