+struct isi_board {
+ unsigned short base;
+ unsigned char irq;
+ unsigned char port_count;
+ unsigned short status;
+ unsigned short port_status; /* each bit represents a single port */
+ unsigned short shift_count;
+ struct isi_port * ports;
+ signed char count;
+ unsigned char isa;
+ spinlock_t card_lock; /* Card wide lock 11/5/00 -sameer */
+ unsigned long flags;
+};
+
+struct isi_port {
+ unsigned short magic;
+ unsigned int flags;
+ int count;
+ int blocked_open;
+ int close_delay;
+ unsigned short channel;
+ unsigned short status;
+ unsigned short closing_wait;
+ struct isi_board * card;
+ struct tty_struct * tty;
+ wait_queue_head_t close_wait;
+ wait_queue_head_t open_wait;
+ struct work_struct hangup_tq;
+ struct work_struct bh_tqueue;
+ unsigned char * xmit_buf;
+ int xmit_head;
+ int xmit_tail;
+ int xmit_cnt;
+};
+
+/*
+ * Locking functions for card level locking. We need to own both
+ * the kernel lock for the card and have the card in a position that
+ * it wants to talk.
+ */
+
+static int lock_card(struct isi_board *card)
+{
+ char retries;
+ unsigned short base = card->base;
+
+ for (retries = 0; retries < 100; retries++) {
+ spin_lock_irqsave(&card->card_lock, card->flags);
+ if (inw(base + 0xe) & 0x1) {
+ return 1;
+ } else {
+ spin_unlock_irqrestore(&card->card_lock, card->flags);
+ udelay(1000); /* 1ms */
+ }
+ }
+ printk(KERN_WARNING "ISICOM: Failed to lock Card (0x%x)\n", card->base);
+ return 0; /* Failed to aquire the card! */
+}
+
+static int lock_card_at_interrupt(struct isi_board *card)
+{
+ unsigned char retries;
+ unsigned short base = card->base;
+
+ for (retries = 0; retries < 200; retries++) {
+ spin_lock_irqsave(&card->card_lock, card->flags);
+
+ if (inw(base + 0xe) & 0x1)
+ return 1;
+ else
+ spin_unlock_irqrestore(&card->card_lock, card->flags);
+ }
+ /* Failing in interrupt is an acceptable event */
+ return 0; /* Failed to aquire the card! */
+}
+
+static void unlock_card(struct isi_board *card)
+{
+ spin_unlock_irqrestore(&card->card_lock, card->flags);
+}
+
+/*
+ * ISI Card specific ops ...
+ */
+
+static void raise_dtr(struct isi_port * port)
+{
+ struct isi_board * card = port->card;
+ unsigned short base = card->base;
+ unsigned char channel = port->channel;
+
+ if (!lock_card(card))
+ return;
+
+ outw(0x8000 | (channel << card->shift_count) | 0x02 , base);
+ outw(0x0504, base);
+ InterruptTheCard(base);
+ port->status |= ISI_DTR;
+ unlock_card(card);
+}
+
+static inline void drop_dtr(struct isi_port * port)
+{
+ struct isi_board * card = port->card;
+ unsigned short base = card->base;
+ unsigned char channel = port->channel;
+
+ if (!lock_card(card))
+ return;
+
+ outw(0x8000 | (channel << card->shift_count) | 0x02 , base);
+ outw(0x0404, base);
+ InterruptTheCard(base);
+ port->status &= ~ISI_DTR;
+ unlock_card(card);
+}
+
+static inline void raise_rts(struct isi_port * port)
+{
+ struct isi_board * card = port->card;
+ unsigned short base = card->base;
+ unsigned char channel = port->channel;
+
+ if (!lock_card(card))
+ return;
+
+ outw(0x8000 | (channel << card->shift_count) | 0x02 , base);
+ outw(0x0a04, base);
+ InterruptTheCard(base);
+ port->status |= ISI_RTS;
+ unlock_card(card);
+}
+static inline void drop_rts(struct isi_port * port)
+{
+ struct isi_board * card = port->card;
+ unsigned short base = card->base;
+ unsigned char channel = port->channel;
+
+ if (!lock_card(card))
+ return;
+
+ outw(0x8000 | (channel << card->shift_count) | 0x02 , base);
+ outw(0x0804, base);
+ InterruptTheCard(base);
+ port->status &= ~ISI_RTS;
+ unlock_card(card);
+}
+
+static inline void raise_dtr_rts(struct isi_port * port)
+{
+ struct isi_board * card = port->card;
+ unsigned short base = card->base;
+ unsigned char channel = port->channel;
+
+ if (!lock_card(card))
+ return;
+
+ outw(0x8000 | (channel << card->shift_count) | 0x02 , base);
+ outw(0x0f04, base);
+ InterruptTheCard(base);
+ port->status |= (ISI_DTR | ISI_RTS);
+ unlock_card(card);
+}
+
+static void drop_dtr_rts(struct isi_port * port)
+{
+ struct isi_board * card = port->card;
+ unsigned short base = card->base;
+ unsigned char channel = port->channel;
+
+ if (!lock_card(card))
+ return;
+
+ outw(0x8000 | (channel << card->shift_count) | 0x02 , base);
+ outw(0x0c04, base);
+ InterruptTheCard(base);
+ port->status &= ~(ISI_RTS | ISI_DTR);
+ unlock_card(card);
+}
+
+static inline void kill_queue(struct isi_port * port, short queue)
+{
+ struct isi_board * card = port->card;
+ unsigned short base = card->base;
+ unsigned char channel = port->channel;
+
+ if (!lock_card(card))
+ return;
+
+ outw(0x8000 | (channel << card->shift_count) | 0x02 , base);
+ outw((queue << 8) | 0x06, base);
+ InterruptTheCard(base);
+ unlock_card(card);
+}
+
+