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

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