11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* $Id: w6692.c,v 1.18.2.4 2004/02/11 13:21:34 keil Exp $
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Winbond W6692 specific routines
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author       Petr Novak
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright    by Petr Novak        <petr.novak@i.cz>
7475be4d85a274d0961593db41cf85689db1d583cJoe Perches *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This software may be used and distributed according to the terms
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the GNU General Public License, incorporated herein by reference.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "hisax.h"
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "w6692.h"
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "isdnl1.h"
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
195a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* table entry in the PCI devices list */
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct {
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int vendor_id;
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int device_id;
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *vendor_name;
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *card_name;
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} PCI_ENTRY;
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const PCI_ENTRY id_list[] =
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, "Winbond", "W6692"},
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, "Dynalink/AsusCom", "IS64PH"},
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{0, 0, "U.S.Robotics", "ISDN PCI Card TA"}
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W6692_SV_USR   0x16ec
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W6692_SD_USR   0x3409
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W6692_WINBOND  0
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W6692_DYNALINK 1
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W6692_USR      2
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42672c3fd9069e5a138f9d4afc9aeb5aa34aacce32Adrian Bunkstatic const char *w6692_revision = "$Revision: 1.18.2.4 $";
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBUSY_TIMER_VALUE 80
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4667eb5db5874076db01febed5a1a9281628fa9fb4Karsten Keilstatic char *W6692Ver[] =
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{"W6692 V00", "W6692 V01", "W6692 V10",
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "W6692 V11"};
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5067eb5db5874076db01febed5a1a9281628fa9fb4Karsten Keilstatic void
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsW6692Version(struct IsdnCardState *cs, char *s)
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int val;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = cs->readW6692(cs, W_D_RBCH);
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "%s Winbond W6692 version (%x): %s\n", s, val, W6692Ver[(val >> 6) & 3]);
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsph_command(struct IsdnCardState *cs, unsigned int command)
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cs->debug & L1_DEB_ISAC)
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debugl1(cs, "ph_command %x", command);
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->writeisac(cs, W_CIX, command);
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsW6692_new_ph(struct IsdnCardState *cs)
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cs->dc.w6692.ph_state) {
72475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (W_L1CMD_RST):
73475be4d85a274d0961593db41cf85689db1d583cJoe Perches		ph_command(cs, W_L1CMD_DRC);
74475be4d85a274d0961593db41cf85689db1d583cJoe Perches		l1_msg(cs, HW_RESET | INDICATION, NULL);
75475be4d85a274d0961593db41cf85689db1d583cJoe Perches		/* fallthru */
76475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (W_L1IND_CD):
77475be4d85a274d0961593db41cf85689db1d583cJoe Perches		l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
78475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
79475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (W_L1IND_DRD):
80475be4d85a274d0961593db41cf85689db1d583cJoe Perches		l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
81475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
82475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (W_L1IND_CE):
83475be4d85a274d0961593db41cf85689db1d583cJoe Perches		l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
84475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
85475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (W_L1IND_LD):
86475be4d85a274d0961593db41cf85689db1d583cJoe Perches		l1_msg(cs, HW_RSYNC | INDICATION, NULL);
87475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
88475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (W_L1IND_ARD):
89475be4d85a274d0961593db41cf85689db1d583cJoe Perches		l1_msg(cs, HW_INFO2 | INDICATION, NULL);
90475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
91475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (W_L1IND_AI8):
92475be4d85a274d0961593db41cf85689db1d583cJoe Perches		l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
93475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
94475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (W_L1IND_AI10):
95475be4d85a274d0961593db41cf85689db1d583cJoe Perches		l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL);
96475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
97475be4d85a274d0961593db41cf85689db1d583cJoe Perches	default:
98475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
103c4028958b6ecad064b1a6303a6a5906d4fe48d73David HowellsW6692_bh(struct work_struct *work)
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
105c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	struct IsdnCardState *cs =
106c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells		container_of(work, struct IsdnCardState, tqueue);
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct PStack *stptr;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cs->debug)
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debugl1(cs, "D-Channel Busy cleared");
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		stptr = cs->stlist;
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (stptr != NULL) {
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			stptr = stptr->next;
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (test_and_clear_bit(D_L1STATECHANGE, &cs->event))
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		W6692_new_ph(cs);
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DChannel_proc_rcv(cs);
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DChannel_proc_xmt(cs);
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
125475be4d85a274d0961593db41cf85689db1d583cJoe Perches  if (test_and_clear_bit(D_RX_MON1, &cs->event))
126475be4d85a274d0961593db41cf85689db1d583cJoe Perches  arcofi_fsm(cs, ARCOFI_RX_END, NULL);
127475be4d85a274d0961593db41cf85689db1d583cJoe Perches  if (test_and_clear_bit(D_TX_MON1, &cs->event))
128475be4d85a274d0961593db41cf85689db1d583cJoe Perches  arcofi_fsm(cs, ARCOFI_TX_END, NULL);
129475be4d85a274d0961593db41cf85689db1d583cJoe Perches*/
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsW6692_empty_fifo(struct IsdnCardState *cs, int count)
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char *ptr;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debugl1(cs, "W6692_empty_fifo");
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cs->debug & L1_DEB_WARN)
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debugl1(cs, "W6692_empty_fifo overrun %d",
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cs->rcvidx + count);
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK);
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->rcvidx = 0;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ptr = cs->rcvbuf + cs->rcvidx;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->rcvidx += count;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->readW6692fifo(cs, ptr, count);
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK);
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cs->debug & L1_DEB_ISAC_FIFO) {
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		char *t = cs->dlog;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		t += sprintf(t, "W6692_empty_fifo cnt %d", count);
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		QuickHex(t, ptr, count);
15735a4a5733b0a8290de39558b82896ab795b108a7Kees Cook		debugl1(cs, "%s", cs->dlog);
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsW6692_fill_fifo(struct IsdnCardState *cs)
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int count, more;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char *ptr;
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debugl1(cs, "W6692_fill_fifo");
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!cs->tx_skb)
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	count = cs->tx_skb->len;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (count <= 0)
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	more = 0;
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (count > W_D_FIFO_THRESH) {
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		more = !0;
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		count = W_D_FIFO_THRESH;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ptr = cs->tx_skb->data;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_pull(cs->tx_skb, count);
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->tx_cnt += count;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->writeW6692fifo(cs, ptr, count);
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->writeW6692(cs, W_D_CMDR, more ? W_D_CMDR_XMS : (W_D_CMDR_XMS | W_D_CMDR_XME));
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debugl1(cs, "W6692_fill_fifo dbusytimer running");
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		del_timer(&cs->dbusytimer);
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_timer(&cs->dbusytimer);
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000);
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	add_timer(&cs->dbusytimer);
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cs->debug & L1_DEB_ISAC_FIFO) {
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		char *t = cs->dlog;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		t += sprintf(t, "W6692_fill_fifo cnt %d", count);
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		QuickHex(t, ptr, count);
19935a4a5733b0a8290de39558b82896ab795b108a7Kees Cook		debugl1(cs, "%s", cs->dlog);
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsW6692B_empty_fifo(struct BCState *bcs, int count)
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char *ptr;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct IsdnCardState *cs = bcs->cs;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debugl1(cs, "W6692B_empty_fifo");
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bcs->hw.w6692.rcvidx + count > HSCX_BUFMAX) {
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cs->debug & L1_DEB_WARN)
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debugl1(cs, "W6692B_empty_fifo: incoming packet too large");
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bcs->hw.w6692.rcvidx = 0;
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ptr = bcs->hw.w6692.rcvbuf + bcs->hw.w6692.rcvidx;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bcs->hw.w6692.rcvidx += count;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	READW6692BFIFO(cs, bcs->channel, ptr, count);
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cs->debug & L1_DEB_HSCX_FIFO) {
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		char *t = bcs->blog;
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		t += sprintf(t, "W6692B_empty_fifo %c cnt %d",
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     bcs->channel + '1', count);
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		QuickHex(t, ptr, count);
22935a4a5733b0a8290de39558b82896ab795b108a7Kees Cook		debugl1(cs, "%s", bcs->blog);
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsW6692B_fill_fifo(struct BCState *bcs)
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct IsdnCardState *cs = bcs->cs;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int more, count;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char *ptr;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!bcs->tx_skb)
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bcs->tx_skb->len <= 0)
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bcs->tx_skb->len > W_B_FIFO_THRESH) {
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		more = 1;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		count = W_B_FIFO_THRESH;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		count = bcs->tx_skb->len;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
253475be4d85a274d0961593db41cf85689db1d583cJoe Perches		debugl1(cs, "W6692B_fill_fifo%s%d", (more ? " " : " last "), count);
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ptr = bcs->tx_skb->data;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_pull(bcs->tx_skb, count);
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bcs->tx_cnt -= count;
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bcs->hw.w6692.count += count;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	WRITEW6692BFIFO(cs, bcs->channel, ptr, count);
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME));
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cs->debug & L1_DEB_HSCX_FIFO) {
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		char *t = bcs->blog;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		t += sprintf(t, "W6692B_fill_fifo %c cnt %d",
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     bcs->channel + '1', count);
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		QuickHex(t, ptr, count);
26735a4a5733b0a8290de39558b82896ab795b108a7Kees Cook		debugl1(cs, "%s", bcs->blog);
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsW6692B_interrupt(struct IsdnCardState *cs, u_char bchan)
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char val;
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char r;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct BCState *bcs;
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int count;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
280475be4d85a274d0961593db41cf85689db1d583cJoe Perches	bcs = (cs->bcs->channel == bchan) ? cs->bcs : (cs->bcs + 1);
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = cs->BC_Read_Reg(cs, bchan, W_B_EXIR);
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	debugl1(cs, "W6692B chan %d B_EXIR 0x%02X", bchan, val);
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!test_bit(BC_FLG_INIT, &bcs->Flag)) {
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debugl1(cs, "W6692B not INIT yet");
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val & W_B_EXI_RME) {	/* RME */
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		r = cs->BC_Read_Reg(cs, bchan, W_B_STAR);
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (r & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB)) {
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cs->debug & L1_DEB_WARN)
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				debugl1(cs, "W6692 B STAR %x", r);
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((r & W_B_STAR_RDOV) && bcs->mode)
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (cs->debug & L1_DEB_WARN)
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					debugl1(cs, "W6692 B RDOV mode=%d",
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						bcs->mode);
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (r & W_B_STAR_CRCE)
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (cs->debug & L1_DEB_WARN)
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					debugl1(cs, "W6692 B CRC error");
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT);
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			count = cs->BC_Read_Reg(cs, bchan, W_B_RBCL) & (W_B_FIFO_THRESH - 1);
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (count == 0)
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				count = W_B_FIFO_THRESH;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			W6692B_empty_fifo(bcs, count);
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((count = bcs->hw.w6692.rcvidx) > 0) {
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (cs->debug & L1_DEB_HSCX_FIFO)
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					debugl1(cs, "W6692 Bchan Frame %d", count);
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!(skb = dev_alloc_skb(count)))
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk(KERN_WARNING "W6692: Bchan receive out of memory\n");
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else {
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					memcpy(skb_put(skb, count), bcs->hw.w6692.rcvbuf, count);
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					skb_queue_tail(&bcs->rqueue, skb);
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bcs->hw.w6692.rcvidx = 0;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		schedule_event(bcs, B_RCVBUFREADY);
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val & W_B_EXI_RMR) {	/* RMR */
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		W6692B_empty_fifo(bcs, W_B_FIFO_THRESH);
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		r = cs->BC_Read_Reg(cs, bchan, W_B_STAR);
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (r & W_B_STAR_RDOV) {
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cs->debug & L1_DEB_WARN)
325475be4d85a274d0961593db41cf85689db1d583cJoe Perches				debugl1(cs, "W6692 B RDOV(RMR) mode=%d", bcs->mode);
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT);
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (bcs->mode != L1_MODE_TRANS)
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bcs->hw.w6692.rcvidx = 0;
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bcs->mode == L1_MODE_TRANS) {
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* receive audio data */
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!(skb = dev_alloc_skb(W_B_FIFO_THRESH)))
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk(KERN_WARNING "HiSax: receive out of memory\n");
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else {
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				memcpy(skb_put(skb, W_B_FIFO_THRESH), bcs->hw.w6692.rcvbuf, W_B_FIFO_THRESH);
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_queue_tail(&bcs->rqueue, skb);
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bcs->hw.w6692.rcvidx = 0;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			schedule_event(bcs, B_RCVBUFREADY);
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val & W_B_EXI_XDUN) {	/* XDUN */
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT);
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cs->debug & L1_DEB_WARN)
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debugl1(cs, "W6692 B EXIR %x Lost TX", val);
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bcs->mode == 1)
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			W6692B_fill_fifo(bcs);
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Here we lost an TX interrupt, so
350475be4d85a274d0961593db41cf85689db1d583cJoe Perches			 * restart transmitting the whole frame.
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (bcs->tx_skb) {
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_push(bcs->tx_skb, bcs->hw.w6692.count);
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bcs->tx_cnt += bcs->hw.w6692.count;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bcs->hw.w6692.count = 0;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val & W_B_EXI_XFR) {	/* XFR */
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		r = cs->BC_Read_Reg(cs, bchan, W_B_STAR);
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (r & W_B_STAR_XDOW) {
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cs->debug & L1_DEB_WARN)
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				debugl1(cs, "W6692 B STAR %x XDOW", r);
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT);
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (bcs->tx_skb && (bcs->mode != 1)) {
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_push(bcs->tx_skb, bcs->hw.w6692.count);
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bcs->tx_cnt += bcs->hw.w6692.count;
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bcs->hw.w6692.count = 0;
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bcs->tx_skb) {
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (bcs->tx_skb->len) {
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				W6692B_fill_fifo(bcs);
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return;
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
377475be4d85a274d0961593db41cf85689db1d583cJoe Perches				if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
378475be4d85a274d0961593db41cf85689db1d583cJoe Perches				    (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
379475be4d85a274d0961593db41cf85689db1d583cJoe Perches					u_long flags;
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					spin_lock_irqsave(&bcs->aclock, flags);
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					bcs->ackcnt += bcs->hw.w6692.count;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					spin_unlock_irqrestore(&bcs->aclock, flags);
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					schedule_event(bcs, B_ACKPENDING);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dev_kfree_skb_irq(bcs->tx_skb);
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bcs->hw.w6692.count = 0;
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bcs->tx_skb = NULL;
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bcs->hw.w6692.count = 0;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			W6692B_fill_fifo(bcs);
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			schedule_event(bcs, B_XMTBUFREADY);
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic irqreturn_t
4027d12e780e003f93433d49ce78cfedf4b4c52adc5David HowellsW6692_interrupt(int intno, void *dev_id)
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct IsdnCardState	*cs = dev_id;
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char			val, exval, v1;
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff		*skb;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int			count;
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long			flags;
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			icnt = 5;
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&cs->lock, flags);
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = cs->readW6692(cs, W_ISTA);
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!val) {
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&cs->lock, flags);
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_NONE;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
417475be4d85a274d0961593db41cf85689db1d583cJoe PerchesStartW6692:
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cs->debug & L1_DEB_ISAC)
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debugl1(cs, "W6692 ISTA %x", val);
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val & W_INT_D_RME) {	/* RME */
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		exval = cs->readW6692(cs, W_D_RSTA);
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (exval & (W_D_RSTA_RDOV | W_D_RSTA_CRCE | W_D_RSTA_RMB)) {
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (exval & W_D_RSTA_RDOV)
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (cs->debug & L1_DEB_WARN)
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					debugl1(cs, "W6692 RDOV");
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (exval & W_D_RSTA_CRCE)
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (cs->debug & L1_DEB_WARN)
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					debugl1(cs, "W6692 D-channel CRC error");
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (exval & W_D_RSTA_RMB)
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (cs->debug & L1_DEB_WARN)
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					debugl1(cs, "W6692 D-channel ABORT");
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST);
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			count = cs->readW6692(cs, W_D_RBCL) & (W_D_FIFO_THRESH - 1);
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (count == 0)
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				count = W_D_FIFO_THRESH;
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			W6692_empty_fifo(cs, count);
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((count = cs->rcvidx) > 0) {
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cs->rcvidx = 0;
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!(skb = alloc_skb(count, GFP_ATOMIC)))
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk(KERN_WARNING "HiSax: D receive out of memory\n");
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else {
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					memcpy(skb_put(skb, count), cs->rcvbuf, count);
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					skb_queue_tail(&cs->rq, skb);
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->rcvidx = 0;
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		schedule_event(cs, D_RCVBUFREADY);
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val & W_INT_D_RMR) {	/* RMR */
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		W6692_empty_fifo(cs, W_D_FIFO_THRESH);
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val & W_INT_D_XFR) {	/* XFR */
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			del_timer(&cs->dbusytimer);
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			schedule_event(cs, D_CLEARBUSY);
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cs->tx_skb) {
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cs->tx_skb->len) {
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				W6692_fill_fifo(cs);
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto afterXFR;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dev_kfree_skb_irq(cs->tx_skb);
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cs->tx_cnt = 0;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cs->tx_skb = NULL;
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cs->tx_cnt = 0;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			W6692_fill_fifo(cs);
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			schedule_event(cs, D_XMTBUFREADY);
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
476475be4d85a274d0961593db41cf85689db1d583cJoe PerchesafterXFR:
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val & (W_INT_XINT0 | W_INT_XINT1)) {	/* XINT0/1 - never */
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cs->debug & L1_DEB_ISAC)
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debugl1(cs, "W6692 spurious XINT!");
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val & W_INT_D_EXI) {	/* EXI */
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		exval = cs->readW6692(cs, W_D_EXIR);
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cs->debug & L1_DEB_WARN)
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debugl1(cs, "W6692 D_EXIR %02x", exval);
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (exval & (W_D_EXI_XDUN | W_D_EXI_XCOL)) {	/* Transmit underrun/collision */
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debugl1(cs, "W6692 D-chan underrun/collision");
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_WARNING "HiSax: W6692 XDUN/XCOL\n");
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				del_timer(&cs->dbusytimer);
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				schedule_event(cs, D_CLEARBUSY);
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cs->tx_skb) {	/* Restart frame */
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_push(cs->tx_skb, cs->tx_cnt);
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cs->tx_cnt = 0;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				W6692_fill_fifo(cs);
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk(KERN_WARNING "HiSax: W6692 XDUN/XCOL no skb\n");
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				debugl1(cs, "W6692 XDUN/XCOL no skb");
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_XRST);
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (exval & W_D_EXI_RDOV) {	/* RDOV */
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debugl1(cs, "W6692 D-channel RDOV");
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_WARNING "HiSax: W6692 D-RDOV\n");
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RRST);
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (exval & W_D_EXI_TIN2) {	/* TIN2 - never */
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debugl1(cs, "W6692 spurious TIN2 interrupt");
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (exval & W_D_EXI_MOC) {	/* MOC - not supported */
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debugl1(cs, "W6692 spurious MOC interrupt");
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			v1 = cs->readW6692(cs, W_MOSR);
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debugl1(cs, "W6692 MOSR %02x", v1);
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (exval & W_D_EXI_ISC) {	/* ISC - Level1 change */
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			v1 = cs->readW6692(cs, W_CIR);
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cs->debug & L1_DEB_ISAC)
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				debugl1(cs, "W6692 ISC CIR=0x%02X", v1);
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (v1 & W_CIR_ICC) {
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cs->dc.w6692.ph_state = v1 & W_CIR_COD_MASK;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (cs->debug & L1_DEB_ISAC)
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					debugl1(cs, "ph_state_change %x", cs->dc.w6692.ph_state);
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				schedule_event(cs, D_L1STATECHANGE);
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (v1 & W_CIR_SCC) {
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				v1 = cs->readW6692(cs, W_SQR);
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				debugl1(cs, "W6692 SCC SQR=0x%02X", v1);
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (exval & W_D_EXI_WEXP) {
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debugl1(cs, "W6692 spurious WEXP interrupt!");
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (exval & W_D_EXI_TEXP) {
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debugl1(cs, "W6692 spurious TEXP interrupt!");
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val & W_INT_B1_EXI) {
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debugl1(cs, "W6692 B channel 1 interrupt");
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		W6692B_interrupt(cs, 0);
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val & W_INT_B2_EXI) {
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debugl1(cs, "W6692 B channel 2 interrupt");
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		W6692B_interrupt(cs, 1);
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = cs->readW6692(cs, W_ISTA);
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val && icnt) {
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		icnt--;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto StartW6692;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!icnt) {
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "W6692 IRQ LOOP\n");
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->writeW6692(cs, W_IMASK, 0xff);
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&cs->lock, flags);
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_HANDLED;
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsW6692_l1hw(struct PStack *st, int pr, void *arg)
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb = arg;
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long flags;
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int val;
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (pr) {
567475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (PH_DATA | REQUEST):
568475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (cs->debug & DEB_DLOG_HEX)
569475be4d85a274d0961593db41cf85689db1d583cJoe Perches			LogFrame(cs, skb->data, skb->len);
570475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (cs->debug & DEB_DLOG_VERBOSE)
571475be4d85a274d0961593db41cf85689db1d583cJoe Perches			dlogframe(cs, skb, 0);
572475be4d85a274d0961593db41cf85689db1d583cJoe Perches		spin_lock_irqsave(&cs->lock, flags);
573475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (cs->tx_skb) {
574475be4d85a274d0961593db41cf85689db1d583cJoe Perches			skb_queue_tail(&cs->sq, skb);
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef L2FRAME_DEBUG		/* psa */
576475be4d85a274d0961593db41cf85689db1d583cJoe Perches			if (cs->debug & L1_DEB_LAPD)
577475be4d85a274d0961593db41cf85689db1d583cJoe Perches				Logl2Frame(cs, skb, "PH_DATA Queued", 0);
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
579475be4d85a274d0961593db41cf85689db1d583cJoe Perches		} else {
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cs->tx_skb = skb;
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cs->tx_cnt = 0;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef L2FRAME_DEBUG		/* psa */
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cs->debug & L1_DEB_LAPD)
584475be4d85a274d0961593db41cf85689db1d583cJoe Perches				Logl2Frame(cs, skb, "PH_DATA", 0);
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			W6692_fill_fifo(cs);
587475be4d85a274d0961593db41cf85689db1d583cJoe Perches		}
588475be4d85a274d0961593db41cf85689db1d583cJoe Perches		spin_unlock_irqrestore(&cs->lock, flags);
589475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
590475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (PH_PULL | INDICATION):
591475be4d85a274d0961593db41cf85689db1d583cJoe Perches		spin_lock_irqsave(&cs->lock, flags);
592475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (cs->tx_skb) {
593475be4d85a274d0961593db41cf85689db1d583cJoe Perches			if (cs->debug & L1_DEB_WARN)
594475be4d85a274d0961593db41cf85689db1d583cJoe Perches				debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
595475be4d85a274d0961593db41cf85689db1d583cJoe Perches			skb_queue_tail(&cs->sq, skb);
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock_irqrestore(&cs->lock, flags);
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
598475be4d85a274d0961593db41cf85689db1d583cJoe Perches		}
599475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (cs->debug & DEB_DLOG_HEX)
600475be4d85a274d0961593db41cf85689db1d583cJoe Perches			LogFrame(cs, skb->data, skb->len);
601475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (cs->debug & DEB_DLOG_VERBOSE)
602475be4d85a274d0961593db41cf85689db1d583cJoe Perches			dlogframe(cs, skb, 0);
603475be4d85a274d0961593db41cf85689db1d583cJoe Perches		cs->tx_skb = skb;
604475be4d85a274d0961593db41cf85689db1d583cJoe Perches		cs->tx_cnt = 0;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef L2FRAME_DEBUG		/* psa */
606475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (cs->debug & L1_DEB_LAPD)
607475be4d85a274d0961593db41cf85689db1d583cJoe Perches			Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
609475be4d85a274d0961593db41cf85689db1d583cJoe Perches		W6692_fill_fifo(cs);
610475be4d85a274d0961593db41cf85689db1d583cJoe Perches		spin_unlock_irqrestore(&cs->lock, flags);
611475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
612475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (PH_PULL | REQUEST):
613475be4d85a274d0961593db41cf85689db1d583cJoe Perches#ifdef L2FRAME_DEBUG		/* psa */
614475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (cs->debug & L1_DEB_LAPD)
615475be4d85a274d0961593db41cf85689db1d583cJoe Perches			debugl1(cs, "-> PH_REQUEST_PULL");
616475be4d85a274d0961593db41cf85689db1d583cJoe Perches#endif
617475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (!cs->tx_skb) {
618475be4d85a274d0961593db41cf85689db1d583cJoe Perches			test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
619475be4d85a274d0961593db41cf85689db1d583cJoe Perches			st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
620475be4d85a274d0961593db41cf85689db1d583cJoe Perches		} else
621475be4d85a274d0961593db41cf85689db1d583cJoe Perches			test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
622475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
623475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (HW_RESET | REQUEST):
624475be4d85a274d0961593db41cf85689db1d583cJoe Perches		spin_lock_irqsave(&cs->lock, flags);
625475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if ((cs->dc.w6692.ph_state == W_L1IND_DRD)) {
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ph_command(cs, W_L1CMD_ECK);
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock_irqrestore(&cs->lock, flags);
628475be4d85a274d0961593db41cf85689db1d583cJoe Perches		} else {
629475be4d85a274d0961593db41cf85689db1d583cJoe Perches			ph_command(cs, W_L1CMD_RST);
630475be4d85a274d0961593db41cf85689db1d583cJoe Perches			cs->dc.w6692.ph_state = W_L1CMD_RST;
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock_irqrestore(&cs->lock, flags);
632475be4d85a274d0961593db41cf85689db1d583cJoe Perches			W6692_new_ph(cs);
633475be4d85a274d0961593db41cf85689db1d583cJoe Perches		}
634475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
635475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (HW_ENABLE | REQUEST):
636475be4d85a274d0961593db41cf85689db1d583cJoe Perches		spin_lock_irqsave(&cs->lock, flags);
637475be4d85a274d0961593db41cf85689db1d583cJoe Perches		ph_command(cs, W_L1CMD_ECK);
638475be4d85a274d0961593db41cf85689db1d583cJoe Perches		spin_unlock_irqrestore(&cs->lock, flags);
639475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
640475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (HW_INFO3 | REQUEST):
641475be4d85a274d0961593db41cf85689db1d583cJoe Perches		spin_lock_irqsave(&cs->lock, flags);
642475be4d85a274d0961593db41cf85689db1d583cJoe Perches		ph_command(cs, W_L1CMD_AR8);
643475be4d85a274d0961593db41cf85689db1d583cJoe Perches		spin_unlock_irqrestore(&cs->lock, flags);
644475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
645475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (HW_TESTLOOP | REQUEST):
646475be4d85a274d0961593db41cf85689db1d583cJoe Perches		val = 0;
647475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (1 & (long) arg)
648475be4d85a274d0961593db41cf85689db1d583cJoe Perches			val |= 0x0c;
649475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (2 & (long) arg)
650475be4d85a274d0961593db41cf85689db1d583cJoe Perches			val |= 0x3;
651475be4d85a274d0961593db41cf85689db1d583cJoe Perches		/* !!! not implemented yet */
652475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
653475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (HW_DEACTIVATE | RESPONSE):
654475be4d85a274d0961593db41cf85689db1d583cJoe Perches		skb_queue_purge(&cs->rq);
655475be4d85a274d0961593db41cf85689db1d583cJoe Perches		skb_queue_purge(&cs->sq);
656475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (cs->tx_skb) {
657475be4d85a274d0961593db41cf85689db1d583cJoe Perches			dev_kfree_skb_any(cs->tx_skb);
658475be4d85a274d0961593db41cf85689db1d583cJoe Perches			cs->tx_skb = NULL;
659475be4d85a274d0961593db41cf85689db1d583cJoe Perches		}
660475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
661475be4d85a274d0961593db41cf85689db1d583cJoe Perches			del_timer(&cs->dbusytimer);
662475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
663475be4d85a274d0961593db41cf85689db1d583cJoe Perches			schedule_event(cs, D_CLEARBUSY);
664475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
665475be4d85a274d0961593db41cf85689db1d583cJoe Perches	default:
666475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (cs->debug & L1_DEB_WARN)
667475be4d85a274d0961593db41cf85689db1d583cJoe Perches			debugl1(cs, "W6692_l1hw unknown %04x", pr);
668475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssetstack_W6692(struct PStack *st, struct IsdnCardState *cs)
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l1.l1hw = W6692_l1hw;
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsDC_Close_W6692(struct IsdnCardState *cs)
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdbusy_timer_handler(struct IsdnCardState *cs)
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct PStack *stptr;
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rbch, star;
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long flags;
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&cs->lock, flags);
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rbch = cs->readW6692(cs, W_D_RBCH);
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		star = cs->readW6692(cs, W_D_STAR);
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cs->debug)
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			debugl1(cs, "D-Channel Busy D_RBCH %02x D_STAR %02x",
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rbch, star);
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (star & W_D_STAR_XBZ) {	/* D-Channel Busy */
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			stptr = cs->stlist;
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while (stptr != NULL) {
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				stptr = stptr->next;
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* discard frame; reset transceiver */
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cs->tx_skb) {
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dev_kfree_skb_any(cs->tx_skb);
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cs->tx_cnt = 0;
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cs->tx_skb = NULL;
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk(KERN_WARNING "HiSax: W6692 D-Channel Busy no skb\n");
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				debugl1(cs, "D-Channel Busy no skb");
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_XRST);	/* Transmitter reset */
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock_irqrestore(&cs->lock, flags);
7177d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells			cs->irq_func(cs->irq, cs);
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&cs->lock, flags);
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsW6692Bmode(struct BCState *bcs, int mode, int bchan)
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct IsdnCardState *cs = bcs->cs;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cs->debug & L1_DEB_HSCX)
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		debugl1(cs, "w6692 %c mode %d ichan %d",
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			'1' + bchan, mode, bchan);
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bcs->mode = mode;
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bcs->channel = bchan;
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bcs->hw.w6692.bchan = bchan;
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (mode) {
737475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (L1_MODE_NULL):
738475be4d85a274d0961593db41cf85689db1d583cJoe Perches		cs->BC_Write_Reg(cs, bchan, W_B_MODE, 0);
739475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
740475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (L1_MODE_TRANS):
741475be4d85a274d0961593db41cf85689db1d583cJoe Perches		cs->BC_Write_Reg(cs, bchan, W_B_MODE, W_B_MODE_MMS);
742475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
743475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (L1_MODE_HDLC):
744475be4d85a274d0961593db41cf85689db1d583cJoe Perches		cs->BC_Write_Reg(cs, bchan, W_B_MODE, W_B_MODE_ITF);
745475be4d85a274d0961593db41cf85689db1d583cJoe Perches		cs->BC_Write_Reg(cs, bchan, W_B_ADM1, 0xff);
746475be4d85a274d0961593db41cf85689db1d583cJoe Perches		cs->BC_Write_Reg(cs, bchan, W_B_ADM2, 0xff);
747475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mode)
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RRST |
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 W_B_CMDR_RACT | W_B_CMDR_XRST);
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->BC_Write_Reg(cs, bchan, W_B_EXIM, 0x00);
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsW6692_l2l1(struct PStack *st, int pr, void *arg)
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb = arg;
759475be4d85a274d0961593db41cf85689db1d583cJoe Perches	struct BCState *bcs = st->l1.bcs;
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long flags;
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (pr) {
763475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (PH_DATA | REQUEST):
764475be4d85a274d0961593db41cf85689db1d583cJoe Perches		spin_lock_irqsave(&bcs->cs->lock, flags);
765475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (bcs->tx_skb) {
766475be4d85a274d0961593db41cf85689db1d583cJoe Perches			skb_queue_tail(&bcs->squeue, skb);
767475be4d85a274d0961593db41cf85689db1d583cJoe Perches		} else {
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bcs->tx_skb = skb;
769475be4d85a274d0961593db41cf85689db1d583cJoe Perches			test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bcs->hw.w6692.count = 0;
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bcs->cs->BC_Send_Data(bcs);
772475be4d85a274d0961593db41cf85689db1d583cJoe Perches		}
773475be4d85a274d0961593db41cf85689db1d583cJoe Perches		spin_unlock_irqrestore(&bcs->cs->lock, flags);
774475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
775475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (PH_PULL | INDICATION):
776475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (bcs->tx_skb) {
777475be4d85a274d0961593db41cf85689db1d583cJoe Perches			printk(KERN_WARNING "W6692_l2l1: this shouldn't happen\n");
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
779475be4d85a274d0961593db41cf85689db1d583cJoe Perches		}
780475be4d85a274d0961593db41cf85689db1d583cJoe Perches		spin_lock_irqsave(&bcs->cs->lock, flags);
781475be4d85a274d0961593db41cf85689db1d583cJoe Perches		test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
782475be4d85a274d0961593db41cf85689db1d583cJoe Perches		bcs->tx_skb = skb;
783475be4d85a274d0961593db41cf85689db1d583cJoe Perches		bcs->hw.w6692.count = 0;
784475be4d85a274d0961593db41cf85689db1d583cJoe Perches		bcs->cs->BC_Send_Data(bcs);
785475be4d85a274d0961593db41cf85689db1d583cJoe Perches		spin_unlock_irqrestore(&bcs->cs->lock, flags);
786475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
787475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (PH_PULL | REQUEST):
788475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (!bcs->tx_skb) {
789475be4d85a274d0961593db41cf85689db1d583cJoe Perches			test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
790475be4d85a274d0961593db41cf85689db1d583cJoe Perches			st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
791475be4d85a274d0961593db41cf85689db1d583cJoe Perches		} else
792475be4d85a274d0961593db41cf85689db1d583cJoe Perches			test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
793475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
794475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (PH_ACTIVATE | REQUEST):
795475be4d85a274d0961593db41cf85689db1d583cJoe Perches		spin_lock_irqsave(&bcs->cs->lock, flags);
796475be4d85a274d0961593db41cf85689db1d583cJoe Perches		test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
797475be4d85a274d0961593db41cf85689db1d583cJoe Perches		W6692Bmode(bcs, st->l1.mode, st->l1.bc);
798475be4d85a274d0961593db41cf85689db1d583cJoe Perches		spin_unlock_irqrestore(&bcs->cs->lock, flags);
799475be4d85a274d0961593db41cf85689db1d583cJoe Perches		l1_msg_b(st, pr, arg);
800475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
801475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (PH_DEACTIVATE | REQUEST):
802475be4d85a274d0961593db41cf85689db1d583cJoe Perches		l1_msg_b(st, pr, arg);
803475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
804475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case (PH_DEACTIVATE | CONFIRM):
805475be4d85a274d0961593db41cf85689db1d583cJoe Perches		spin_lock_irqsave(&bcs->cs->lock, flags);
806475be4d85a274d0961593db41cf85689db1d583cJoe Perches		test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
807475be4d85a274d0961593db41cf85689db1d583cJoe Perches		test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
808475be4d85a274d0961593db41cf85689db1d583cJoe Perches		W6692Bmode(bcs, 0, st->l1.bc);
809475be4d85a274d0961593db41cf85689db1d583cJoe Perches		spin_unlock_irqrestore(&bcs->cs->lock, flags);
810475be4d85a274d0961593db41cf85689db1d583cJoe Perches		st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
811475be4d85a274d0961593db41cf85689db1d583cJoe Perches		break;
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsclose_w6692state(struct BCState *bcs)
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	W6692Bmode(bcs, 0, bcs->channel);
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
8203c7208f253571ee5f157b98f0e315b5172afe092Jesper Juhl		kfree(bcs->hw.w6692.rcvbuf);
8213c7208f253571ee5f157b98f0e315b5172afe092Jesper Juhl		bcs->hw.w6692.rcvbuf = NULL;
8223c7208f253571ee5f157b98f0e315b5172afe092Jesper Juhl		kfree(bcs->blog);
8233c7208f253571ee5f157b98f0e315b5172afe092Jesper Juhl		bcs->blog = NULL;
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb_queue_purge(&bcs->rqueue);
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb_queue_purge(&bcs->squeue);
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bcs->tx_skb) {
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_kfree_skb_any(bcs->tx_skb);
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bcs->tx_skb = NULL;
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsopen_w6692state(struct IsdnCardState *cs, struct BCState *bcs)
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(bcs->hw.w6692.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_WARNING
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "HiSax: No memory for w6692.rcvbuf\n");
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (1);
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_WARNING
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "HiSax: No memory for bcs->blog\n");
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(bcs->hw.w6692.rcvbuf);
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bcs->hw.w6692.rcvbuf = NULL;
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (2);
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb_queue_head_init(&bcs->rqueue);
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb_queue_head_init(&bcs->squeue);
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bcs->tx_skb = NULL;
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bcs->event = 0;
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bcs->hw.w6692.rcvidx = 0;
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bcs->tx_cnt = 0;
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssetstack_w6692(struct PStack *st, struct BCState *bcs)
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bcs->channel = st->l1.bc;
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (open_w6692state(st->l1.hardware, bcs))
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (-1);
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l1.bcs = bcs;
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	st->l2.l2l1 = W6692_l2l1;
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	setstack_manager(st);
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bcs->st = st;
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	setstack_l1_B(st);
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
877672c3fd9069e5a138f9d4afc9aeb5aa34aacce32Adrian Bunkstatic void resetW6692(struct IsdnCardState *cs)
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->writeW6692(cs, W_D_CTL, W_D_CTL_SRST);
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mdelay(10);
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->writeW6692(cs, W_D_CTL, 0x00);
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mdelay(10);
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->writeW6692(cs, W_IMASK, 0xff);
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->writeW6692(cs, W_D_SAM, 0xff);
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->writeW6692(cs, W_D_TAM, 0xff);
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->writeW6692(cs, W_D_EXIM, 0x00);
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->writeW6692(cs, W_D_MODE, W_D_MODE_RACT);
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->writeW6692(cs, W_IMASK, 0x18);
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cs->subtyp == W6692_USR) {
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* seems that USR implemented some power control features
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Pin 79 is connected to the oscilator circuit so we
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * have to handle it here
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->writeW6692(cs, W_PCTL, 0x80);
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->writeW6692(cs, W_XDATA, 0x00);
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
89967eb5db5874076db01febed5a1a9281628fa9fb4Karsten Keilstatic void initW6692(struct IsdnCardState *cs, int part)
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (part & 1) {
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->setstack_d = setstack_W6692;
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->DC_Close = DC_Close_W6692;
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->dbusytimer.function = (void *) dbusy_timer_handler;
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->dbusytimer.data = (long) cs;
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		init_timer(&cs->dbusytimer);
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		resetW6692(cs);
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ph_command(cs, W_L1CMD_RST);
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->dc.w6692.ph_state = W_L1CMD_RST;
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		W6692_new_ph(cs);
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ph_command(cs, W_L1CMD_ECK);
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->bcs[0].BC_SetStack = setstack_w6692;
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->bcs[1].BC_SetStack = setstack_w6692;
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->bcs[0].BC_Close = close_w6692state;
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->bcs[1].BC_Close = close_w6692state;
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		W6692Bmode(cs->bcs, 0, 0);
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		W6692Bmode(cs->bcs + 1, 0, 0);
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (part & 2) {
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Reenable all IRQ */
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->writeW6692(cs, W_IMASK, 0x18);
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->writeW6692(cs, W_D_EXIM, 0x00);
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->BC_Write_Reg(cs, 0, W_B_EXIM, 0x00);
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->BC_Write_Reg(cs, 1, W_B_EXIM, 0x00);
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Reset D-chan receiver and transmitter */
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RRST | W_D_CMDR_XRST);
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Interface functions */
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_char
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsReadW6692(struct IsdnCardState *cs, u_char offset)
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (inb(cs->hw.w6692.iobase + offset));
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsWriteW6692(struct IsdnCardState *cs, u_char offset, u_char value)
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(value, cs->hw.w6692.iobase + offset);
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
946475be4d85a274d0961593db41cf85689db1d583cJoe PerchesReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	insb(cs->hw.w6692.iobase + W_D_RFIFO, data, size);
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
952475be4d85a274d0961593db41cf85689db1d583cJoe PerchesWriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outsb(cs->hw.w6692.iobase + W_D_XFIFO, data, size);
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_char
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsReadW6692B(struct IsdnCardState *cs, int bchan, u_char offset)
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (inb(cs->hw.w6692.iobase + (bchan ? 0x40 : 0) + offset));
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsWriteW6692B(struct IsdnCardState *cs, int bchan, u_char offset, u_char value)
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(value, cs->hw.w6692.iobase + (bchan ? 0x40 : 0) + offset);
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsw6692_card_msg(struct IsdnCardState *cs, int mt, void *arg)
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (mt) {
973475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case CARD_RESET:
974475be4d85a274d0961593db41cf85689db1d583cJoe Perches		resetW6692(cs);
975475be4d85a274d0961593db41cf85689db1d583cJoe Perches		return (0);
976475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case CARD_RELEASE:
977475be4d85a274d0961593db41cf85689db1d583cJoe Perches		cs->writeW6692(cs, W_IMASK, 0xff);
978475be4d85a274d0961593db41cf85689db1d583cJoe Perches		release_region(cs->hw.w6692.iobase, 256);
979475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (cs->subtyp == W6692_USR) {
980475be4d85a274d0961593db41cf85689db1d583cJoe Perches			cs->writeW6692(cs, W_XDATA, 0x04);
981475be4d85a274d0961593db41cf85689db1d583cJoe Perches		}
982475be4d85a274d0961593db41cf85689db1d583cJoe Perches		return (0);
983475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case CARD_INIT:
984475be4d85a274d0961593db41cf85689db1d583cJoe Perches		initW6692(cs, 3);
985475be4d85a274d0961593db41cf85689db1d583cJoe Perches		return (0);
986475be4d85a274d0961593db41cf85689db1d583cJoe Perches	case CARD_TEST:
987475be4d85a274d0961593db41cf85689db1d583cJoe Perches		return (0);
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (0);
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
992475be4d85a274d0961593db41cf85689db1d583cJoe Perchesstatic int id_idx;
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
994ed5a84cdf593e54969518e82762786fbe1284ce4Greg Kroah-Hartmanstatic struct pci_dev *dev_w6692 = NULL;
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
996ed5a84cdf593e54969518e82762786fbe1284ce4Greg Kroah-Hartmanint setup_w6692(struct IsdnCard *card)
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct IsdnCardState *cs = card->cs;
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char tmp[64];
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char found = 0;
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char pci_irq = 0;
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int pci_ioaddr = 0;
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy(tmp, w6692_revision);
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp));
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cs->typ != ISDN_CTYPE_W6692)
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
1008bfc7c89f068bbbc2c48588385529d15c6feef802Jeff Garzik
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (id_list[id_idx].vendor_id) {
101041a68a748bbc61f5bcea999e33ba72926dfbe6f7Tilman Schmidt		dev_w6692 = hisax_find_pci_device(id_list[id_idx].vendor_id,
1011475be4d85a274d0961593db41cf85689db1d583cJoe Perches						  id_list[id_idx].device_id,
1012475be4d85a274d0961593db41cf85689db1d583cJoe Perches						  dev_w6692);
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (dev_w6692) {
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (pci_enable_device(dev_w6692))
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cs->subtyp = id_idx;
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		id_idx++;
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev_w6692) {
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		found = 1;
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_irq = dev_w6692->irq;
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* I think address 0 is allways the configuration area */
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* and address 1 is the real IO space KKe 03.09.99 */
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_ioaddr = pci_resource_start(dev_w6692, 1);
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* USR ISDN PCI card TA need some special handling */
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cs->subtyp == W6692_WINBOND) {
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((W6692_SV_USR == dev_w6692->subsystem_vendor) &&
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    (W6692_SD_USR == dev_w6692->subsystem_device)) {
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cs->subtyp = W6692_USR;
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!found) {
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "W6692: No PCI card found\n");
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->irq = pci_irq;
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!cs->irq) {
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "W6692: No IRQ for PCI card found\n");
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!pci_ioaddr) {
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "W6692: NO I/O Base Address found\n");
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->hw.w6692.iobase = pci_ioaddr;
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "Found: %s %s, I/O base: 0x%x, irq: %d\n",
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       id_list[cs->subtyp].vendor_name, id_list[cs->subtyp].card_name,
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       pci_ioaddr, pci_irq);
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!request_region(cs->hw.w6692.iobase, 256, id_list[cs->subtyp].card_name)) {
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "HiSax: %s I/O ports %x-%x already in use\n",
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       id_list[cs->subtyp].card_name,
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       cs->hw.w6692.iobase,
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       cs->hw.w6692.iobase + 255);
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (0);
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       "HiSax: %s config irq:%d I/O:%x\n",
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       id_list[cs->subtyp].card_name, cs->irq,
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       cs->hw.w6692.iobase);
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1066c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	INIT_WORK(&cs->tqueue, W6692_bh);
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->readW6692 = &ReadW6692;
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->writeW6692 = &WriteW6692;
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->readisacfifo = &ReadISACfifo;
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->writeisacfifo = &WriteISACfifo;
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->BC_Read_Reg = &ReadW6692B;
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->BC_Write_Reg = &WriteW6692B;
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->BC_Send_Data = &W6692B_fill_fifo;
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->cardmsg = &w6692_card_msg;
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cs->irq_func = &W6692_interrupt;
10769ba02bec3888d391bad0fb0a8dd584f88eed6c8dThomas Gleixner	cs->irq_flags |= IRQF_SHARED;
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	W6692Version(cs, "W6692:");
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "W6692 ISTA=0x%X\n", ReadW6692(cs, W_ISTA));
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "W6692 IMASK=0x%X\n", ReadW6692(cs, W_IMASK));
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "W6692 D_EXIR=0x%X\n", ReadW6692(cs, W_D_EXIR));
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "W6692 D_EXIM=0x%X\n", ReadW6692(cs, W_D_EXIM));
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "W6692 D_RSTA=0x%X\n", ReadW6692(cs, W_D_RSTA));
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (1);
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1085