--- linux/drivers/net/wan/Makefile	2003-03-06 14:56:13.000000000 +0100
+++ linux/drivers/net/wan/Makefile	2003-03-30 22:37:04.000000000 +0200
@@ -66,6 +66,7 @@
 endif
 obj-$(CONFIG_N2)		+= n2.o
 obj-$(CONFIG_C101)		+= c101.o
+obj-$(CONFIG_TAHOE9XX)		+= tahoe9xx.o
 obj-$(CONFIG_WANXL)		+= wanxl.o
 obj-$(CONFIG_PCI200SYN)		+= pci200syn.o
 
--- linux/drivers/net/wan/tahoe9xx.c	2003-04-07 14:18:45.000000000 +0200
+++ linux/drivers/net/wan/tahoe9xx.c	2003-04-07 13:47:45.000000000 +0200
@@ -0,0 +1,824 @@
+/*
+ * Tahoe 9xx synchronous serial card driver for Linux
+ *
+ * Copyright (C) 2002-2003 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 2003 Piotr Kaczmarzyk <piotr@tahoe.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * For information see http://hq.pm.waw.pl/hdlc/
+ *
+ * Sources of information:
+ *    Hitachi HD64570 SCA User's Manual
+ *    PLX Technology Inc. PCI9052 Data Book
+ *    Dallas Semiconductor DS21554 Datasheet
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/hdlc.h>
+#include <linux/pci.h>
+#include <asm/delay.h>
+#include <asm/io.h>
+
+#include "hd64570.h"
+
+static const char* version = "Tahoe 9xx driver version: 1.16t";
+static const char* devname = "TAHOE9XX";
+
+#define	TAHOE9XX_PLX_SIZE	0x80	/* PLX control window size (128b) */
+#define	TAHOE9XX_SCA_SIZE	0x100	/* SCA window size (256b) */
+#define ALL_PAGES_ALWAYS_MAPPED
+#define NEED_DETECT_RAM
+#define NEED_SCA_MSCI_INTR
+#define MAX_TX_BUFFERS		10
+
+#define CLOCK_BASE 9216000
+
+#define G703_AMI		0
+#define G703_HDB3		1
+
+#define DEFAULT_LICR    0x80
+
+#define PCI_VENDOR_ID_TAHOE		0x8246
+#define PCI_DEVICE_ID_TAHOE931	0x0931
+#define PCI_DEVICE_ID_TAHOE932	0x0932
+#define PCI_DEVICE_ID_TAHOE971	0x0971
+#define PCI_DEVICE_ID_TAHOE972	0x0972
+
+/*
+ *      PLX PCI9052 local configuration and shared runtime registers.
+ *	This structure can be used to access 9052 registers (memory mapped).
+ */
+typedef struct {
+	u32 loc_addr_range[4];	/* 00-0Ch : Local Address Ranges */
+	u32 loc_rom_range;	/* 10h : Local ROM Range */
+	u32 loc_addr_base[4];	/* 14-20h : Local Address Base Addrs */
+	u32 loc_rom_base;	/* 24h : Local ROM Base */
+	u32 loc_bus_descr[4];	/* 28-34h : Local Bus Descriptors */
+	u32 rom_bus_descr;	/* 38h : ROM Bus Descriptor */
+	u32 cs_base[4];		/* 3C-48h : Chip Select Base Addrs */
+	u32 intr_ctrl_stat;	/* 4Ch : Interrupt Control/Status */
+	u32 init_ctrl;		/* 50h : EEPROM ctrl, Init Ctrl, etc */
+}plx9052;
+
+
+
+
+
+typedef struct ds21554_s {
+	u8	vcr1;		/* Counter:	Violation Error */
+	u8	vcr2;
+	u8	crccr1;		/* Counter:	CRC4 Error */
+	u8	crccr2;
+	u8	ebcr1;		/* Counter:	E-bit Error (FEBE) */
+	u8	ebcr2;
+	u8	sr1;		/* Status:	Status Register 1 */
+	u8	sr2;		/* Status:	Status Register 2 */
+	u8	rir;		/* Status:	Receive Information */
+	u8	reserved1[6];
+	u8	idr;		/* Misc:	Device Indentification */
+	u8	rcr1;		/* Control:	Receive Control 1 */
+	u8	rcr2;		/* Control:	Receive Control 2 */
+	u8	tcr1;		/* Control:	Transmit Control 1 */
+	u8	tcr2;		/* Control:	Transmit Control 2 */
+	u8	ccr1;		/* Control:	Common Control 1 */
+	u8	test1;
+	u8	imr1;		/* Interrupt Mask 1 */
+	u8	imr2;		/* Interrupt Mask 2 */
+	u8	licr;		/* Control: Line interface */
+	u8	test2;
+	u8	ccr2;		/* Control: Common Control 2 */
+	u8	ccr3;		/* Control: Common Control 3 */
+	u8	tsacr;		/* Control: Transmit Sa bit */
+	u8	ccr6;		/* Control: Common Control 6 */
+	u8	ssr;		/* Status: 	Synchronizer Status */
+	u8	rnaf;		/* Receive non-align frame */
+	u8	taf;		/* Transmit align frame */
+	u8	tnaf;		/* Transmit non-align frame */
+	u8	tcbr1;		/* Transmit channel blocking */
+	u8	tcbr2;
+	u8	tcbr3;
+	u8	tcbr4;
+	u8	tir1;		/* Transmit idle */
+	u8	tir2;
+	u8	tir3;
+	u8	tir4;
+	u8	tidr;		/* Transmit idle definition */
+	u8	rcbr1;		/* Receive channel blocking */
+	u8	rcbr2;
+	u8	rcbr3;
+	u8	rcbr4;
+	u8	raf;		/* Receive align frame */
+	u8	rs1;		/* Receive signalling */
+	u8	rs2;
+	u8	rs3;
+	u8	rs4;
+	u8	rs5;
+	u8	rs6;
+	u8	rs7;
+	u8	rs8;
+	u8	rs9;
+	u8	rs10;
+	u8	rs11;
+	u8	rs12;
+	u8	rs13;
+	u8	rs14;
+	u8	rs15;
+	u8	rs16;
+	u8	ts1;		/* Transmit signaling */
+	u8	ts2;
+	u8	ts3;
+	u8	ts4;
+	u8	ts5;
+	u8	ts6;
+	u8	ts7;
+	u8	ts8;
+	u8	ts9;
+	u8	ts10;
+	u8	ts11;
+	u8	ts12;
+	u8	ts13;
+	u8	ts14;
+	u8	ts15;
+	u8	ts16;
+	u8	tsiaf;		/* Transmit Si Bits Align Frame */
+	u8	tsinaf;		/* Transmit Si Bits Non-align Frame */
+	u8	tra;		/* Transmit Remote Alarm Bits */
+	u8	tsa4;		/* Transmit Sa Bits */
+	u8	tsa5;
+	u8	tsa6;
+	u8	tsa7;
+	u8	tsa8;
+	u8	rsiaf;		/* Receive Si Bits Align Frame */
+	u8	rsinaf;		/* Receive Si Bits Non-Align Frame */
+	u8	rra;		/* Receive Remote Alarm Bits */
+	u8	rsa4;		/* Receive Sa Bits */
+	u8	rsa5;
+	u8	rsa6;
+	u8	rsa7;
+	u8	rsa8;
+	u8	tc1;		/* Transmit channel */
+	u8	tc2;
+	u8	tc3;
+	u8	tc4;
+	u8	tc5;
+	u8	tc6;
+	u8	tc7;
+	u8	tc8;
+	u8	tc9;
+	u8	tc10;
+	u8	tc11;
+	u8	tc12;
+	u8	tc13;
+	u8	tc14;
+	u8	tc15;
+	u8	tc16;
+	u8	tc17;
+	u8	tc18;
+	u8	tc19;
+	u8	tc20;
+	u8	tc21;
+	u8	tc22;
+	u8	tc23;
+	u8	tc24;
+	u8	tc25;
+	u8	tc26;
+	u8	tc27;
+	u8	tc28;
+	u8	tc29;
+	u8	tc30;
+	u8	tc31;
+	u8	tc32;
+	u8	rc1;		/* Receive channel */
+	u8	rc2;
+	u8	rc3;
+	u8	rc4;
+	u8	rc5;
+	u8	rc6;
+	u8	rc7;
+	u8	rc8;
+	u8	rc9;
+	u8	rc10;
+	u8	rc11;
+	u8	rc12;
+	u8	rc13;
+	u8	rc14;
+	u8	rc15;
+	u8	rc16;
+	u8	rc17;
+	u8	rc18;
+	u8	rc19;
+	u8	rc20;
+	u8	rc21;
+	u8	rc22;
+	u8	rc23;
+	u8	rc24;
+	u8	rc25;
+	u8	rc26;
+	u8	rc27;
+	u8	rc28;
+	u8	rc29;
+	u8	rc30;
+	u8	rc31;
+	u8	rc32;
+	u8	tcc1;		/* Transmit channel control */
+	u8	tcc2;
+	u8	tcc3;
+	u8	tcc4;
+	u8	rcc1;		/* Receive channel control */
+	u8	rcc2;
+	u8	rcc3;
+	u8	rcc4;
+	u8	ccr4;		/* Control:	Common Control 4 */
+	u8	tds0m;		/* Transmit DS0 Monitor */
+	u8	ccr5;		/* Control:	Common Control 5 */
+	u8	rds0m;		/* Receive DS0 Monitor */
+	u8	test3;
+	u8	reserved2[3];
+	u8	hcr;		/* HDLC Control */
+	u8	hsr;		/* HDLC Status */
+	u8	himr;		/* HDLC Interrupt Mask */
+	u8	rhir;		/* Receive HDLC Information */
+	u8	rhfr;		/* Receive HDLC FIFO */
+	u8	ibo;		/* Interleave Bus Operation */
+	u8	thir;		/* Transmit HDLC Information */
+	u8	thfr;		/* Transmit HDLC FIFO */
+	u8	rdc1;		/* Receive HDLC DS0 Control 1 */
+	u8	rdc2;		/* Receive HDLC DS0 Control 2 */
+	u8	tdc1;		/* Transmit HDLC DS0 Control 1 */
+	u8	tdc2;		/* Transmit HDLC DS0 Control 2 */
+	u8	reserved3[4];
+} ds21554_t;
+
+typedef struct port_s {
+	struct net_device *dev;
+    struct card_s *card;
+	spinlock_t lock;	/* TX lock */
+	te1_settings settings;
+	int rxpart;		/* partial frame received, next frame invalid*/
+	unsigned short encoding;
+	unsigned short parity;
+	u16 rxin;		/* rx ring buffer 'in' pointer */
+	u16 txin;		/* tx ring buffer 'in' and 'last' pointers */
+	u16 txlast;
+	u8 rxs, txs, tmc;	/* SCA registers */
+	u8 phy_node;		/* physical port # - 0 or 1 */
+	u32 dsphys;			/* DS21544 memory base (physical) */
+	ds21554_t* dsbase;	/* DS21544 memory base (virtual) */
+	u8	g703_on;		/* Enable/disable G.703 transceiver */
+	u8	g703_coding;	/* G.703 line coding */
+	u8	g703_idlecode;	/* G.703 idle timeslots contents */
+}port_t;
+
+typedef struct card_s {
+	u8* rambase;		/* buffer memory base (virtual) */
+	u8* scabase;		/* SCA memory base (virtual) */
+	plx9052* plxbase;	/* PLX registers memory base (virtual) */
+	u16 rx_ring_buffers;	/* number of buffers in a ring */
+	u16 tx_ring_buffers;
+	u16 buff_offset;	/* offset of first buffer of first channel */
+	u8 irq;				/* interrupt request level */
+	u8 no_ports;		/* number of ports */
+	char dev_name[10];	/* device name */
+	port_t ports[2];
+}card_t;
+
+#define sca_in(reg, card)	     readb(card->scabase + (reg))
+#define sca_out(value, reg, card)    writeb(value, card->scabase + (reg))
+#define sca_inw(reg, card)	     readw(card->scabase + (reg))
+#define sca_outw(value, reg, card)   writew(value, card->scabase + (reg))
+#define sca_inl(reg, card)	     readl(card->scabase + (reg))
+#define sca_outl(value, reg, card)   writel(value, card->scabase + (reg))
+
+#define port_to_card(port)	     (port->card)
+#define log_node(port)		     (port->phy_node)
+#define phy_node(port)		     (port->phy_node)
+#define winbase(card)      	     (card->rambase)
+#define get_port(card, port)	     (&card->ports[port])
+#define sca_flush(card)		     (sca_in(IER0, card));
+
+static inline void new_memcpy_toio(char *dest, char *src, int length)
+{
+	int len;
+	
+	do {
+		len = length > 64 ? 64 : length; /* 32 */
+		memcpy_toio(dest, src, len);
+		dest += len;
+		src += len;
+		length -= len;
+		readb(dest);
+	} while (len);
+}
+
+#undef memcpy_toio
+#define memcpy_toio new_memcpy_toio
+
+#include "hd6457x.c"
+
+void init_ds21554(port_t *port);
+
+static void t9xx_set_iface(port_t *port)
+{
+	card_t *card = port->card;
+	u8 msci = get_msci(port);
+	u8 rxs = port->rxs & CLK_BRG_MASK;
+	u8 txs = port->txs & CLK_BRG_MASK;
+	
+	if (port->dsbase) {
+		init_ds21554(port);
+	}
+	
+	rxs |= CLK_LINE_RX; /* RXC input */
+	txs |= CLK_LINE_TX; /* TXC input */
+
+	port->rxs = rxs;
+	port->txs = txs;
+	sca_out(rxs, msci + RXS, card);
+	sca_out(txs, msci + TXS, card);
+	sca_set_port(port);
+}
+
+
+
+static int t9xx_open(struct net_device *dev)
+{
+	port_t *port = dev_to_port(dev);
+
+	int result = hdlc_open(dev);
+	if (result)
+		return result;
+
+	sca_open(dev);
+	t9xx_set_iface(port);
+	sca_flush(port_to_card(port));
+	return 0;
+}
+
+
+
+static int t9xx_close(struct net_device *dev)
+{
+	sca_close(dev);
+	sca_flush(port_to_card(dev_to_port(dev)));
+	hdlc_close(dev);
+	return 0;
+}
+
+
+
+static int t9xx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	const size_t size = sizeof(te1_settings);
+	te1_settings new_line, *line = ifr->ifr_settings.ifs_ifsu.te1;
+	port_t *port = dev_to_port(dev);
+
+#ifdef DEBUG_RINGS
+	if (cmd == SIOCDEVPRIVATE) {
+		sca_dump_rings(dev);
+		return 0;
+	}
+#endif
+	if (cmd != SIOCWANDEV)
+		return hdlc_ioctl(dev, ifr, cmd);
+
+	switch(ifr->ifr_settings.type) {
+	case IF_GET_IFACE:
+		if (port->dsbase)
+			ifr->ifr_settings.type = IF_IFACE_E1;
+		else
+			ifr->ifr_settings.type = IF_IFACE_V35;
+		if (ifr->ifr_settings.size < size) {
+			ifr->ifr_settings.size = size; /* data size wanted */
+			return -ENOBUFS;
+		}
+		if (copy_to_user(line, &port->settings, size))
+			return -EFAULT;
+		return 0;
+
+	case IF_IFACE_E1:
+	case IF_IFACE_V35:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if (copy_from_user(&new_line, line, size))
+			return -EFAULT;
+
+		if (new_line.clock_type != CLOCK_EXT)
+			return -EINVAL;	/* No such clock setting */
+
+		if (new_line.loopback > 3)
+			return -EINVAL;
+
+		memcpy(&port->settings, &new_line, size); /* Update settings */
+		t9xx_set_iface(port);
+		sca_flush(port_to_card(port));
+		return 0;
+
+	default:
+		return hdlc_ioctl(dev, ifr, cmd);
+	}
+}
+
+
+
+static void t9xx_pci_remove_one(struct pci_dev *pdev)
+{
+	int i, ports;
+	card_t *card = pci_get_drvdata(pdev);
+
+	if ((pdev->subsystem_device == PCI_DEVICE_ID_TAHOE932) ||
+	    (pdev->subsystem_device == PCI_DEVICE_ID_TAHOE972))
+		ports = 2;
+	else
+		ports = 1;
+	for(i = 0; i < ports; i++)
+		if (card->ports[i].card) {
+			struct net_device *dev = port_to_dev(&card->ports[i]);
+			unregister_hdlc_device(dev);
+		}
+
+	if (card->rambase)
+		iounmap(card->rambase);
+	if (card->scabase)
+		iounmap(card->scabase);
+	if (card->plxbase)
+		iounmap(card->plxbase);
+
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+	if (card->ports[0].dev)
+		free_netdev(card->ports[0].dev);
+	if ((ports == 2) && (card->ports[1].dev))
+		free_netdev(card->ports[1].dev);
+	kfree(card);
+}
+
+static void ds21554_update_licr(port_t *port)
+{
+	port->dsbase->licr = DEFAULT_LICR | (port->settings.egl << 4) | (port->g703_on == 0);
+}
+
+static void ds21554_update_registers(port_t *port)
+{
+	ds21554_t	*ds = port->dsbase;
+
+	if (port->settings.slot_map == 0xffffffff) {
+		/* Unframed */
+		ds->ccr1 = 0x08 | (port->g703_coding << 6) | (port->g703_coding << 2);
+		ds->tcr1 = 0x40;
+		ds->tcr2 = 0x00;
+		ds->ccr2 = 0x80; //84
+		ds->tir1 = 0; ds->tir2 = 0; ds->tir3 = 0; ds->tir4 = 0;
+		ds->tcc1 = 0; ds->tcc2 = 0; ds->tcc3 = 0; ds->tcc4 = 0;
+		ds->rcc1 = 0; ds->rcc2 = 0; ds->rcc3 = 0; ds->rcc4 = 0;
+		ds->rcbr1 = 0xff; ds->rcbr2 = 0xff; 
+		ds->rcbr3 = 0xff; ds->rcbr4 = 0xff; 
+		ds->tcbr1 = 0xff; ds->tcbr2 = 0xff; 
+		ds->tcbr3 = 0xff; ds->tcbr4 = 0xff; 
+		ds->tsacr = 0x00;
+		ds->tdc1 = 0x00;
+
+		ds->rcr2 = 0x04;
+		ds->ccr3 = 0x02;
+
+		ds->ccr6 = 0x03;	/* elastic buffers reset */
+		udelay(1000);
+		ds->ccr6 = 0x00;	/* elastic buffers reset */
+
+		ds->ccr5 = 0x60;	/* elastic buffers align */
+		udelay(1000);
+		ds->ccr5 = 0x00;
+	} else {
+		ds->ccr1 = 0x08 | (port->g703_coding << 6) | (port->g703_coding << 2)
+		                | (port->settings.crc4 << 4) | (port->settings.crc4);
+		ds->tcr1 = 0x00;
+		ds->ccr2 = 0x94;	/* Automatic alarm generation */
+
+		/* Receive channels */
+		ds->rcbr1 = port->settings.slot_map & 0xff;
+		ds->rcbr2 = (port->settings.slot_map >> 8) & 0xff;
+		ds->rcbr3 = (port->settings.slot_map >> 16) & 0xff;
+		ds->rcbr4 = (port->settings.slot_map >> 24) & 0xff;
+	
+		/* Transmit channels */
+		ds->tcbr1 = port->settings.slot_map & 0xff;
+		ds->tcbr2 = (port->settings.slot_map >> 8) & 0xff;
+		ds->tcbr3 = (port->settings.slot_map >> 16) & 0xff;
+		ds->tcbr4 = (port->settings.slot_map >> 24) & 0xff;
+
+		/* Transmit idle */
+		/* (remaining timeslots are filled with idle code) */
+		ds->tir1 = ~port->settings.slot_map & 0xfe;	/* Slot 0 is never idle */
+		ds->tir2 = (~port->settings.slot_map >> 8) & 0xff;
+		ds->tir3 = (~port->settings.slot_map >> 16) & 0xff;
+		ds->tir4 = (~port->settings.slot_map >> 24) & 0xff;
+		ds->rcr2 = 0x06;	/* RSYSCLK = 2048, rx elastic store enabled */
+		ds->ccr3 = 0x82;	/* TSYSCLK = 2048, tx elastic store enabled */
+
+		ds->ccr6 = 0x07;	/* elastic buffers reset */
+		udelay(1000);
+		ds->ccr6 = 0x04;	/* elastic buffers reset */
+
+		ds->ccr5 = 0x60;	/* elastic buffers align */
+		udelay(1000);
+		ds->ccr5 = 0x00;
+	}
+}
+
+void init_ds21554(port_t *port)
+{
+	ds21554_t	*ds = port->dsbase;
+	
+	ds->ccr2 = 0x04;
+	udelay(1000);
+	ds->ccr5 = 0x80;	/* Line Interface Reset */
+	udelay(1000);
+
+	ds->ccr5 = 0xe0;	/* Elastic Buffers Reset */
+	udelay(1000);
+	ds->ccr5 = 0x00;
+	ds->ccr6 = 0x04;	/* TCLK from RCLK */
+	ds->tcr2 = 0x00;
+	ds21554_update_licr(port);
+
+	/* Setup HDB3, CRC4, CAS/CCS, G.802 */
+	ds21554_update_registers(port);
+
+	ds->ccr2 = 0x94;	/* Automatic alarm generation */
+
+	ds->taf = 0x1b;
+	ds->tnaf = 0x40;
+
+	ds21554_update_registers(port);
+
+	ds->tidr = port->g703_idlecode;
+
+//	ds->ccr4 |= 0x40;
+}
+
+
+static int __devinit t9xx_pci_init_one(struct pci_dev *pdev,
+					 const struct pci_device_id *ent)
+{
+	card_t *card;
+	u8 rev_id, tahoe97x = 0;
+	u32 *p;
+	int i;
+	u32 ramsize;
+	u32 ramphys;		/* buffer memory base */
+	u32 scaphys;		/* SCA memory base */
+	u32 plxphys;		/* PLX registers memory base */
+
+#ifndef MODULE
+        static int printed_version;
+        if (!printed_version++)
+                printk(KERN_INFO "%s\n", version);
+#endif
+
+	i = pci_enable_device(pdev);
+	if (i)
+		return i;
+
+	i = pci_request_regions(pdev, "Tahoe9xx");
+	if (i) {
+		pci_disable_device(pdev);
+		return i;
+	}
+
+	card = kmalloc(sizeof(card_t), GFP_KERNEL);
+	if (card == NULL) {
+		printk(KERN_ERR "%s: unable to allocate memory\n", card->dev_name);
+		pci_release_regions(pdev);
+		pci_disable_device(pdev);
+		return -ENOBUFS;
+	}
+	memset(card, 0, sizeof(card_t));
+	pci_set_drvdata(pdev, card);
+	card->ports[0].dev = alloc_hdlcdev(&card->ports[0]);
+	card->ports[1].dev = alloc_hdlcdev(&card->ports[1]);
+	if (!card->ports[0].dev || !card->ports[1].dev) {
+		printk(KERN_ERR "tahoe9xx: unable to allocate memory\n");
+		t9xx_pci_remove_one(pdev);
+		return -ENOMEM;
+	}
+
+	sprintf(card->dev_name, "Tahoe");
+	switch (pdev->subsystem_device) {
+		case PCI_DEVICE_ID_TAHOE931:
+			strcat(card->dev_name, "931");
+			card->no_ports = 1;
+			break;
+		case PCI_DEVICE_ID_TAHOE932:
+			strcat(card->dev_name, "932");
+			card->no_ports = 2;
+			break;
+		case PCI_DEVICE_ID_TAHOE971:
+			strcat(card->dev_name, "971");
+			tahoe97x = 1;
+			card->no_ports = 1;
+			break;
+		case PCI_DEVICE_ID_TAHOE972:
+			strcat(card->dev_name, "972");
+			tahoe97x = 1;
+			card->no_ports = 2;
+			break;
+		default:
+			strcat(card->dev_name, "9xx");
+			card->no_ports = 0;
+			break;
+	}
+
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
+	if (pci_resource_len(pdev, 0) != TAHOE9XX_PLX_SIZE ||
+	    pci_resource_len(pdev, 2) != TAHOE9XX_SCA_SIZE ||
+	    pci_resource_len(pdev, 3) < 16384) {
+		printk(KERN_ERR "%s: invalid card EEPROM parameters\n", card->dev_name);
+		t9xx_pci_remove_one(pdev);
+		return -EFAULT;
+	}
+
+	plxphys = pci_resource_start(pdev,0) & PCI_BASE_ADDRESS_MEM_MASK;
+	card->plxbase = ioremap(plxphys, TAHOE9XX_PLX_SIZE);
+
+	scaphys = pci_resource_start(pdev,2) & PCI_BASE_ADDRESS_MEM_MASK;
+	card->scabase = ioremap(scaphys, TAHOE9XX_SCA_SIZE);
+
+	ramphys = pci_resource_start(pdev,3) & PCI_BASE_ADDRESS_MEM_MASK;
+	card->rambase = ioremap(ramphys, pci_resource_len(pdev,3));
+
+	if (tahoe97x) {
+		for (i=0; i < card->no_ports; i++) {
+			card->ports[i].dsphys = pci_resource_start(pdev,4+i) & PCI_BASE_ADDRESS_MEM_MASK;
+			card->ports[i].dsbase = (ds21554_t *)ioremap(card->ports[i].dsphys, pci_resource_len(pdev,4+i));
+		}
+	} else {
+		for (i=0; i < card->no_ports; i++)
+			card->ports[i].dsbase = (ds21554_t *)0;
+	}
+
+	if (card->plxbase == NULL ||
+	    card->scabase == NULL ||
+	    card->rambase == NULL) {
+		printk(KERN_ERR "tahoe9xx: ioremap() failed\n");
+		t9xx_pci_remove_one(pdev);
+	}
+
+	/* Reset PLX */
+	p = &card->plxbase->init_ctrl;
+	writel(readl(p) | 0x40000000, p);
+	readl(p);		/* Flush the write - do not use sca_flush */
+	udelay(1);
+
+	writel(readl(p) & ~0x40000000, p);
+	readl(p);		/* Flush the write - do not use sca_flush */
+	udelay(1);
+
+	ramsize = sca_detect_ram(card, card->rambase,
+				pci_resource_len(pdev,3));
+
+	/* number of TX + RX buffers for one port - this is dual port card */
+	i = ramsize / (2 * (sizeof(pkt_desc) + HDLC_MAX_MRU));
+	card->tx_ring_buffers = min(i / 2, MAX_TX_BUFFERS);
+	card->rx_ring_buffers = i - card->tx_ring_buffers;
+
+	card->buff_offset = 2 * sizeof(pkt_desc) * (card->tx_ring_buffers +
+						    card->rx_ring_buffers);
+
+	printk(KERN_INFO "%s: %u KB RAM at 0x%x, IRQ%u, using %u TX +"
+	       " %u RX packets rings\n", card->dev_name, ramsize / 1024,
+	       ramphys, pdev->irq,
+	       card->tx_ring_buffers, card->rx_ring_buffers);
+	if (tahoe97x) {
+		for (i=0; i < card->no_ports; i++) {
+			/* Make sure DS21554 is there */
+			card->ports[i].dsbase->idr = 0x00;
+			card->ports[i].dsbase->tc1 = 0xaa;
+			card->ports[i].dsbase->rc1 = 0x55;
+			if (((card->ports[i].dsbase->idr & 0xf0) == 0xa0) && (card->ports[i].dsbase->tc1 == 0xaa) && (card->ports[i].dsbase->rc1 == 0x55)) {
+				printk(KERN_INFO "%s: DS21554 (port %d) detected at 0x%x\n", card->dev_name, i, card->ports[i].dsphys);
+				/* Clear registers */
+				memset(card->ports[i].dsbase, 0, 256);
+				/* Default settings */
+				card->ports[i].g703_on = 1;
+				card->ports[i].settings.egl = 0;
+				card->ports[i].g703_coding = G703_HDB3;
+				card->ports[i].g703_idlecode = 0x54;
+				card->ports[i].settings.crc4 = 1;
+				/* Unframed */
+				card->ports[i].settings.slot_map = 0xffffffff;
+				init_ds21554(&card->ports[i]);
+			} else
+				printk(KERN_INFO "%s: DS21554 (port %d) test failed!\n", card->dev_name, i);
+		}
+	}
+
+	if (card->tx_ring_buffers < 1) {
+		printk(KERN_ERR "%s: RAM test failed\n", card->dev_name);
+		t9xx_pci_remove_one(pdev);
+		return -EFAULT;
+	}
+
+	/* Enable interrupts on the PCI bridge */
+	p = &card->plxbase->intr_ctrl_stat;
+	writew(readw(p) | 0x0040, p);
+
+	/* Allocate IRQ */
+	if(request_irq(pdev->irq, sca_intr, SA_SHIRQ, devname, card)) {
+		printk(KERN_WARNING "%s: could not allocate IRQ%d.\n", card->dev_name,
+		       pdev->irq);
+		t9xx_pci_remove_one(pdev);
+		return -EBUSY;
+	}
+	card->irq = pdev->irq;
+
+	sca_init(card, 0);
+
+	for(i = 0; i < card->no_ports; i++) {
+		port_t *port = &card->ports[i];
+		struct net_device *dev = port_to_dev(port);
+		hdlc_device *hdlc = dev_to_hdlc(dev);
+		port->phy_node = i;
+
+		spin_lock_init(&port->lock);
+		SET_MODULE_OWNER(dev);
+		dev->irq = card->irq;
+		dev->mem_start = ramphys;
+		dev->mem_end = ramphys + ramsize - 1;
+		dev->tx_queue_len = 50;
+		dev->do_ioctl = t9xx_ioctl;
+		dev->open = t9xx_open;
+		dev->stop = t9xx_close;
+		hdlc->attach = sca_attach;
+		hdlc->xmit = sca_xmit;
+		port->settings.clock_type = CLOCK_EXT;
+		port->card = card;
+		if(register_hdlc_device(dev)) {
+			printk(KERN_ERR "%s: unable to register hdlc "
+			       "device\n", card->dev_name);
+			port->card = NULL;
+			t9xx_pci_remove_one(pdev);
+			return -ENOBUFS;
+		}
+		sca_init_sync_port(port);	/* Set up SCA memory */
+
+		printk(KERN_INFO "%s: %s node %d\n",
+		       dev->name, card->dev_name, port->phy_node);
+	}
+
+	sca_flush(card);
+	return 0;
+}
+
+
+
+static struct pci_device_id t9xx_pci_tbl[] __devinitdata = {
+        { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, 
+          PCI_VENDOR_ID_TAHOE, PCI_ANY_ID,
+          0, 0, 0 },
+        { 0, }
+};
+
+static struct pci_driver t9xx_pci_driver = {
+        name:           "Tahoe9xx",
+        id_table:       t9xx_pci_tbl,
+        probe:          t9xx_pci_init_one,
+        remove:         t9xx_pci_remove_one,
+};
+
+static int __init t9xx_init_module(void)
+{
+#ifdef MODULE
+        printk(KERN_INFO "%s\n", version);
+#endif
+	return pci_module_init(&t9xx_pci_driver);
+}
+
+
+
+static void __exit t9xx_cleanup_module(void)
+{
+	pci_unregister_driver(&t9xx_pci_driver);
+}
+
+MODULE_AUTHOR("Piotr Kaczmarzyk <piotr@tahoe.pl>");
+MODULE_DESCRIPTION("Tahoe 9xx serial port driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(pci, t9xx_pci_tbl);
+module_init(t9xx_init_module);
+module_exit(t9xx_cleanup_module);
--- linux/drivers/net/wan/Kconfig	2003-03-06 14:56:13.000000000 +0100
+++ linux/drivers/net/wan/Kconfig	2003-03-30 22:37:04.000000000 +0200
@@ -331,6 +331,21 @@
 comment "X.25/LAPB support is disabled"
 	depends on WAN && HDLC && (LAPB!=m || HDLC!=m) && LAPB!=y
 
+config TAHOE9XX
+	tristate "Tahoe 9xx support"
+	depends on HDLC && PCI
+	help
+	  This driver is for Tahoe 931/932/971/972 cards
+	  If you have such a card, say Y or M here and see
+	  <http://www.tahoe.pl/>
+
+	  If you want to compile the driver as a module ( = code which can be
+	  inserted in and removed from the running kernel whenever you want),
+	  say M here and read <file:Documentation/modules.txt>.  The module
+	  will be called tahoe9xx.o.
+
+	  If unsure, say N here.
+
 config PCI200SYN
 	tristate "Goramo PCI200SYN support"
 	depends on HDLC && PCI
--- linux/include/linux/hdlc/ioctl.h	1970-01-01 01:00:00.000000000 +0100
+++ linux/include/linux/hdlc/ioctl.h	2003-07-31 14:46:58.000000000 +0200
@@ -12,6 +12,8 @@
 	unsigned int clock_type; /* internal, external, TX-internal etc. */
 	unsigned short loopback;
 	unsigned int slot_map;
+ 	unsigned short crc4;
+	unsigned short egl;
 } te1_settings;                  /* T1, E1 */
 
 typedef struct {
