linux/drivers/char/isicom.c
<<
>>
Prefs
   1/*
   2 *      This program is free software; you can redistribute it and/or
   3 *      modify it under the terms of the GNU General Public License
   4 *      as published by the Free Software Foundation; either version
   5 *      2 of the License, or (at your option) any later version.
   6 *
   7 *      Original driver code supplied by Multi-Tech
   8 *
   9 *      Changes
  10 *      1/9/98  alan@lxorguk.ukuu.org.uk
  11 *                                      Merge to 2.0.x kernel tree
  12 *                                      Obtain and use official major/minors
  13 *                                      Loader switched to a misc device
  14 *                                      (fixed range check bug as a side effect)
  15 *                                      Printk clean up
  16 *      9/12/98 alan@lxorguk.ukuu.org.uk
  17 *                                      Rough port to 2.1.x
  18 *
  19 *      10/6/99 sameer                  Merged the ISA and PCI drivers to
  20 *                                      a new unified driver.
  21 *
  22 *      3/9/99  sameer                  Added support for ISI4616 cards.
  23 *
  24 *      16/9/99 sameer                  We do not force RTS low anymore.
  25 *                                      This is to prevent the firmware
  26 *                                      from getting confused.
  27 *
  28 *      26/10/99 sameer                 Cosmetic changes:The driver now
  29 *                                      dumps the Port Count information
  30 *                                      along with I/O address and IRQ.
  31 *
  32 *      13/12/99 sameer                 Fixed the problem with IRQ sharing.
  33 *
  34 *      10/5/00  sameer                 Fixed isicom_shutdown_board()
  35 *                                      to not lower DTR on all the ports
  36 *                                      when the last port on the card is
  37 *                                      closed.
  38 *
  39 *      10/5/00  sameer                 Signal mask setup command added
  40 *                                      to  isicom_setup_port and
  41 *                                      isicom_shutdown_port.
  42 *
  43 *      24/5/00  sameer                 The driver is now SMP aware.
  44 *
  45 *
  46 *      27/11/00 Vinayak P Risbud       Fixed the Driver Crash Problem
  47 *
  48 *
  49 *      03/01/01  anil .s               Added support for resetting the
  50 *                                      internal modems on ISI cards.
  51 *
  52 *      08/02/01  anil .s               Upgraded the driver for kernel
  53 *                                      2.4.x
  54 *
  55 *      11/04/01  Kevin                 Fixed firmware load problem with
  56 *                                      ISIHP-4X card
  57 *
  58 *      30/04/01  anil .s               Fixed the remote login through
  59 *                                      ISI port problem. Now the link
  60 *                                      does not go down before password
  61 *                                      prompt.
  62 *
  63 *      03/05/01  anil .s               Fixed the problem with IRQ sharing
  64 *                                      among ISI-PCI cards.
  65 *
  66 *      03/05/01  anil .s               Added support to display the version
  67 *                                      info during insmod as well as module
  68 *                                      listing by lsmod.
  69 *
  70 *      10/05/01  anil .s               Done the modifications to the source
  71 *                                      file and Install script so that the
  72 *                                      same installation can be used for
  73 *                                      2.2.x and 2.4.x kernel.
  74 *
  75 *      06/06/01  anil .s               Now we drop both dtr and rts during
  76 *                                      shutdown_port as well as raise them
  77 *                                      during isicom_config_port.
  78 *
  79 *      09/06/01 acme@conectiva.com.br  use capable, not suser, do
  80 *                                      restore_flags on failure in
  81 *                                      isicom_send_break, verify put_user
  82 *                                      result
  83 *
  84 *      11/02/03  ranjeeth              Added support for 230 Kbps and 460 Kbps
  85 *                                      Baud index extended to 21
  86 *
  87 *      20/03/03  ranjeeth              Made to work for Linux Advanced server.
  88 *                                      Taken care of license warning.
  89 *
  90 *      10/12/03  Ravindra              Made to work for Fedora Core 1 of
  91 *                                      Red Hat Distribution
  92 *
  93 *      06/01/05  Alan Cox              Merged the ISI and base kernel strands
  94 *                                      into a single 2.6 driver
  95 *
  96 *      ***********************************************************
  97 *
  98 *      To use this driver you also need the support package. You
  99 *      can find this in RPM format on
 100 *              ftp://ftp.linux.org.uk/pub/linux/alan
 101 *
 102 *      You can find the original tools for this direct from Multitech
 103 *              ftp://ftp.multitech.com/ISI-Cards/
 104 *
 105 *      Having installed the cards the module options (/etc/modprobe.conf)
 106 *
 107 *      options isicom   io=card1,card2,card3,card4 irq=card1,card2,card3,card4
 108 *
 109 *      Omit those entries for boards you don't have installed.
 110 *
 111 *      TODO
 112 *              Merge testing
 113 *              64-bit verification
 114 */
 115
 116#include <linux/module.h>
 117#include <linux/firmware.h>
 118#include <linux/kernel.h>
 119#include <linux/tty.h>
 120#include <linux/tty_flip.h>
 121#include <linux/termios.h>
 122#include <linux/fs.h>
 123#include <linux/sched.h>
 124#include <linux/serial.h>
 125#include <linux/mm.h>
 126#include <linux/interrupt.h>
 127#include <linux/timer.h>
 128#include <linux/delay.h>
 129#include <linux/ioport.h>
 130
 131#include <linux/uaccess.h>
 132#include <linux/io.h>
 133#include <asm/system.h>
 134
 135#include <linux/pci.h>
 136
 137#include <linux/isicom.h>
 138
 139#define InterruptTheCard(base) outw(0, (base) + 0xc)
 140#define ClearInterrupt(base) inw((base) + 0x0a)
 141
 142#define pr_dbg(str...) pr_debug("ISICOM: " str)
 143#ifdef DEBUG
 144#define isicom_paranoia_check(a, b, c) __isicom_paranoia_check((a), (b), (c))
 145#else
 146#define isicom_paranoia_check(a, b, c) 0
 147#endif
 148
 149static int isicom_probe(struct pci_dev *, const struct pci_device_id *);
 150static void __devexit isicom_remove(struct pci_dev *);
 151
 152static struct pci_device_id isicom_pci_tbl[] = {
 153        { PCI_DEVICE(VENDOR_ID, 0x2028) },
 154        { PCI_DEVICE(VENDOR_ID, 0x2051) },
 155        { PCI_DEVICE(VENDOR_ID, 0x2052) },
 156        { PCI_DEVICE(VENDOR_ID, 0x2053) },
 157        { PCI_DEVICE(VENDOR_ID, 0x2054) },
 158        { PCI_DEVICE(VENDOR_ID, 0x2055) },
 159        { PCI_DEVICE(VENDOR_ID, 0x2056) },
 160        { PCI_DEVICE(VENDOR_ID, 0x2057) },
 161        { PCI_DEVICE(VENDOR_ID, 0x2058) },
 162        { 0 }
 163};
 164MODULE_DEVICE_TABLE(pci, isicom_pci_tbl);
 165
 166static struct pci_driver isicom_driver = {
 167        .name           = "isicom",
 168        .id_table       = isicom_pci_tbl,
 169        .probe          = isicom_probe,
 170        .remove         = __devexit_p(isicom_remove)
 171};
 172
 173static int prev_card = 3;       /*      start servicing isi_card[0]     */
 174static struct tty_driver *isicom_normal;
 175
 176static void isicom_tx(unsigned long _data);
 177static void isicom_start(struct tty_struct *tty);
 178
 179static DEFINE_TIMER(tx, isicom_tx, 0, 0);
 180
 181/*   baud index mappings from linux defns to isi */
 182
 183static signed char linuxb_to_isib[] = {
 184        -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17, 18, 19, 20, 21
 185};
 186
 187struct  isi_board {
 188        unsigned long           base;
 189        int                     irq;
 190        unsigned char           port_count;
 191        unsigned short          status;
 192        unsigned short          port_status; /* each bit for each port */
 193        unsigned short          shift_count;
 194        struct isi_port         *ports;
 195        signed char             count;
 196        spinlock_t              card_lock; /* Card wide lock 11/5/00 -sameer */
 197        unsigned long           flags;
 198        unsigned int            index;
 199};
 200
 201struct  isi_port {
 202        unsigned short          magic;
 203        struct tty_port         port;
 204        u16                     channel;
 205        u16                     status;
 206        struct isi_board        *card;
 207        unsigned char           *xmit_buf;
 208        int                     xmit_head;
 209        int                     xmit_tail;
 210        int                     xmit_cnt;
 211};
 212
 213static struct isi_board isi_card[BOARD_COUNT];
 214static struct isi_port  isi_ports[PORT_COUNT];
 215
 216/*
 217 *      Locking functions for card level locking. We need to own both
 218 *      the kernel lock for the card and have the card in a position that
 219 *      it wants to talk.
 220 */
 221
 222static inline int WaitTillCardIsFree(unsigned long base)
 223{
 224        unsigned int count = 0;
 225        unsigned int a = in_atomic(); /* do we run under spinlock? */
 226
 227        while (!(inw(base + 0xe) & 0x1) && count++ < 100)
 228                if (a)
 229                        mdelay(1);
 230                else
 231                        msleep(1);
 232
 233        return !(inw(base + 0xe) & 0x1);
 234}
 235
 236static int lock_card(struct isi_board *card)
 237{
 238        unsigned long base = card->base;
 239        unsigned int retries, a;
 240
 241        for (retries = 0; retries < 10; retries++) {
 242                spin_lock_irqsave(&card->card_lock, card->flags);
 243                for (a = 0; a < 10; a++) {
 244                        if (inw(base + 0xe) & 0x1)
 245                                return 1;
 246                        udelay(10);
 247                }
 248                spin_unlock_irqrestore(&card->card_lock, card->flags);
 249                msleep(10);
 250        }
 251        printk(KERN_WARNING "ISICOM: Failed to lock Card (0x%lx)\n",
 252                card->base);
 253
 254        return 0;       /* Failed to acquire the card! */
 255}
 256
 257static void unlock_card(struct isi_board *card)
 258{
 259        spin_unlock_irqrestore(&card->card_lock, card->flags);
 260}
 261
 262/*
 263 *  ISI Card specific ops ...
 264 */
 265
 266/* card->lock HAS to be held */
 267static void raise_dtr(struct isi_port *port)
 268{
 269        struct isi_board *card = port->card;
 270        unsigned long base = card->base;
 271        u16 channel = port->channel;
 272
 273        if (WaitTillCardIsFree(base))
 274                return;
 275
 276        outw(0x8000 | (channel << card->shift_count) | 0x02, base);
 277        outw(0x0504, base);
 278        InterruptTheCard(base);
 279        port->status |= ISI_DTR;
 280}
 281
 282/* card->lock HAS to be held */
 283static inline void drop_dtr(struct isi_port *port)
 284{
 285        struct isi_board *card = port->card;
 286        unsigned long base = card->base;
 287        u16 channel = port->channel;
 288
 289        if (WaitTillCardIsFree(base))
 290                return;
 291
 292        outw(0x8000 | (channel << card->shift_count) | 0x02, base);
 293        outw(0x0404, base);
 294        InterruptTheCard(base);
 295        port->status &= ~ISI_DTR;
 296}
 297
 298/* card->lock HAS to be held */
 299static inline void raise_rts(struct isi_port *port)
 300{
 301        struct isi_board *card = port->card;
 302        unsigned long base = card->base;
 303        u16 channel = port->channel;
 304
 305        if (WaitTillCardIsFree(base))
 306                return;
 307
 308        outw(0x8000 | (channel << card->shift_count) | 0x02, base);
 309        outw(0x0a04, base);
 310        InterruptTheCard(base);
 311        port->status |= ISI_RTS;
 312}
 313
 314/* card->lock HAS to be held */
 315static inline void drop_rts(struct isi_port *port)
 316{
 317        struct isi_board *card = port->card;
 318        unsigned long base = card->base;
 319        u16 channel = port->channel;
 320
 321        if (WaitTillCardIsFree(base))
 322                return;
 323
 324        outw(0x8000 | (channel << card->shift_count) | 0x02, base);
 325        outw(0x0804, base);
 326        InterruptTheCard(base);
 327        port->status &= ~ISI_RTS;
 328}
 329
 330/* card->lock MUST NOT be held */
 331
 332static void isicom_raise_dtr_rts(struct tty_port *port)
 333{
 334        struct isi_port *ip = container_of(port, struct isi_port, port);
 335        struct isi_board *card = ip->card;
 336        unsigned long base = card->base;
 337        u16 channel = ip->channel;
 338
 339        if (!lock_card(card))
 340                return;
 341
 342        outw(0x8000 | (channel << card->shift_count) | 0x02, base);
 343        outw(0x0f04, base);
 344        InterruptTheCard(base);
 345        ip->status |= (ISI_DTR | ISI_RTS);
 346        unlock_card(card);
 347}
 348
 349/* card->lock HAS to be held */
 350static void drop_dtr_rts(struct isi_port *port)
 351{
 352        struct isi_board *card = port->card;
 353        unsigned long base = card->base;
 354        u16 channel = port->channel;
 355
 356        if (WaitTillCardIsFree(base))
 357                return;
 358
 359        outw(0x8000 | (channel << card->shift_count) | 0x02, base);
 360        outw(0x0c04, base);
 361        InterruptTheCard(base);
 362        port->status &= ~(ISI_RTS | ISI_DTR);
 363}
 364
 365/*
 366 *      ISICOM Driver specific routines ...
 367 *
 368 */
 369
 370static inline int __isicom_paranoia_check(struct isi_port const *port,
 371        char *name, const char *routine)
 372{
 373        if (!port) {
 374                printk(KERN_WARNING "ISICOM: Warning: bad isicom magic for "
 375                        "dev %s in %s.\n", name, routine);
 376                return 1;
 377        }
 378        if (port->magic != ISICOM_MAGIC) {
 379                printk(KERN_WARNING "ISICOM: Warning: NULL isicom port for "
 380                        "dev %s in %s.\n", name, routine);
 381                return 1;
 382        }
 383
 384        return 0;
 385}
 386
 387/*
 388 *      Transmitter.
 389 *
 390 *      We shovel data into the card buffers on a regular basis. The card
 391 *      will do the rest of the work for us.
 392 */
 393
 394static void isicom_tx(unsigned long _data)
 395{
 396        unsigned long flags, base;
 397        unsigned int retries;
 398        short count = (BOARD_COUNT-1), card;
 399        short txcount, wrd, residue, word_count, cnt;
 400        struct isi_port *port;
 401        struct tty_struct *tty;
 402
 403        /*      find next active board  */
 404        card = (prev_card + 1) & 0x0003;
 405        while (count-- > 0) {
 406                if (isi_card[card].status & BOARD_ACTIVE)
 407                        break;
 408                card = (card + 1) & 0x0003;
 409        }
 410        if (!(isi_card[card].status & BOARD_ACTIVE))
 411                goto sched_again;
 412
 413        prev_card = card;
 414
 415        count = isi_card[card].port_count;
 416        port = isi_card[card].ports;
 417        base = isi_card[card].base;
 418
 419        spin_lock_irqsave(&isi_card[card].card_lock, flags);
 420        for (retries = 0; retries < 100; retries++) {
 421                if (inw(base + 0xe) & 0x1)
 422                        break;
 423                udelay(2);
 424        }
 425        if (retries >= 100)
 426                goto unlock;
 427
 428        tty = tty_port_tty_get(&port->port);
 429        if (tty == NULL)
 430                goto put_unlock;
 431
 432        for (; count > 0; count--, port++) {
 433                /* port not active or tx disabled to force flow control */
 434                if (!(port->port.flags & ASYNC_INITIALIZED) ||
 435                                !(port->status & ISI_TXOK))
 436                        continue;
 437
 438                txcount = min_t(short, TX_SIZE, port->xmit_cnt);
 439                if (txcount <= 0 || tty->stopped || tty->hw_stopped)
 440                        continue;
 441
 442                if (!(inw(base + 0x02) & (1 << port->channel)))
 443                        continue;
 444
 445                pr_dbg("txing %d bytes, port%d.\n", txcount,
 446                        port->channel + 1);
 447                outw((port->channel << isi_card[card].shift_count) | txcount,
 448                        base);
 449                residue = NO;
 450                wrd = 0;
 451                while (1) {
 452                        cnt = min_t(int, txcount, (SERIAL_XMIT_SIZE
 453                                        - port->xmit_tail));
 454                        if (residue == YES) {
 455                                residue = NO;
 456                                if (cnt > 0) {
 457                                        wrd |= (port->port.xmit_buf[port->xmit_tail]
 458                                                                        << 8);
 459                                        port->xmit_tail = (port->xmit_tail + 1)
 460                                                & (SERIAL_XMIT_SIZE - 1);
 461                                        port->xmit_cnt--;
 462                                        txcount--;
 463                                        cnt--;
 464                                        outw(wrd, base);
 465                                } else {
 466                                        outw(wrd, base);
 467                                        break;
 468                                }
 469                        }
 470                        if (cnt <= 0)
 471                                break;
 472                        word_count = cnt >> 1;
 473                        outsw(base, port->port.xmit_buf+port->xmit_tail, word_count);
 474                        port->xmit_tail = (port->xmit_tail
 475                                + (word_count << 1)) & (SERIAL_XMIT_SIZE - 1);
 476                        txcount -= (word_count << 1);
 477                        port->xmit_cnt -= (word_count << 1);
 478                        if (cnt & 0x0001) {
 479                                residue = YES;
 480                                wrd = port->port.xmit_buf[port->xmit_tail];
 481                                port->xmit_tail = (port->xmit_tail + 1)
 482                                        & (SERIAL_XMIT_SIZE - 1);
 483                                port->xmit_cnt--;
 484                                txcount--;
 485                        }
 486                }
 487
 488                InterruptTheCard(base);
 489                if (port->xmit_cnt <= 0)
 490                        port->status &= ~ISI_TXOK;
 491                if (port->xmit_cnt <= WAKEUP_CHARS)
 492                        tty_wakeup(tty);
 493        }
 494
 495put_unlock:
 496        tty_kref_put(tty);
 497unlock:
 498        spin_unlock_irqrestore(&isi_card[card].card_lock, flags);
 499        /*      schedule another tx for hopefully in about 10ms */
 500sched_again:
 501        mod_timer(&tx, jiffies + msecs_to_jiffies(10));
 502}
 503
 504/*
 505 *      Main interrupt handler routine
 506 */
 507
 508static irqreturn_t isicom_interrupt(int irq, void *dev_id)
 509{
 510        struct isi_board *card = dev_id;
 511        struct isi_port *port;
 512        struct tty_struct *tty;
 513        unsigned long base;
 514        u16 header, word_count, count, channel;
 515        short byte_count;
 516        unsigned char *rp;
 517
 518        if (!card || !(card->status & FIRMWARE_LOADED))
 519                return IRQ_NONE;
 520
 521        base = card->base;
 522
 523        /* did the card interrupt us? */
 524        if (!(inw(base + 0x0e) & 0x02))
 525                return IRQ_NONE;
 526
 527        spin_lock(&card->card_lock);
 528
 529        /*
 530         * disable any interrupts from the PCI card and lower the
 531         * interrupt line
 532         */
 533        outw(0x8000, base+0x04);
 534        ClearInterrupt(base);
 535
 536        inw(base);              /* get the dummy word out */
 537        header = inw(base);
 538        channel = (header & 0x7800) >> card->shift_count;
 539        byte_count = header & 0xff;
 540
 541        if (channel + 1 > card->port_count) {
 542                printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%lx): "
 543                        "%d(channel) > port_count.\n", base, channel+1);
 544                outw(0x0000, base+0x04); /* enable interrupts */
 545                spin_unlock(&card->card_lock);
 546                return IRQ_HANDLED;
 547        }
 548        port = card->ports + channel;
 549        if (!(port->port.flags & ASYNC_INITIALIZED)) {
 550                outw(0x0000, base+0x04); /* enable interrupts */
 551                spin_unlock(&card->card_lock);
 552                return IRQ_HANDLED;
 553        }
 554
 555        tty = tty_port_tty_get(&port->port);
 556        if (tty == NULL) {
 557                word_count = byte_count >> 1;
 558                while (byte_count > 1) {
 559                        inw(base);
 560                        byte_count -= 2;
 561                }
 562                if (byte_count & 0x01)
 563                        inw(base);
 564                outw(0x0000, base+0x04); /* enable interrupts */
 565                spin_unlock(&card->card_lock);
 566                return IRQ_HANDLED;
 567        }
 568
 569        if (header & 0x8000) {          /* Status Packet */
 570                header = inw(base);
 571                switch (header & 0xff) {
 572                case 0: /* Change in EIA signals */
 573                        if (port->port.flags & ASYNC_CHECK_CD) {
 574                                if (port->status & ISI_DCD) {
 575                                        if (!(header & ISI_DCD)) {
 576                                        /* Carrier has been lost  */
 577                                                pr_dbg("interrupt: DCD->low.\n"
 578                                                        );
 579                                                port->status &= ~ISI_DCD;
 580                                                tty_hangup(tty);
 581                                        }
 582                                } else if (header & ISI_DCD) {
 583                                /* Carrier has been detected */
 584                                        pr_dbg("interrupt: DCD->high.\n");
 585                                        port->status |= ISI_DCD;
 586                                        wake_up_interruptible(&port->port.open_wait);
 587                                }
 588                        } else {
 589                                if (header & ISI_DCD)
 590                                        port->status |= ISI_DCD;
 591                                else
 592                                        port->status &= ~ISI_DCD;
 593                        }
 594
 595                        if (port->port.flags & ASYNC_CTS_FLOW) {
 596                                if (tty->hw_stopped) {
 597                                        if (header & ISI_CTS) {
 598                                                port->port.tty->hw_stopped = 0;
 599                                                /* start tx ing */
 600                                                port->status |= (ISI_TXOK
 601                                                        | ISI_CTS);
 602                                                tty_wakeup(tty);
 603                                        }
 604                                } else if (!(header & ISI_CTS)) {
 605                                        tty->hw_stopped = 1;
 606                                        /* stop tx ing */
 607                                        port->status &= ~(ISI_TXOK | ISI_CTS);
 608                                }
 609                        } else {
 610                                if (header & ISI_CTS)
 611                                        port->status |= ISI_CTS;
 612                                else
 613                                        port->status &= ~ISI_CTS;
 614                        }
 615
 616                        if (header & ISI_DSR)
 617                                port->status |= ISI_DSR;
 618                        else
 619                                port->status &= ~ISI_DSR;
 620
 621                        if (header & ISI_RI)
 622                                port->status |= ISI_RI;
 623                        else
 624                                port->status &= ~ISI_RI;
 625
 626                        break;
 627
 628                case 1: /* Received Break !!! */
 629                        tty_insert_flip_char(tty, 0, TTY_BREAK);
 630                        if (port->port.flags & ASYNC_SAK)
 631                                do_SAK(tty);
 632                        tty_flip_buffer_push(tty);
 633                        break;
 634
 635                case 2: /* Statistics            */
 636                        pr_dbg("isicom_interrupt: stats!!!.\n");
 637                        break;
 638
 639                default:
 640                        pr_dbg("Intr: Unknown code in status packet.\n");
 641                        break;
 642                }
 643        } else {                                /* Data   Packet */
 644
 645                count = tty_prepare_flip_string(tty, &rp, byte_count & ~1);
 646                pr_dbg("Intr: Can rx %d of %d bytes.\n", count, byte_count);
 647                word_count = count >> 1;
 648                insw(base, rp, word_count);
 649                byte_count -= (word_count << 1);
 650                if (count & 0x0001) {
 651                        tty_insert_flip_char(tty,  inw(base) & 0xff,
 652                                TTY_NORMAL);
 653                        byte_count -= 2;
 654                }
 655                if (byte_count > 0) {
 656                        pr_dbg("Intr(0x%lx:%d): Flip buffer overflow! dropping "
 657                                "bytes...\n", base, channel + 1);
 658                /* drain out unread xtra data */
 659                while (byte_count > 0) {
 660                                inw(base);
 661                                byte_count -= 2;
 662                        }
 663                }
 664                tty_flip_buffer_push(tty);
 665        }
 666        outw(0x0000, base+0x04); /* enable interrupts */
 667        spin_unlock(&card->card_lock);
 668        tty_kref_put(tty);
 669
 670        return IRQ_HANDLED;
 671}
 672
 673static void isicom_config_port(struct tty_struct *tty)
 674{
 675        struct isi_port *port = tty->driver_data;
 676        struct isi_board *card = port->card;
 677        unsigned long baud;
 678        unsigned long base = card->base;
 679        u16 channel_setup, channel = port->channel,
 680                shift_count = card->shift_count;
 681        unsigned char flow_ctrl;
 682
 683        /* FIXME: Switch to new tty baud API */
 684        baud = C_BAUD(tty);
 685        if (baud & CBAUDEX) {
 686                baud &= ~CBAUDEX;
 687
 688                /*  if CBAUDEX bit is on and the baud is set to either 50 or 75
 689                 *  then the card is programmed for 57.6Kbps or 115Kbps
 690                 *  respectively.
 691                 */
 692
 693                /* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */
 694                if (baud < 1 || baud > 4)
 695                        tty->termios->c_cflag &= ~CBAUDEX;
 696                else
 697                        baud += 15;
 698        }
 699        if (baud == 15) {
 700
 701                /*  the ASYNC_SPD_HI and ASYNC_SPD_VHI options are set
 702                 *  by the set_serial_info ioctl ... this is done by
 703                 *  the 'setserial' utility.
 704                 */
 705
 706                if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
 707                        baud++; /*  57.6 Kbps */
 708                if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
 709                        baud += 2; /*  115  Kbps */
 710                if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
 711                        baud += 3; /* 230 kbps*/
 712                if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
 713                        baud += 4; /* 460 kbps*/
 714        }
 715        if (linuxb_to_isib[baud] == -1) {
 716                /* hang up */
 717                drop_dtr(port);
 718                return;
 719        } else
 720                raise_dtr(port);
 721
 722        if (WaitTillCardIsFree(base) == 0) {
 723                outw(0x8000 | (channel << shift_count) | 0x03, base);
 724                outw(linuxb_to_isib[baud] << 8 | 0x03, base);
 725                channel_setup = 0;
 726                switch (C_CSIZE(tty)) {
 727                case CS5:
 728                        channel_setup |= ISICOM_CS5;
 729                        break;
 730                case CS6:
 731                        channel_setup |= ISICOM_CS6;
 732                        break;
 733                case CS7:
 734                        channel_setup |= ISICOM_CS7;
 735                        break;
 736                case CS8:
 737                        channel_setup |= ISICOM_CS8;
 738                        break;
 739                }
 740
 741                if (C_CSTOPB(tty))
 742                        channel_setup |= ISICOM_2SB;
 743                if (C_PARENB(tty)) {
 744                        channel_setup |= ISICOM_EVPAR;
 745                        if (C_PARODD(tty))
 746                                channel_setup |= ISICOM_ODPAR;
 747                }
 748                outw(channel_setup, base);
 749                InterruptTheCard(base);
 750        }
 751        if (C_CLOCAL(tty))
 752                port->port.flags &= ~ASYNC_CHECK_CD;
 753        else
 754                port->port.flags |= ASYNC_CHECK_CD;
 755
 756        /* flow control settings ...*/
 757        flow_ctrl = 0;
 758        port->port.flags &= ~ASYNC_CTS_FLOW;
 759        if (C_CRTSCTS(tty)) {
 760                port->port.flags |= ASYNC_CTS_FLOW;
 761                flow_ctrl |= ISICOM_CTSRTS;
 762        }
 763        if (I_IXON(tty))
 764                flow_ctrl |= ISICOM_RESPOND_XONXOFF;
 765        if (I_IXOFF(tty))
 766                flow_ctrl |= ISICOM_INITIATE_XONXOFF;
 767
 768        if (WaitTillCardIsFree(base) == 0) {
 769                outw(0x8000 | (channel << shift_count) | 0x04, base);
 770                outw(flow_ctrl << 8 | 0x05, base);
 771                outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base);
 772                InterruptTheCard(base);
 773        }
 774
 775        /*      rx enabled -> enable port for rx on the card    */
 776        if (C_CREAD(tty)) {
 777                card->port_status |= (1 << channel);
 778                outw(card->port_status, base + 0x02);
 779        }
 780}
 781
 782/* open et all */
 783
 784static inline void isicom_setup_board(struct isi_board *bp)
 785{
 786        int channel;
 787        struct isi_port *port;
 788        unsigned long flags;
 789
 790        spin_lock_irqsave(&bp->card_lock, flags);
 791        if (bp->status & BOARD_ACTIVE) {
 792                spin_unlock_irqrestore(&bp->card_lock, flags);
 793                return;
 794        }
 795        port = bp->ports;
 796        bp->status |= BOARD_ACTIVE;
 797        for (channel = 0; channel < bp->port_count; channel++, port++)
 798                drop_dtr_rts(port);
 799        spin_unlock_irqrestore(&bp->card_lock, flags);
 800}
 801
 802static int isicom_setup_port(struct tty_struct *tty)
 803{
 804        struct isi_port *port = tty->driver_data;
 805        struct isi_board *card = port->card;
 806        unsigned long flags;
 807
 808        if (port->port.flags & ASYNC_INITIALIZED)
 809                return 0;
 810        if (tty_port_alloc_xmit_buf(&port->port) < 0)
 811                return -ENOMEM;
 812
 813        spin_lock_irqsave(&card->card_lock, flags);
 814        clear_bit(TTY_IO_ERROR, &tty->flags);
 815        if (port->port.count == 1)
 816                card->count++;
 817
 818        port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
 819
 820        /*      discard any residual data       */
 821        if (WaitTillCardIsFree(card->base) == 0) {
 822                outw(0x8000 | (port->channel << card->shift_count) | 0x02,
 823                                card->base);
 824                outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base);
 825                InterruptTheCard(card->base);
 826        }
 827
 828        isicom_config_port(tty);
 829        port->port.flags |= ASYNC_INITIALIZED;
 830        spin_unlock_irqrestore(&card->card_lock, flags);
 831
 832        return 0;
 833}
 834
 835static int isicom_carrier_raised(struct tty_port *port)
 836{
 837        struct isi_port *ip = container_of(port, struct isi_port, port);
 838        return (ip->status & ISI_DCD)?1 : 0;
 839}
 840
 841static int isicom_open(struct tty_struct *tty, struct file *filp)
 842{
 843        struct isi_port *port;
 844        struct isi_board *card;
 845        unsigned int board;
 846        int error, line;
 847
 848        line = tty->index;
 849        if (line < 0 || line > PORT_COUNT-1)
 850                return -ENODEV;
 851        board = BOARD(line);
 852        card = &isi_card[board];
 853
 854        if (!(card->status & FIRMWARE_LOADED))
 855                return -ENODEV;
 856
 857        /*  open on a port greater than the port count for the card !!! */
 858        if (line > ((board * 16) + card->port_count - 1))
 859                return -ENODEV;
 860
 861        port = &isi_ports[line];
 862        if (isicom_paranoia_check(port, tty->name, "isicom_open"))
 863                return -ENODEV;
 864
 865        isicom_setup_board(card);
 866
 867        /* FIXME: locking on port.count etc */
 868        port->port.count++;
 869        tty->driver_data = port;
 870        tty_port_tty_set(&port->port, tty);
 871        error = isicom_setup_port(tty);
 872        if (error == 0)
 873                error = tty_port_block_til_ready(&port->port, tty, filp);
 874        return error;
 875}
 876
 877/* close et all */
 878
 879static inline void isicom_shutdown_board(struct isi_board *bp)
 880{
 881        if (bp->status & BOARD_ACTIVE)
 882                bp->status &= ~BOARD_ACTIVE;
 883}
 884
 885/* card->lock HAS to be held */
 886static void isicom_shutdown_port(struct isi_port *port)
 887{
 888        struct isi_board *card = port->card;
 889        struct tty_struct *tty;
 890
 891        tty = tty_port_tty_get(&port->port);
 892
 893        if (!(port->port.flags & ASYNC_INITIALIZED)) {
 894                tty_kref_put(tty);
 895                return;
 896        }
 897
 898        tty_port_free_xmit_buf(&port->port);
 899        port->port.flags &= ~ASYNC_INITIALIZED;
 900        /* 3rd October 2000 : Vinayak P Risbud */
 901        tty_port_tty_set(&port->port, NULL);
 902
 903        /*Fix done by Anil .S on 30-04-2001
 904        remote login through isi port has dtr toggle problem
 905        due to which the carrier drops before the password prompt
 906        appears on the remote end. Now we drop the dtr only if the
 907        HUPCL(Hangup on close) flag is set for the tty*/
 908
 909        if (C_HUPCL(tty))
 910                /* drop dtr on this port */
 911                drop_dtr(port);
 912
 913        /* any other port uninits  */
 914        if (tty)
 915                set_bit(TTY_IO_ERROR, &tty->flags);
 916
 917        if (--card->count < 0) {
 918                pr_dbg("isicom_shutdown_port: bad board(0x%lx) count %d.\n",
 919                        card->base, card->count);
 920                card->count = 0;
 921        }
 922
 923        /* last port was closed, shutdown that boad too */
 924        if (C_HUPCL(tty)) {
 925                if (!card->count)
 926                        isicom_shutdown_board(card);
 927        }
 928        tty_kref_put(tty);
 929}
 930
 931static void isicom_flush_buffer(struct tty_struct *tty)
 932{
 933        struct isi_port *port = tty->driver_data;
 934        struct isi_board *card = port->card;
 935        unsigned long flags;
 936
 937        if (isicom_paranoia_check(port, tty->name, "isicom_flush_buffer"))
 938                return;
 939
 940        spin_lock_irqsave(&card->card_lock, flags);
 941        port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
 942        spin_unlock_irqrestore(&card->card_lock, flags);
 943
 944        tty_wakeup(tty);
 945}
 946
 947static void isicom_close(struct tty_struct *tty, struct file *filp)
 948{
 949        struct isi_port *ip = tty->driver_data;
 950        struct tty_port *port = &ip->port;
 951        struct isi_board *card;
 952        unsigned long flags;
 953
 954        BUG_ON(!ip);
 955
 956        card = ip->card;
 957        if (isicom_paranoia_check(ip, tty->name, "isicom_close"))
 958                return;
 959
 960        /* indicate to the card that no more data can be received
 961           on this port */
 962        spin_lock_irqsave(&card->card_lock, flags);
 963        if (port->flags & ASYNC_INITIALIZED) {
 964                card->port_status &= ~(1 << ip->channel);
 965                outw(card->port_status, card->base + 0x02);
 966        }
 967        isicom_shutdown_port(ip);
 968        spin_unlock_irqrestore(&card->card_lock, flags);
 969
 970        isicom_flush_buffer(tty);
 971        
 972        tty_port_close_end(port, tty);
 973}
 974
 975/* write et all */
 976static int isicom_write(struct tty_struct *tty, const unsigned char *buf,
 977        int count)
 978{
 979        struct isi_port *port = tty->driver_data;
 980        struct isi_board *card = port->card;
 981        unsigned long flags;
 982        int cnt, total = 0;
 983
 984        if (isicom_paranoia_check(port, tty->name, "isicom_write"))
 985                return 0;
 986
 987        spin_lock_irqsave(&card->card_lock, flags);
 988
 989        while (1) {
 990                cnt = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt
 991                                - 1, SERIAL_XMIT_SIZE - port->xmit_head));
 992                if (cnt <= 0)
 993                        break;
 994
 995                memcpy(port->port.xmit_buf + port->xmit_head, buf, cnt);
 996                port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE
 997                        - 1);
 998                port->xmit_cnt += cnt;
 999                buf += cnt;
1000                count -= cnt;
1001                total += cnt;
1002        }
1003        if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped)
1004                port->status |= ISI_TXOK;
1005        spin_unlock_irqrestore(&card->card_lock, flags);
1006        return total;
1007}
1008
1009/* put_char et all */
1010static int isicom_put_char(struct tty_struct *tty, unsigned char ch)
1011{
1012        struct isi_port *port = tty->driver_data;
1013        struct isi_board *card = port->card;
1014        unsigned long flags;
1015
1016        if (isicom_paranoia_check(port, tty->name, "isicom_put_char"))
1017                return 0;
1018
1019        spin_lock_irqsave(&card->card_lock, flags);
1020        if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
1021                spin_unlock_irqrestore(&card->card_lock, flags);
1022                return 0;
1023        }
1024
1025        port->port.xmit_buf[port->xmit_head++] = ch;
1026        port->xmit_head &= (SERIAL_XMIT_SIZE - 1);
1027        port->xmit_cnt++;
1028        spin_unlock_irqrestore(&card->card_lock, flags);
1029        return 1;
1030}
1031
1032/* flush_chars et all */
1033static void isicom_flush_chars(struct tty_struct *tty)
1034{
1035        struct isi_port *port = tty->driver_data;
1036
1037        if (isicom_paranoia_check(port, tty->name, "isicom_flush_chars"))
1038                return;
1039
1040        if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
1041                        !port->port.xmit_buf)
1042                return;
1043
1044        /* this tells the transmitter to consider this port for
1045           data output to the card ... that's the best we can do. */
1046        port->status |= ISI_TXOK;
1047}
1048
1049/* write_room et all */
1050static int isicom_write_room(struct tty_struct *tty)
1051{
1052        struct isi_port *port = tty->driver_data;
1053        int free;
1054
1055        if (isicom_paranoia_check(port, tty->name, "isicom_write_room"))
1056                return 0;
1057
1058        free = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
1059        if (free < 0)
1060                free = 0;
1061        return free;
1062}
1063
1064/* chars_in_buffer et all */
1065static int isicom_chars_in_buffer(struct tty_struct *tty)
1066{
1067        struct isi_port *port = tty->driver_data;
1068        if (isicom_paranoia_check(port, tty->name, "isicom_chars_in_buffer"))
1069                return 0;
1070        return port->xmit_cnt;
1071}
1072
1073/* ioctl et all */
1074static int isicom_send_break(struct tty_struct *tty, int length)
1075{
1076        struct isi_port *port = tty->driver_data;
1077        struct isi_board *card = port->card;
1078        unsigned long base = card->base;
1079
1080        if (length == -1)
1081                return -EOPNOTSUPP;
1082
1083        if (!lock_card(card))
1084                return -EINVAL;
1085
1086        outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base);
1087        outw((length & 0xff) << 8 | 0x00, base);
1088        outw((length & 0xff00), base);
1089        InterruptTheCard(base);
1090
1091        unlock_card(card);
1092        return 0;
1093}
1094
1095static int isicom_tiocmget(struct tty_struct *tty, struct file *file)
1096{
1097        struct isi_port *port = tty->driver_data;
1098        /* just send the port status */
1099        u16 status = port->status;
1100
1101        if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
1102                return -ENODEV;
1103
1104        return  ((status & ISI_RTS) ? TIOCM_RTS : 0) |
1105                ((status & ISI_DTR) ? TIOCM_DTR : 0) |
1106                ((status & ISI_DCD) ? TIOCM_CAR : 0) |
1107                ((status & ISI_DSR) ? TIOCM_DSR : 0) |
1108                ((status & ISI_CTS) ? TIOCM_CTS : 0) |
1109                ((status & ISI_RI ) ? TIOCM_RI  : 0);
1110}
1111
1112static int isicom_tiocmset(struct tty_struct *tty, struct file *file,
1113        unsigned int set, unsigned int clear)
1114{
1115        struct isi_port *port = tty->driver_data;
1116        unsigned long flags;
1117
1118        if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
1119                return -ENODEV;
1120
1121        spin_lock_irqsave(&port->card->card_lock, flags);
1122        if (set & TIOCM_RTS)
1123                raise_rts(port);
1124        if (set & TIOCM_DTR)
1125                raise_dtr(port);
1126
1127        if (clear & TIOCM_RTS)
1128                drop_rts(port);
1129        if (clear & TIOCM_DTR)
1130                drop_dtr(port);
1131        spin_unlock_irqrestore(&port->card->card_lock, flags);
1132
1133        return 0;
1134}
1135
1136static int isicom_set_serial_info(struct tty_struct *tty,
1137                                        struct serial_struct __user *info)
1138{
1139        struct isi_port *port = tty->driver_data;
1140        struct serial_struct newinfo;
1141        int reconfig_port;
1142
1143        if (copy_from_user(&newinfo, info, sizeof(newinfo)))
1144                return -EFAULT;
1145
1146        lock_kernel();
1147
1148        reconfig_port = ((port->port.flags & ASYNC_SPD_MASK) !=
1149                (newinfo.flags & ASYNC_SPD_MASK));
1150
1151        if (!capable(CAP_SYS_ADMIN)) {
1152                if ((newinfo.close_delay != port->port.close_delay) ||
1153                                (newinfo.closing_wait != port->port.closing_wait) ||
1154                                ((newinfo.flags & ~ASYNC_USR_MASK) !=
1155                                (port->port.flags & ~ASYNC_USR_MASK))) {
1156                        unlock_kernel();
1157                        return -EPERM;
1158                }
1159                port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) |
1160                                (newinfo.flags & ASYNC_USR_MASK));
1161        } else {
1162                port->port.close_delay = newinfo.close_delay;
1163                port->port.closing_wait = newinfo.closing_wait;
1164                port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) |
1165                                (newinfo.flags & ASYNC_FLAGS));
1166        }
1167        if (reconfig_port) {
1168                unsigned long flags;
1169                spin_lock_irqsave(&port->card->card_lock, flags);
1170                isicom_config_port(tty);
1171                spin_unlock_irqrestore(&port->card->card_lock, flags);
1172        }
1173        unlock_kernel();
1174        return 0;
1175}
1176
1177static int isicom_get_serial_info(struct isi_port *port,
1178        struct serial_struct __user *info)
1179{
1180        struct serial_struct out_info;
1181
1182        lock_kernel();
1183        memset(&out_info, 0, sizeof(out_info));
1184/*      out_info.type = ? */
1185        out_info.line = port - isi_ports;
1186        out_info.port = port->card->base;
1187        out_info.irq = port->card->irq;
1188        out_info.flags = port->port.flags;
1189/*      out_info.baud_base = ? */
1190        out_info.close_delay = port->port.close_delay;
1191        out_info.closing_wait = port->port.closing_wait;
1192        unlock_kernel();
1193        if (copy_to_user(info, &out_info, sizeof(out_info)))
1194                return -EFAULT;
1195        return 0;
1196}
1197
1198static int isicom_ioctl(struct tty_struct *tty, struct file *filp,
1199        unsigned int cmd, unsigned long arg)
1200{
1201        struct isi_port *port = tty->driver_data;
1202        void __user *argp = (void __user *)arg;
1203
1204        if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
1205                return -ENODEV;
1206
1207        switch (cmd) {
1208        case TIOCGSERIAL:
1209                return isicom_get_serial_info(port, argp);
1210
1211        case TIOCSSERIAL:
1212                return isicom_set_serial_info(tty, argp);
1213
1214        default:
1215                return -ENOIOCTLCMD;
1216        }
1217        return 0;
1218}
1219
1220/* set_termios et all */
1221static void isicom_set_termios(struct tty_struct *tty,
1222        struct ktermios *old_termios)
1223{
1224        struct isi_port *port = tty->driver_data;
1225        unsigned long flags;
1226
1227        if (isicom_paranoia_check(port, tty->name, "isicom_set_termios"))
1228                return;
1229
1230        if (tty->termios->c_cflag == old_termios->c_cflag &&
1231                        tty->termios->c_iflag == old_termios->c_iflag)
1232                return;
1233
1234        spin_lock_irqsave(&port->card->card_lock, flags);
1235        isicom_config_port(tty);
1236        spin_unlock_irqrestore(&port->card->card_lock, flags);
1237
1238        if ((old_termios->c_cflag & CRTSCTS) &&
1239                        !(tty->termios->c_cflag & CRTSCTS)) {
1240                tty->hw_stopped = 0;
1241                isicom_start(tty);
1242        }
1243}
1244
1245/* throttle et all */
1246static void isicom_throttle(struct tty_struct *tty)
1247{
1248        struct isi_port *port = tty->driver_data;
1249        struct isi_board *card = port->card;
1250
1251        if (isicom_paranoia_check(port, tty->name, "isicom_throttle"))
1252                return;
1253
1254        /* tell the card that this port cannot handle any more data for now */
1255        card->port_status &= ~(1 << port->channel);
1256        outw(card->port_status, card->base + 0x02);
1257}
1258
1259/* unthrottle et all */
1260static void isicom_unthrottle(struct tty_struct *tty)
1261{
1262        struct isi_port *port = tty->driver_data;
1263        struct isi_board *card = port->card;
1264
1265        if (isicom_paranoia_check(port, tty->name, "isicom_unthrottle"))
1266                return;
1267
1268        /* tell the card that this port is ready to accept more data */
1269        card->port_status |= (1 << port->channel);
1270        outw(card->port_status, card->base + 0x02);
1271}
1272
1273/* stop et all */
1274static void isicom_stop(struct tty_struct *tty)
1275{
1276        struct isi_port *port = tty->driver_data;
1277
1278        if (isicom_paranoia_check(port, tty->name, "isicom_stop"))
1279                return;
1280
1281        /* this tells the transmitter not to consider this port for
1282           data output to the card. */
1283        port->status &= ~ISI_TXOK;
1284}
1285
1286/* start et all */
1287static void isicom_start(struct tty_struct *tty)
1288{
1289        struct isi_port *port = tty->driver_data;
1290
1291        if (isicom_paranoia_check(port, tty->name, "isicom_start"))
1292                return;
1293
1294        /* this tells the transmitter to consider this port for
1295           data output to the card. */
1296        port->status |= ISI_TXOK;
1297}
1298
1299static void isicom_hangup(struct tty_struct *tty)
1300{
1301        struct isi_port *port = tty->driver_data;
1302        unsigned long flags;
1303
1304        if (isicom_paranoia_check(port, tty->name, "isicom_hangup"))
1305                return;
1306
1307        spin_lock_irqsave(&port->card->card_lock, flags);
1308        isicom_shutdown_port(port);
1309        spin_unlock_irqrestore(&port->card->card_lock, flags);
1310
1311        tty_port_hangup(&port->port);
1312}
1313
1314
1315/*
1316 * Driver init and deinit functions
1317 */
1318
1319static const struct tty_operations isicom_ops = {
1320        .open                   = isicom_open,
1321        .close                  = isicom_close,
1322        .write                  = isicom_write,
1323        .put_char               = isicom_put_char,
1324        .flush_chars            = isicom_flush_chars,
1325        .write_room             = isicom_write_room,
1326        .chars_in_buffer        = isicom_chars_in_buffer,
1327        .ioctl                  = isicom_ioctl,
1328        .set_termios            = isicom_set_termios,
1329        .throttle               = isicom_throttle,
1330        .unthrottle             = isicom_unthrottle,
1331        .stop                   = isicom_stop,
1332        .start                  = isicom_start,
1333        .hangup                 = isicom_hangup,
1334        .flush_buffer           = isicom_flush_buffer,
1335        .tiocmget               = isicom_tiocmget,
1336        .tiocmset               = isicom_tiocmset,
1337        .break_ctl              = isicom_send_break,
1338};
1339
1340static const struct tty_port_operations isicom_port_ops = {
1341        .carrier_raised         = isicom_carrier_raised,
1342        .raise_dtr_rts          = isicom_raise_dtr_rts,
1343};
1344
1345static int __devinit reset_card(struct pci_dev *pdev,
1346        const unsigned int card, unsigned int *signature)
1347{
1348        struct isi_board *board = pci_get_drvdata(pdev);
1349        unsigned long base = board->base;
1350        unsigned int sig, portcount = 0;
1351        int retval = 0;
1352
1353        dev_dbg(&pdev->dev, "ISILoad:Resetting Card%d at 0x%lx\n", card + 1,
1354                base);
1355
1356        inw(base + 0x8);
1357
1358        msleep(10);
1359
1360        outw(0, base + 0x8); /* Reset */
1361
1362        msleep(1000);
1363
1364        sig = inw(base + 0x4) & 0xff;
1365
1366        if (sig != 0xa5 && sig != 0xbb && sig != 0xcc && sig != 0xdd &&
1367                        sig != 0xee) {
1368                dev_warn(&pdev->dev, "ISILoad:Card%u reset failure (Possible "
1369                        "bad I/O Port Address 0x%lx).\n", card + 1, base);
1370                dev_dbg(&pdev->dev, "Sig=0x%x\n", sig);
1371                retval = -EIO;
1372                goto end;
1373        }
1374
1375        msleep(10);
1376
1377        portcount = inw(base + 0x2);
1378        if (!(inw(base + 0xe) & 0x1) || (portcount != 0 && portcount != 4 &&
1379                                portcount != 8 && portcount != 16)) {
1380                dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure.\n",
1381                        card + 1);
1382                retval = -EIO;
1383                goto end;
1384        }
1385
1386        switch (sig) {
1387        case 0xa5:
1388        case 0xbb:
1389        case 0xdd:
1390                board->port_count = (portcount == 4) ? 4 : 8;
1391                board->shift_count = 12;
1392                break;
1393        case 0xcc:
1394        case 0xee:
1395                board->port_count = 16;
1396                board->shift_count = 11;
1397                break;
1398        }
1399        dev_info(&pdev->dev, "-Done\n");
1400        *signature = sig;
1401
1402end:
1403        return retval;
1404}
1405
1406static int __devinit load_firmware(struct pci_dev *pdev,
1407        const unsigned int index, const unsigned int signature)
1408{
1409        struct isi_board *board = pci_get_drvdata(pdev);
1410        const struct firmware *fw;
1411        unsigned long base = board->base;
1412        unsigned int a;
1413        u16 word_count, status;
1414        int retval = -EIO;
1415        char *name;
1416        u8 *data;
1417
1418        struct stframe {
1419                u16     addr;
1420                u16     count;
1421                u8      data[0];
1422        } *frame;
1423
1424        switch (signature) {
1425        case 0xa5:
1426                name = "isi608.bin";
1427                break;
1428        case 0xbb:
1429                name = "isi608em.bin";
1430                break;
1431        case 0xcc:
1432                name = "isi616em.bin";
1433                break;
1434        case 0xdd:
1435                name = "isi4608.bin";
1436                break;
1437        case 0xee:
1438                name = "isi4616.bin";
1439                break;
1440        default:
1441                dev_err(&pdev->dev, "Unknown signature.\n");
1442                goto end;
1443        }
1444
1445        retval = request_firmware(&fw, name, &pdev->dev);
1446        if (retval)
1447                goto end;
1448
1449        retval = -EIO;
1450
1451        for (frame = (struct stframe *)fw->data;
1452                        frame < (struct stframe *)(fw->data + fw->size);
1453                        frame = (struct stframe *)((u8 *)(frame + 1) +
1454                                frame->count)) {
1455                if (WaitTillCardIsFree(base))
1456                        goto errrelfw;
1457
1458                outw(0xf0, base);       /* start upload sequence */
1459                outw(0x00, base);
1460                outw(frame->addr, base); /* lsb of address */
1461
1462                word_count = frame->count / 2 + frame->count % 2;
1463                outw(word_count, base);
1464                InterruptTheCard(base);
1465
1466                udelay(100); /* 0x2f */
1467
1468                if (WaitTillCardIsFree(base))
1469                        goto errrelfw;
1470
1471                status = inw(base + 0x4);
1472                if (status != 0) {
1473                        dev_warn(&pdev->dev, "Card%d rejected load header:\n"
1474                                KERN_WARNING "Address:0x%x\n"
1475                                KERN_WARNING "Count:0x%x\n"
1476                                KERN_WARNING "Status:0x%x\n",
1477                                index + 1, frame->addr, frame->count, status);
1478                        goto errrelfw;
1479                }
1480                outsw(base, frame->data, word_count);
1481
1482                InterruptTheCard(base);
1483
1484                udelay(50); /* 0x0f */
1485
1486                if (WaitTillCardIsFree(base))
1487                        goto errrelfw;
1488
1489                status = inw(base + 0x4);
1490                if (status != 0) {
1491                        dev_err(&pdev->dev, "Card%d got out of sync.Card "
1492                                "Status:0x%x\n", index + 1, status);
1493                        goto errrelfw;
1494                }
1495        }
1496
1497/* XXX: should we test it by reading it back and comparing with original like
1498 * in load firmware package? */
1499        for (frame = (struct stframe *)fw->data;
1500                        frame < (struct stframe *)(fw->data + fw->size);
1501                        frame = (struct stframe *)((u8 *)(frame + 1) +
1502                                frame->count)) {
1503                if (WaitTillCardIsFree(base))
1504                        goto errrelfw;
1505
1506                outw(0xf1, base); /* start download sequence */
1507                outw(0x00, base);
1508                outw(frame->addr, base); /* lsb of address */
1509
1510                word_count = (frame->count >> 1) + frame->count % 2;
1511                outw(word_count + 1, base);
1512                InterruptTheCard(base);
1513
1514                udelay(50); /* 0xf */
1515
1516                if (WaitTillCardIsFree(base))
1517                        goto errrelfw;
1518
1519                status = inw(base + 0x4);
1520                if (status != 0) {
1521                        dev_warn(&pdev->dev, "Card%d rejected verify header:\n"
1522                                KERN_WARNING "Address:0x%x\n"
1523                                KERN_WARNING "Count:0x%x\n"
1524                                KERN_WARNING "Status: 0x%x\n",
1525                                index + 1, frame->addr, frame->count, status);
1526                        goto errrelfw;
1527                }
1528
1529                data = kmalloc(word_count * 2, GFP_KERNEL);
1530                if (data == NULL) {
1531                        dev_err(&pdev->dev, "Card%d, firmware upload "
1532                                "failed, not enough memory\n", index + 1);
1533                        goto errrelfw;
1534                }
1535                inw(base);
1536                insw(base, data, word_count);
1537                InterruptTheCard(base);
1538
1539                for (a = 0; a < frame->count; a++)
1540                        if (data[a] != frame->data[a]) {
1541                                kfree(data);
1542                                dev_err(&pdev->dev, "Card%d, firmware upload "
1543                                        "failed\n", index + 1);
1544                                goto errrelfw;
1545                        }
1546                kfree(data);
1547
1548                udelay(50); /* 0xf */
1549
1550                if (WaitTillCardIsFree(base))
1551                        goto errrelfw;
1552
1553                status = inw(base + 0x4);
1554                if (status != 0) {
1555                        dev_err(&pdev->dev, "Card%d verify got out of sync. "
1556                                "Card Status:0x%x\n", index + 1, status);
1557                        goto errrelfw;
1558                }
1559        }
1560
1561        /* xfer ctrl */
1562        if (WaitTillCardIsFree(base))
1563                goto errrelfw;
1564
1565        outw(0xf2, base);
1566        outw(0x800, base);
1567        outw(0x0, base);
1568        outw(0x0, base);
1569        InterruptTheCard(base);
1570        outw(0x0, base + 0x4); /* for ISI4608 cards */
1571
1572        board->status |= FIRMWARE_LOADED;
1573        retval = 0;
1574
1575errrelfw:
1576        release_firmware(fw);
1577end:
1578        return retval;
1579}
1580
1581/*
1582 *      Insmod can set static symbols so keep these static
1583 */
1584static unsigned int card_count;
1585
1586static int __devinit isicom_probe(struct pci_dev *pdev,
1587        const struct pci_device_id *ent)
1588{
1589        unsigned int signature, index;
1590        int retval = -EPERM;
1591        struct isi_board *board = NULL;
1592
1593        if (card_count >= BOARD_COUNT)
1594                goto err;
1595
1596        retval = pci_enable_device(pdev);
1597        if (retval) {
1598                dev_err(&pdev->dev, "failed to enable\n");
1599                goto err;
1600        }
1601
1602        dev_info(&pdev->dev, "ISI PCI Card(Device ID 0x%x)\n", ent->device);
1603
1604        /* allot the first empty slot in the array */
1605        for (index = 0; index < BOARD_COUNT; index++)
1606                if (isi_card[index].base == 0) {
1607                        board = &isi_card[index];
1608                        break;
1609                }
1610
1611        board->index = index;
1612        board->base = pci_resource_start(pdev, 3);
1613        board->irq = pdev->irq;
1614        card_count++;
1615
1616        pci_set_drvdata(pdev, board);
1617
1618        retval = pci_request_region(pdev, 3, ISICOM_NAME);
1619        if (retval) {
1620                dev_err(&pdev->dev, "I/O Region 0x%lx-0x%lx is busy. Card%d "
1621                        "will be disabled.\n", board->base, board->base + 15,
1622                        index + 1);
1623                retval = -EBUSY;
1624                goto errdec;
1625        }
1626
1627        retval = request_irq(board->irq, isicom_interrupt,
1628                        IRQF_SHARED | IRQF_DISABLED, ISICOM_NAME, board);
1629        if (retval < 0) {
1630                dev_err(&pdev->dev, "Could not install handler at Irq %d. "
1631                        "Card%d will be disabled.\n", board->irq, index + 1);
1632                goto errunrr;
1633        }
1634
1635        retval = reset_card(pdev, index, &signature);
1636        if (retval < 0)
1637                goto errunri;
1638
1639        retval = load_firmware(pdev, index, signature);
1640        if (retval < 0)
1641                goto errunri;
1642
1643        for (index = 0; index < board->port_count; index++)
1644                tty_register_device(isicom_normal, board->index * 16 + index,
1645                                &pdev->dev);
1646
1647        return 0;
1648
1649errunri:
1650        free_irq(board->irq, board);
1651errunrr:
1652        pci_release_region(pdev, 3);
1653errdec:
1654        board->base = 0;
1655        card_count--;
1656        pci_disable_device(pdev);
1657err:
1658        return retval;
1659}
1660
1661static void __devexit isicom_remove(struct pci_dev *pdev)
1662{
1663        struct isi_board *board = pci_get_drvdata(pdev);
1664        unsigned int i;
1665
1666        for (i = 0; i < board->port_count; i++)
1667                tty_unregister_device(isicom_normal, board->index * 16 + i);
1668
1669        free_irq(board->irq, board);
1670        pci_release_region(pdev, 3);
1671        board->base = 0;
1672        card_count--;
1673        pci_disable_device(pdev);
1674}
1675
1676static int __init isicom_init(void)
1677{
1678        int retval, idx, channel;
1679        struct isi_port *port;
1680
1681        for (idx = 0; idx < BOARD_COUNT; idx++) {
1682                port = &isi_ports[idx * 16];
1683                isi_card[idx].ports = port;
1684                spin_lock_init(&isi_card[idx].card_lock);
1685                for (channel = 0; channel < 16; channel++, port++) {
1686                        tty_port_init(&port->port);
1687                        port->port.ops = &isicom_port_ops;
1688                        port->magic = ISICOM_MAGIC;
1689                        port->card = &isi_card[idx];
1690                        port->channel = channel;
1691                        port->port.close_delay = 50 * HZ/100;
1692                        port->port.closing_wait = 3000 * HZ/100;
1693                        port->status = 0;
1694                        /*  . . .  */
1695                }
1696                isi_card[idx].base = 0;
1697                isi_card[idx].irq = 0;
1698        }
1699
1700        /* tty driver structure initialization */
1701        isicom_normal = alloc_tty_driver(PORT_COUNT);
1702        if (!isicom_normal) {
1703                retval = -ENOMEM;
1704                goto error;
1705        }
1706
1707        isicom_normal->owner                    = THIS_MODULE;
1708        isicom_normal->name                     = "ttyM";
1709        isicom_normal->major                    = ISICOM_NMAJOR;
1710        isicom_normal->minor_start              = 0;
1711        isicom_normal->type                     = TTY_DRIVER_TYPE_SERIAL;
1712        isicom_normal->subtype                  = SERIAL_TYPE_NORMAL;
1713        isicom_normal->init_termios             = tty_std_termios;
1714        isicom_normal->init_termios.c_cflag     = B9600 | CS8 | CREAD | HUPCL |
1715                CLOCAL;
1716        isicom_normal->flags                    = TTY_DRIVER_REAL_RAW |
1717                TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK;
1718        tty_set_operations(isicom_normal, &isicom_ops);
1719
1720        retval = tty_register_driver(isicom_normal);
1721        if (retval) {
1722                pr_dbg("Couldn't register the dialin driver\n");
1723                goto err_puttty;
1724        }
1725
1726        retval = pci_register_driver(&isicom_driver);
1727        if (retval < 0) {
1728                printk(KERN_ERR "ISICOM: Unable to register pci driver.\n");
1729                goto err_unrtty;
1730        }
1731
1732        mod_timer(&tx, jiffies + 1);
1733
1734        return 0;
1735err_unrtty:
1736        tty_unregister_driver(isicom_normal);
1737err_puttty:
1738        put_tty_driver(isicom_normal);
1739error:
1740        return retval;
1741}
1742
1743static void __exit isicom_exit(void)
1744{
1745        del_timer_sync(&tx);
1746
1747        pci_unregister_driver(&isicom_driver);
1748        tty_unregister_driver(isicom_normal);
1749        put_tty_driver(isicom_normal);
1750}
1751
1752module_init(isicom_init);
1753module_exit(isicom_exit);
1754
1755MODULE_AUTHOR("MultiTech");
1756MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech");
1757MODULE_LICENSE("GPL");
1758
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.