diff -ur --new-file old/linux/arch/sparc/config.in new/linux/arch/sparc/config.in
--- old/linux/arch/sparc/config.in	Thu Jan 14 19:29:28 1999
+++ new/linux/arch/sparc/config.in	Thu Jun  3 00:42:16 1999
@@ -170,6 +170,9 @@
 #		bool 'FDDI driver support' CONFIG_FDDI
 #		if [ "$CONFIG_FDDI" = "y" ]; then
 #		fi
+		if [ "$CONFIG_ATM" = "y" ]; then
+		  source drivers/atm/Config.in
+		fi
 	fi
 	endmenu
 fi
diff -ur --new-file old/linux/drivers/atm/Config.in new/linux/drivers/atm/Config.in
--- old/linux/drivers/atm/Config.in	Thu Jun  3 00:40:49 1999
+++ new/linux/drivers/atm/Config.in	Thu Jun  3 00:42:17 1999
@@ -31,6 +31,9 @@
 #    bool '  Enable extended debugging' CONFIG_ATM_TNETA1570_DEBUG n
 #  fi
   tristate 'IDT 77201 (NICStAR)' CONFIG_ATM_NICSTAR
+  if [ "$CONFIG_ATM_NICSTAR" != "n" ]; then
+    bool '  Use suni PHY driver' CONFIG_ATM_NICSTAR_USE_SUNI
+  fi
   tristate 'Madge Ambassador (Collage PCI 155 Server)' CONFIG_ATM_AMBASSADOR
   if [ "$CONFIG_ATM_AMBASSADOR" != "n" ]; then
     bool '  Enable debugging messages' CONFIG_ATM_AMBASSADOR_DEBUG
diff -ur --new-file old/linux/drivers/atm/Makefile new/linux/drivers/atm/Makefile
--- old/linux/drivers/atm/Makefile	Thu Jun  3 00:40:49 1999
+++ new/linux/drivers/atm/Makefile	Thu Jun  3 00:42:17 1999
@@ -38,9 +38,15 @@
 
 ifeq ($(CONFIG_ATM_NICSTAR),y)
 L_OBJS += nicstar.o
+  ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y)
+  LX_OBJS += suni.o
+  endif
 else
   ifeq ($(CONFIG_ATM_NICSTAR),m)
   M_OBJS += nicstar.o
+    ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y)
+    MX_OBJS += suni.o
+    endif
   endif
 endif
 
diff -ur --new-file old/linux/drivers/atm/eni.c new/linux/drivers/atm/eni.c
--- old/linux/drivers/atm/eni.c	Thu Jun  3 00:40:49 1999
+++ new/linux/drivers/atm/eni.c	Thu Jun  3 00:42:17 1999
@@ -30,6 +30,11 @@
 #include "suni.h"
 #include "eni.h"
 
+#ifndef __i386__
+#ifndef ioremap_nocache
+#define ioremap_nocache(X,Y) ioremap(X,Y)
+#endif 
+#endif
 
 /*
  * TODO:
@@ -91,7 +96,8 @@
  */
 
 #define NULLCHECK(x) \
-  if ((unsigned long) (x) < 0x30) printk(KERN_CRIT #x "==0x%x\n", (int) (x))
+	if ((unsigned long) (x) < 0x30) \
+		printk(KERN_CRIT #x "==0x%lx\n",(unsigned long) (x))
 
 /*
  * Very extensive activity logging. Greatly improves bug detection speed but
@@ -152,6 +158,10 @@
 
 static u32 *zeroes = NULL; /* aligned "magic" zeroes */
 
+/* Read/write registers on card */
+#define eni_in(r)	readl(eni_dev->reg+(r)*4)
+#define eni_out(v,r)	writel((v),eni_dev->reg+(r)*4)
+
 
 /*-------------------------------- utilities --------------------------------*/
 
@@ -179,12 +189,12 @@
 	printk(KERN_NOTICE "TX buffers\n");
 	for (i = 0; i < NR_CHAN; i++)
 		if (eni_dev->tx[i].send)
-			printk(KERN_NOTICE "  TX %d @ 0x%p: %ld\n",i,
+			printk(KERN_NOTICE "  TX %d @ 0x%lx: %ld\n",i,
 			    eni_dev->tx[i].send,eni_dev->tx[i].words*4);
 	printk(KERN_NOTICE "RX buffers\n");
 	for (i = 0; i < 1024; i++)
 		if (eni_dev->rx_map[i] && ENI_VCC(eni_dev->rx_map[i])->rx)
-			printk(KERN_NOTICE "  RX %d @ 0x%p: %ld\n",i,
+			printk(KERN_NOTICE "  RX %d @ 0x%lx: %ld\n",i,
 			    ENI_VCC(eni_dev->rx_map[i])->recv,
 			    ENI_VCC(eni_dev->rx_map[i])->words*4);
 	printk(KERN_NOTICE "----\n");
@@ -255,8 +265,7 @@
 	*size = 1 << order;
 	eni_put_free(eni_dev,start+*size,(1 << best_order)-*size);
 	DPRINTK("%ld bytes (order %d) at 0x%lx\n",*size,order,start);
-	for (i = (*size >> 2)-1; i >= 0; i--) /* never leak data */
-		((unsigned long *) start)[i] = 0;
+	memset_io(start,0,*size);       /* never leak data */
 	/*dump_mem(eni_dev);*/
 	return start;
 }
@@ -305,12 +314,14 @@
 static void rx_ident_err(struct atm_vcc *vcc)
 {
 	struct atm_dev *dev;
+	struct eni_dev *eni_dev;
 	struct eni_vcc *eni_vcc;
 
 	dev = vcc->dev;
+	eni_dev = ENI_DEV(dev);
 	/* immediately halt adapter */
-	writel(readl(ENI_DEV(dev)->reg+MID_MC_S) & ~(MID_DMA_ENABLE |
-	    MID_TX_ENABLE | MID_RX_ENABLE),ENI_DEV(dev)->reg+MID_MC_S);
+	eni_out(eni_in(MID_MC_S) &
+	    ~(MID_DMA_ENABLE | MID_TX_ENABLE | MID_RX_ENABLE),MID_MC_S);
 	/* dump useful information */
 	eni_vcc = ENI_VCC(vcc);
 	printk(KERN_ALERT DEV_LABEL "(itf %d): driver error - RX ident "
@@ -319,7 +330,7 @@
 	    eni_vcc->rxing,eni_vcc->words);
 	printk(KERN_ALERT "  host descr 0x%lx, rx pos 0x%lx, descr value "
 	    "0x%x\n",eni_vcc->descr,eni_vcc->rx_pos,
-	    readl(eni_vcc->recv+eni_vcc->descr));
+	    (unsigned) readl(eni_vcc->recv+eni_vcc->descr*4));
 	printk(KERN_ALERT "  last 0x%p, servicing %d\n",eni_vcc->last,
 	    eni_vcc->servicing);
 	EVENT("---dump ends here---\n",0,0);
@@ -441,8 +452,8 @@
 	}
 	dma[j-2] |= MID_DMA_END;
 	j = j >> 1;
-	dma_wr = readl(eni_dev->reg+MID_DMA_WR_RX);
-	dma_rd = readl(eni_dev->reg+MID_DMA_RD_RX);
+	dma_wr = eni_in(MID_DMA_WR_RX);
+	dma_rd = eni_in(MID_DMA_RD_RX);
 	/*
 	 * Can I move the dma_wr pointer by 2j+1 positions without overwriting
 	 * data that hasn't been read (position of dma_rd) yet ?
@@ -454,8 +465,8 @@
 		return -1;
 	}
         for (i = 0; i < j; i++) {
-		writel(dma[i*2],eni_dev->rx_dma+dma_wr*2);
-		writel(dma[i*2+1],eni_dev->rx_dma+dma_wr*2+1);
+		writel(dma[i*2],eni_dev->rx_dma+dma_wr*8);
+		writel(dma[i*2+1],eni_dev->rx_dma+dma_wr*8+4);
 		dma_wr = (dma_wr+1) & (NR_DMA_RX-1);
         }
 	if (skb) {
@@ -465,7 +476,7 @@
 rx_enqueued++;
 	}
 	eni_vcc->descr = here;
-	writel(dma_wr,eni_dev->reg+MID_DMA_WR_RX);
+	eni_out(dma_wr,MID_DMA_WR_RX);
 	return 0;
 }
 
@@ -497,7 +508,7 @@
 
 	DPRINTK(">rx_aal0\n");
 	eni_vcc = ENI_VCC(vcc);
-	descr = readl(eni_vcc->recv+eni_vcc->descr);
+	descr = readl(eni_vcc->recv+eni_vcc->descr*4);
 	if ((descr & MID_RED_IDEN) != (MID_RED_RX_ID << MID_RED_SHIFT)) {
 		rx_ident_err(vcc);
 		return 1;
@@ -539,7 +550,7 @@
 	EVENT("rx_aal5\n",0,0);
 	DPRINTK(">rx_aal5\n");
 	eni_vcc = ENI_VCC(vcc);
-	descr = readl(eni_vcc->recv+eni_vcc->descr);
+	descr = readl(eni_vcc->recv+eni_vcc->descr*4);
 	if ((descr & MID_RED_IDEN) != (MID_RED_RX_ID << MID_RED_SHIFT)) {
 		rx_ident_err(vcc);
 		return 1;
@@ -570,8 +581,9 @@
 	else {
 		size = (descr & MID_RED_COUNT)*(ATM_CELL_PAYLOAD >> 2);
 		DPRINTK("size=%ld\n",size);
-		length = readl(eni_vcc->recv+((eni_vcc->descr+size-1) &
-		    (eni_vcc->words-1))) & 0xffff; /* -trailer(2)+header(1) */
+		length = readl(eni_vcc->recv+(((eni_vcc->descr+size-1) &
+		    (eni_vcc->words-1)))*4) & 0xffff;
+				/* -trailer(2)+header(1) */
 		if (length && length <= (size << 2)-8 && length <=
 		  ATM_MAX_AAL5_PDU) eff = (length+3) >> 2;
 		else {				 /* ^ trailer length (8) */
@@ -608,19 +620,18 @@
 
 static inline int rx_vcc(struct atm_vcc *vcc)
 {
-	u32 *vci_dsc;
+	unsigned long vci_dsc,tmp;
 	struct eni_vcc *eni_vcc;
-	unsigned long tmp;
 
 	eni_vcc = ENI_VCC(vcc);
-	vci_dsc = ENI_DEV(vcc->dev)->vci+vcc->vci*4;
+	vci_dsc = ENI_DEV(vcc->dev)->vci+vcc->vci*16;
 	EVENT("rx_vcc(1)\n",0,0);
-	while (eni_vcc->descr != (tmp = (readl(vci_dsc+1) & MID_VCI_DESCR) >>
+	while (eni_vcc->descr != (tmp = (readl(vci_dsc+4) & MID_VCI_DESCR) >>
 	    MID_VCI_DESCR_SHIFT)) {
 		EVENT("rx_vcc(2: host dsc=0x%lx, nic dsc=0x%lx)\n",
 		    eni_vcc->descr,tmp);
 		DPRINTK("CB_DESCR %ld REG_DESCR %d\n",ENI_VCC(vcc)->descr,
-		    ((readl(vci_dsc+1) & MID_VCI_DESCR) >>
+		    (((unsigned) readl(vci_dsc+4) & MID_VCI_DESCR) >>
 		    MID_VCI_DESCR_SHIFT));
 		if (ENI_VCC(vcc)->rx(vcc)) return 1;
 	}
@@ -632,12 +643,12 @@
 	 * follows. So we have to loop again to be sure.
 	 */
 	EVENT("rx_vcc(3)\n",0,0);
-	while (ENI_VCC(vcc)->descr != (tmp = (readl(vci_dsc+1) & MID_VCI_DESCR)
+	while (ENI_VCC(vcc)->descr != (tmp = (readl(vci_dsc+4) & MID_VCI_DESCR)
 	    >> MID_VCI_DESCR_SHIFT)) {
 		EVENT("rx_vcc(4: host dsc=0x%lx, nic dsc=0x%lx)\n",
 		    eni_vcc->descr,tmp);
 		DPRINTK("CB_DESCR %ld REG_DESCR %d\n",ENI_VCC(vcc)->descr,
-		    ((readl(vci_dsc+1) & MID_VCI_DESCR) >>
+		    (((unsigned) readl(vci_dsc+4) & MID_VCI_DESCR) >>
 		    MID_VCI_DESCR_SHIFT));
 		if (ENI_VCC(vcc)->rx(vcc)) return 1;
 	}
@@ -676,8 +687,8 @@
 
 	DPRINTK(">get_service\n");
 	eni_dev = ENI_DEV(dev);
-	while (readl(eni_dev->reg+MID_SERV_WRITE) != eni_dev->serv_read) {
-		vci = readl(eni_dev->service+eni_dev->serv_read);
+	while (eni_in(MID_SERV_WRITE) != eni_dev->serv_read) {
+		vci = readl(eni_dev->service+eni_dev->serv_read*4);
 		eni_dev->serv_read = (eni_dev->serv_read+1) & (NR_SERVICE-1);
 		vcc = eni_dev->rx_map[vci & 1023];
 		if (!vcc) {
@@ -718,7 +729,7 @@
 	struct eni_vcc *eni_vcc;
 	struct atm_vcc *vcc;
 	struct sk_buff *skb;
-	u32 *vci_dsc;
+	unsigned long vci_dsc;
 	int first;
 
 	eni_dev = ENI_DEV(dev);
@@ -739,9 +750,9 @@
 		vcc = ATM_SKB(skb)->vcc;
 		eni_vcc = ENI_VCC(vcc);
 		first = 0;
-		vci_dsc = eni_dev->vci+(vcc->vci << 2);
+		vci_dsc = eni_dev->vci+vcc->vci*16;
 		if (!EEPMOK(eni_vcc->rx_pos,ENI_PRV_SIZE(skb),
-		    (readl(vci_dsc+1) & MID_VCI_READ) >> MID_VCI_READ_SHIFT,
+		    (readl(vci_dsc+4) & MID_VCI_READ) >> MID_VCI_READ_SHIFT,
 		    eni_vcc->words)) {
 			EVENT("requeuing\n",0,0);
 			skb_queue_head(&eni_dev->rx_queue,skb);
@@ -780,8 +791,8 @@
 	if (size > MID_MAX_BUF_SIZE && vcc->qos.rxtp.max_sdu <=
 	    MID_MAX_BUF_SIZE)
 		size = MID_MAX_BUF_SIZE;
-	eni_vcc->recv = (u32 *) eni_alloc_mem(eni_dev,&size);
-	DPRINTK("rx at 0x%p\n",eni_vcc->recv);
+	eni_vcc->recv = eni_alloc_mem(eni_dev,&size);
+	DPRINTK("rx at 0x%lx\n",eni_vcc->recv);
 	eni_vcc->words = size >> 2;
 	if (!eni_vcc->recv) return -ENOBUFS;
 	eni_vcc->rx = vcc->qos.aal == ATM_AAL5 ? rx_aal5 : rx_aal0;
@@ -796,7 +807,7 @@
 
 static int open_rx_second(struct atm_vcc *vcc)
 {
-	u32 *here;
+	unsigned long here;
 	struct eni_dev *eni_dev;
 	struct eni_vcc *eni_vcc;
 	unsigned long size;
@@ -807,19 +818,19 @@
 	eni_vcc = ENI_VCC(vcc);
 	if (!eni_vcc->rx) return 0;
 	/* set up VCI descriptor */
-	here = eni_dev->vci+(vcc->vci << 2);
-	DPRINTK("loc 0x%x\n",eni_vcc->recv-eni_dev->ram);
+	here = eni_dev->vci+vcc->vci*16;
+	DPRINTK("loc 0x%x\n",(unsigned) (eni_vcc->recv-eni_dev->ram)/4);
 	size = eni_vcc->words >> 8;
 	for (order = -1; size; order++) size >>= 1;
-	writel(0,here+1); /* descr, read = 0 */
-	writel(0,here+2); /* write, state, count = 0 */
+	writel(0,here+4); /* descr, read = 0 */
+	writel(0,here+8); /* write, state, count = 0 */
 	if (eni_dev->rx_map[vcc->vci])
 		printk(KERN_CRIT DEV_LABEL "(itf %d): BUG - VCI %d already "
 		    "in use\n",vcc->dev->number,vcc->vci);
 	eni_dev->rx_map[vcc->vci] = vcc; /* now it counts */
 	writel(((vcc->qos.aal != ATM_AAL5 ? MID_MODE_RAW : MID_MODE_AAL5) <<
 	    MID_VCI_MODE_SHIFT) | MID_VCI_PTI_MODE |
-	    (((eni_vcc->recv-eni_dev->ram) >> MID_LOC_SKIP) <<
+	    (((eni_vcc->recv-eni_dev->ram) >> (MID_LOC_SKIP+2)) <<
 	    MID_VCI_LOCATION_SHIFT) | (order << MID_VCI_SIZE_SHIFT),here);
 	return 0;
 }
@@ -827,17 +838,16 @@
 
 static void close_rx(struct atm_vcc *vcc)
 {
-	u32 *here;
+	unsigned long here,flags;
 	struct eni_dev *eni_dev;
 	struct eni_vcc *eni_vcc;
-	unsigned long flags;
 	u32 tmp;
 
 	eni_vcc = ENI_VCC(vcc);
 	if (!eni_vcc->rx) return;
 	eni_dev = ENI_DEV(vcc->dev);
 	if (vcc->vpi != ATM_VPI_UNSPEC && vcc->vci != ATM_VCI_UNSPEC) {
-		here = eni_dev->vci+(vcc->vci << 2);
+		here = eni_dev->vci+vcc->vci*16;
 		/* block receiver */
 		writel((readl(here) & ~MID_VCI_MODE) | (MID_MODE_TRASH <<
 		    MID_VCI_MODE_SHIFT),here);
@@ -859,8 +869,9 @@
 			    eni_vcc->rxing);
 			sleep_on(&eni_dev->rx_wait);
 		}
-		while (eni_vcc->rx_pos != (tmp = eni_dev->vci[vcc->vci*4+1] &
-		    MID_VCI_READ) >> MID_VCI_READ_SHIFT) {
+		while (eni_vcc->rx_pos != (tmp =
+		     readl(eni_dev->vci+vcc->vci*16+4) & MID_VCI_READ)>>
+		     MID_VCI_READ_SHIFT) {
 			EVENT("drain discard (host 0x%lx, nic 0x%lx)\n",
 			    eni_vcc->rx_pos,tmp);
 			printk(KERN_INFO "draining RX: host 0x%lx, nic 0x%x\n",
@@ -869,8 +880,7 @@
 		}
 		restore_flags(flags);
 	}
-	eni_free_mem(eni_dev,(unsigned long) eni_vcc->recv,
-	    eni_vcc->words << 2);
+	eni_free_mem(eni_dev,eni_vcc->recv,eni_vcc->words << 2);
 	eni_vcc->rx = NULL;
 }
 
@@ -892,8 +902,8 @@
 	eni_dev->slow = eni_dev->last_slow = NULL;
 	eni_dev->rx_wait = NULL;
 	skb_queue_head_init(&eni_dev->rx_queue);
-	eni_dev->serv_read = readl(eni_dev->reg+MID_SERV_WRITE);
-	writel(0,eni_dev->reg+MID_DMA_WR_RX);
+	eni_dev->serv_read = eni_in(MID_SERV_WRITE);
+	eni_out(0,MID_DMA_WR_RX);
 	return 0;
 }
 
@@ -1057,14 +1067,14 @@
 	 * the manual calls "too close".
 	 */
 	if (!NEPMOK(tx->tx_pos,size+TX_GAP,
-	    readl(eni_dev->reg+MID_TX_RDPTR(tx->index)),tx->words)) {
-		DPRINTK(DEV_LABEL "(itf %d): TX full (size %ld)\n",
+	    eni_in(MID_TX_RDPTR(tx->index)),tx->words)) {
+		DPRINTK(DEV_LABEL "(itf %d): TX full (size %d)\n",
 		    vcc->dev->number,size);
 		return enq_next;
 	}
 	/* check DMA */
-	dma_wr = readl(eni_dev->reg+MID_DMA_WR_TX);
-	dma_rd = readl(eni_dev->reg+MID_DMA_RD_TX);
+	dma_wr = eni_in(MID_DMA_WR_TX);
+	dma_rd = eni_in(MID_DMA_RD_TX);
 	dma_size = 3; /* JK for descriptor and final fill, plus final size
 			 mis-alignment fix */
 DPRINTK("iovcnt = %d\n",ATM_SKB(skb)->iovcnt);
@@ -1074,7 +1084,7 @@
 		printk(KERN_CRIT DEV_LABEL "(itf %d): needs %d DMA entries "
 		    "(got only %d)\n",vcc->dev->number,dma_size,TX_DMA_BUF);
 	}
-	DPRINTK("dma_wr is %ld, tx_pos is %ld\n",dma_wr,tx->tx_pos);
+	DPRINTK("dma_wr is %d, tx_pos is %ld\n",dma_wr,tx->tx_pos);
 	if (dma_wr != dma_rd && ((dma_rd+NR_DMA_TX-dma_wr) & (NR_DMA_TX-1)) <
 	     dma_size) {
 		printk(KERN_WARNING DEV_LABEL "(itf %d): TX DMA full\n",
@@ -1110,30 +1120,31 @@
 	j++;
 	DPRINTK("DMA at end: %d\n",j);
 	/* store frame */
-	tx->send[tx->tx_pos] = (MID_SEG_TX_ID << MID_SEG_ID_SHIFT) |
+	writel((MID_SEG_TX_ID << MID_SEG_ID_SHIFT) |
 	    (aal5 ? MID_SEG_AAL5 : 0) | (tx->prescaler << MID_SEG_PR_SHIFT) |
 	    (tx->resolution << MID_SEG_RATE_SHIFT) |
-	    (size/(ATM_CELL_PAYLOAD/4));
-/*printk("dsc = 0x%08lx\n",tx->send[tx->tx_pos]);*/
-	tx->send[(tx->tx_pos+1) & (tx->words-1)] = (vcc->vci <<
-	    MID_SEG_VCI_SHIFT) | (aal5 ? 0 : (skb->data[3] & 0xf)) |
-	    (ATM_SKB(skb)->atm_options & ATM_ATMOPT_CLP ? MID_SEG_CLP : 0);
-	DPRINTK("size: %ld, len:%d\n",size,skb->len);
+	    (size/(ATM_CELL_PAYLOAD/4)),tx->send+tx->tx_pos*4);
+/*printk("dsc = 0x%08lx\n",(unsigned long) readl(tx->send+tx->tx_pos*4));*/
+	writel((vcc->vci << MID_SEG_VCI_SHIFT) |
+            (aal5 ? 0 : (skb->data[3] & 0xf)) |
+	    (ATM_SKB(skb)->atm_options & ATM_ATMOPT_CLP ? MID_SEG_CLP : 0),
+	    tx->send+((tx->tx_pos+1) & (tx->words-1))*4);
+	DPRINTK("size: %d, len:%d\n",size,skb->len);
 	if (aal5)
-		tx->send[(tx->tx_pos+size-AAL5_TRAILER) & (tx->words-1)] =
-		    skb->len;
+		writel(skb->len,tx->send+
+                    ((tx->tx_pos+size-AAL5_TRAILER) & (tx->words-1))*4);
 	j = j >> 1;
 	for (i = 0; i < j; i++) {
-		writel(eni_dev->dma[i*2],eni_dev->tx_dma+dma_wr*2);
-		writel(eni_dev->dma[i*2+1],eni_dev->tx_dma+dma_wr*2+1);
+		writel(eni_dev->dma[i*2],eni_dev->tx_dma+dma_wr*8);
+		writel(eni_dev->dma[i*2+1],eni_dev->tx_dma+dma_wr*8+4);
 		dma_wr = (dma_wr+1) & (NR_DMA_TX-1);
 	}
 	ENI_PRV_POS(skb) = tx->tx_pos;
 	ENI_PRV_SIZE(skb) = size;
 	ENI_VCC(vcc)->txing += size;
 	tx->tx_pos = (tx->tx_pos+size) & (tx->words-1);
-	DPRINTK("dma_wr set to %ld, tx_pos is now %ld\n",dma_wr,tx->tx_pos);
-	writel(dma_wr,eni_dev->reg+MID_DMA_WR_TX);
+	DPRINTK("dma_wr set to %d, tx_pos is now %ld\n",dma_wr,tx->tx_pos);
+	eni_out(dma_wr,MID_DMA_WR_TX);
 	skb_queue_tail(&eni_dev->tx_queue,skb);
 queued++;
 	return enq_ok;
@@ -1181,9 +1192,9 @@
 		tx = ENI_VCC(vcc)->tx;
 		NULLCHECK(ENI_VCC(vcc)->tx);
 		DPRINTK("dequeue_tx: next 0x%lx curr 0x%x\n",ENI_PRV_POS(skb),
-		    readl(eni_dev->reg+MID_TX_DESCRSTART(tx->index)));
+		    (unsigned) eni_in(MID_TX_DESCRSTART(tx->index)));
 		if (ENI_VCC(vcc)->txing < tx->words && ENI_PRV_POS(skb) ==
-		    readl(eni_dev->reg+MID_TX_DESCRSTART(tx->index))) {
+		    eni_in(MID_TX_DESCRSTART(tx->index))) {
 			skb_queue_head(&eni_dev->tx_queue,skb);
 			break;
 		}
@@ -1286,14 +1297,14 @@
 		}
 		DPRINTK("got chan %d\n",tx->index);
 		tx->reserved = tx->shaping = 0;
-		tx->send = (u32 *) mem;
+		tx->send = mem;
 		tx->words = size >> 2;
 		skb_queue_head_init(&tx->backlog);
 		for (order = 0; size > (1 << (order+10)); order++);
-		writel((order << MID_SIZE_SHIFT) |
-		    ((tx->send-eni_dev->ram) >> MID_LOC_SKIP),
-		    eni_dev->reg+MID_TX_PLACE(tx->index));
-		tx->tx_pos = readl(eni_dev->reg+MID_TX_DESCRSTART(tx->index)) &
+		eni_out((order << MID_SIZE_SHIFT) |
+		    ((tx->send-eni_dev->ram) >> (MID_LOC_SKIP+2)),
+		    MID_TX_PLACE(tx->index));
+		tx->tx_pos = eni_in(MID_TX_DESCRSTART(tx->index)) &
 		    MID_DESCR_START;
 	}
 	error = comp_tx(eni_dev,&rate,tx->reserved,&pre,&res,unlimited);
@@ -1308,7 +1319,7 @@
 		error = -EINVAL;
 	if (error) {
 		if (new_tx) {
-			tx->send = NULL;
+			tx->send = 0;
 			eni_free_mem(eni_dev,mem,size);
 		}
 		return error;
@@ -1367,8 +1378,8 @@
 	 * Looping a few times in here is probably far cheaper than keeping
 	 * track of TX completions all the time, so let's poll a bit ...
 	 */
-	while (readl(eni_dev->reg+MID_TX_RDPTR(eni_vcc->tx->index)) !=
-	    readl(eni_dev->reg+MID_TX_DESCRSTART(eni_vcc->tx->index)))
+	while (eni_in(MID_TX_RDPTR(eni_vcc->tx->index)) !=
+	    eni_in(MID_TX_DESCRSTART(eni_vcc->tx->index)))
 		schedule();
 	restore_flags(flags);
 #if 0
@@ -1376,9 +1387,8 @@
 		printk(KERN_CRIT DEV_LABEL "SKBs in BACKLOG !!!\n");
 #endif
 	if (eni_vcc->tx != eni_dev->ubr) {
-		eni_free_mem(eni_dev,(unsigned long) eni_vcc->tx->send,
-		    eni_vcc->tx->words << 2);
-		eni_vcc->tx->send = NULL;
+		eni_free_mem(eni_dev,eni_vcc->tx->send,eni_vcc->tx->words << 2);
+		eni_vcc->tx->send = 0;
 		eni_dev->tx_bw += eni_vcc->tx->reserved;
 	}
 	eni_vcc->tx = NULL;
@@ -1396,9 +1406,9 @@
 	eni_dev->tx_wait = NULL;
 	eni_dev->ubr = NULL;
 	skb_queue_head_init(&eni_dev->tx_queue);
-	writel(0,eni_dev->reg+MID_DMA_WR_TX);
+	eni_out(0,MID_DMA_WR_TX);
 	for (i = 0; i < NR_CHAN; i++) {
-		eni_dev->tx[i].send = NULL;
+		eni_dev->tx[i].send = 0;
 		eni_dev->tx[i].index = i;
 	}
 	return 0;
@@ -1431,7 +1441,7 @@
 	eni_dev = ENI_DEV(dev);
 	if (reason & MID_STAT_OVFL) {
 		EVENT("stat overflow\n",0,0);
-		eni_dev->lost += readl(eni_dev->reg+MID_STAT) & MID_OVFL_TRASH;
+		eni_dev->lost += eni_in(MID_STAT) & MID_OVFL_TRASH;
 	}
 	if (reason & MID_SUNI_INT) {
 		EVENT("SUNI int\n",0,0);
@@ -1473,7 +1483,7 @@
 	DPRINTK(">eni_int\n");
 	dev = dev_id;
 	eni_dev = ENI_DEV(dev);
-	while ((reason = readl(eni_dev->reg+MID_ISA))) {
+	while ((reason = eni_in(MID_ISA))) {
 		DPRINTK(DEV_LABEL ": int 0x%lx\n",reason);
 		if (reason & MID_RX_DMA_COMPLETE) {
 			EVENT("INT: RX DMA complete, starting dequeue_rx\n",
@@ -1632,15 +1642,11 @@
 
 __initfunc(static int get_esi_fpga(struct atm_dev *dev,unsigned long base))
 {
-	struct eni_dev *eni_dev;
-	struct midway_eprom *eprom;
+	unsigned long mac_base;
 	int i;
 
-	eprom = (struct midway_eprom *) (base+EPROM_SIZE-sizeof(struct
-	    midway_eprom));
-	eni_dev = ENI_DEV(dev);
-	for (i = 0; i < ESI_LEN; i++)
-		dev->esi[i] = readl(&eprom->mac+((i & ~3) | (3-(i & 3))));
+	mac_base = base+EPROM_SIZE-sizeof(struct midway_eprom);
+	for (i = 0; i < ESI_LEN; i++) dev->esi[i] = readb(mac_base+(i^3));
 	return 0;
 }
 
@@ -1691,17 +1697,16 @@
 		if (readl(&eprom->magic) != ENI155_MAGIC) {
 			printk("\n");
 			printk(KERN_ERR KERN_ERR DEV_LABEL "(itf %d): bad "
-			    "magic - expected 0x%X, got 0x%X\n",dev->number,
-			    ENI155_MAGIC,readl(&eprom->magic));
+			    "magic - expected 0x%x, got 0x%x\n",dev->number,
+			    ENI155_MAGIC,(unsigned) readl(&eprom->magic));
 			return -EINVAL;
 		}
 	}
-	eni_dev->phy = (u32 *) (base+PHY_BASE);
-	eni_dev->reg = (u32 *) (base+REG_BASE);
-	eni_dev->ram = (u32 *) (base+RAM_BASE);
-	last = (MAP_MAX_SIZE-RAM_BASE)/4;
-	for (i = last-RAM_INCREMENT; i >= 0;
-	    i -= RAM_INCREMENT) {
+	eni_dev->phy = base+PHY_BASE;
+	eni_dev->reg = base+REG_BASE;
+	eni_dev->ram = base+RAM_BASE;
+	last = MAP_MAX_SIZE-RAM_BASE;
+	for (i = last-RAM_INCREMENT; i >= 0; i -= RAM_INCREMENT) {
 		writel(0x55555555,eni_dev->ram+i);
 		if (readl(eni_dev->ram+i) != 0x55555555) last = i;
 		else {
@@ -1712,15 +1717,15 @@
 	}
 	for (i = 0; i < last; i += RAM_INCREMENT)
 		if (readl(eni_dev->ram+i) != i) break;
-	eni_dev->mem = i << 2;
+	eni_dev->mem = i;
 	memset_io(eni_dev->ram,0,eni_dev->mem);
 	/* TODO: should shrink allocation now */
 	printk("mem=%dkB (",eni_dev->mem >> 10);
 	/* TODO: check for non-SUNI, check for TAXI ? */
-	if (!(readl(eni_dev->reg+MID_RES_ID_MCON) & 0x200) != !eni_dev->asic) {
+	if (!(eni_in(MID_RES_ID_MCON) & 0x200) != !eni_dev->asic) {
 		printk(")\n");
-		printk(KERN_ERR DEV_LABEL "(itf %d): ERROR - wrong id 0x%0x\n",
-		    dev->number,readl(eni_dev->reg+MID_RES_ID_MCON));
+		printk(KERN_ERR DEV_LABEL "(itf %d): ERROR - wrong id 0x%x\n",
+		    dev->number,(unsigned) eni_in(MID_RES_ID_MCON));
 		return -EINVAL;
 	}
 	error = eni_dev->asic ? get_esi_asic(dev) : get_esi_fpga(dev,base);
@@ -1729,8 +1734,8 @@
 		printk("%s%02X",i ? "-" : "",dev->esi[i]);
 	printk(")\n");
 	printk(KERN_NOTICE DEV_LABEL "(itf %d): %s,%s\n",dev->number,
-	    readl(eni_dev->reg+MID_RES_ID_MCON) & 0x200 ? "ASIC" : "FPGA",
-	    media_name[readl(eni_dev->reg+MID_RES_ID_MCON) & DAUGTHER_ID]);
+	    eni_in(MID_RES_ID_MCON) & 0x200 ? "ASIC" : "FPGA",
+	    media_name[eni_in(MID_RES_ID_MCON) & DAUGTHER_ID]);
 	return suni_init(dev);
 }
 
@@ -1738,8 +1743,7 @@
 __initfunc(static int eni_start(struct atm_dev *dev))
 {
 	struct eni_dev *eni_dev;
-	u32 *buf;
-	unsigned long buffer_mem;
+	unsigned long buf,buffer_mem;
 	int error;
 
 	DPRINTK(">eni_start\n");
@@ -1765,16 +1769,15 @@
 	}
 	/* determine addresses of internal tables */
 	eni_dev->vci = eni_dev->ram;
-	eni_dev->rx_dma = eni_dev->ram+NR_VCI*4;
-	eni_dev->tx_dma = eni_dev->rx_dma+NR_DMA_RX*2;
-	eni_dev->service = eni_dev->tx_dma+NR_DMA_TX*2;
-	buf = eni_dev->service+NR_SERVICE;
-	DPRINTK("vci 0x%p,rx 0x%p, tx 0x%p,srv 0x%p,buf 0x%p\n",
-	     eni_dev->vci,eni_dev->rx_dma,eni_dev->tx_dma,eni_dev->service,
-	     buf);
+	eni_dev->rx_dma = eni_dev->ram+NR_VCI*16;
+	eni_dev->tx_dma = eni_dev->rx_dma+NR_DMA_RX*8;
+	eni_dev->service = eni_dev->tx_dma+NR_DMA_TX*8;
+	buf = eni_dev->service+NR_SERVICE*4;
+	DPRINTK("vci 0x%lx,rx 0x%lx, tx 0x%lx,srv 0x%lx,buf 0x%lx\n",
+	     eni_dev->vci,eni_dev->rx_dma,eni_dev->tx_dma,
+	     eni_dev->service,buf);
 	/* initialize memory management */
-	buffer_mem = eni_dev->mem-((unsigned long) buf-
-	    (unsigned long) eni_dev->ram);
+	buffer_mem = eni_dev->mem-(buf-eni_dev->ram);
 	eni_dev->free_list_size = buffer_mem/MID_MIN_BUF_SIZE/2;
 	eni_dev->free_list = (struct eni_free *) kmalloc(
 	    sizeof(struct eni_free)*(eni_dev->free_list_size+1),GFP_KERNEL);
@@ -1784,7 +1787,7 @@
 		return -ENOMEM;
 	}
 	eni_dev->free_len = 0;
-	eni_put_free(eni_dev,(unsigned long) buf,buffer_mem);
+	eni_put_free(eni_dev,buf,buffer_mem);
 	memset_io(eni_dev->vci,0,16*NR_VCI); /* clear VCI table */
 	/*
 	 * byte_addr  free (k)
@@ -1795,18 +1798,18 @@
 	 * 0x00007000	  484  buffers
 	 * 0x00080000	    0  end (512kB)
 	 */
-	writel(0xffffffff,eni_dev->reg+MID_IE);
+	eni_out(0xffffffff,MID_IE);
 	error = start_tx(dev);
 	if (error) return error;
 	error = start_rx(dev);
 	if (error) return error;
 	error = dev->phy->start(dev);
 	if (error) return error;
-	writel(readl(eni_dev->reg+MID_MC_S) | (1 << MID_INT_SEL_SHIFT) |
+	eni_out(eni_in(MID_MC_S) | (1 << MID_INT_SEL_SHIFT) |
 	    MID_TX_LOCK_MODE | MID_DMA_ENABLE | MID_TX_ENABLE | MID_RX_ENABLE,
-	    eni_dev->reg+MID_MC_S);
+	    MID_MC_S);
 	    /* Tonga uses SBus INTReq1 */
-	(void) readl(eni_dev->reg+MID_ISA); /* clear Midway interrupts */
+	(void) eni_in(MID_ISA); /* clear Midway interrupts */
 	return 0;
 }
 
@@ -1942,13 +1945,13 @@
 	cli();
 	for (skb = eni_dev->tx_queue.next; skb !=
 	    (struct sk_buff *) &eni_dev->tx_queue; skb = skb->next) {
-		u32 *dsc;
+		unsigned long dsc;
 
 		if (ATM_SKB(skb)->vcc != vcc) continue;
-		dsc = tx->send+ENI_PRV_POS(skb);
-		*dsc = (*dsc & ~(MID_SEG_RATE | MID_SEG_PR)) |
+		dsc = tx->send+ENI_PRV_POS(skb)*4;
+		writel((readl(dsc) & ~(MID_SEG_RATE | MID_SEG_PR)) |
 		    (tx->prescaler << MID_SEG_PR_SHIFT) |
-		    (tx->resolution << MID_SEG_RATE_SHIFT);
+		    (tx->resolution << MID_SEG_RATE_SHIFT), dsc);
 	}
 	restore_flags(flags);
 	return 0;
@@ -2055,14 +2058,14 @@
 static void eni_phy_put(struct atm_dev *dev,unsigned char value,
     unsigned long addr)
 {
-	writel(value,ENI_DEV(dev)->phy+addr);
+	writel(value,ENI_DEV(dev)->phy+addr*4);
 }
 
 
 
 static unsigned char eni_phy_get(struct atm_dev *dev,unsigned long addr)
 {
-	return readl(ENI_DEV(dev)->phy+addr);
+	return readl(ENI_DEV(dev)->phy+addr*4);
 }
 
 
@@ -2127,9 +2130,10 @@
 
 		if (!tx->send) continue;
 		if (--left) continue;
-		return sprintf(page,"tx[%d]:    0x%06x-0x%06lx (%6ld bytes), "
-		    "rsv %d cps, shp %d cps%s\n",i,(tx->send-eni_dev->ram)*4,
-		    (tx->send-eni_dev->ram+tx->words)*4-1,tx->words*4,
+		return sprintf(page,"tx[%d]:    0x%06lx-0x%06lx (%6ld bytes), "
+		    "rsv %d cps, shp %d cps%s\n",i,
+		    tx->send-eni_dev->ram,
+		    tx->send-eni_dev->ram+tx->words*4-1,tx->words*4,
 		    tx->reserved,tx->shaping,
 		    tx == eni_dev->ubr ? " (UBR)" : "");
 	}
@@ -2140,9 +2144,10 @@
 		if (--left) continue;
 		length = sprintf(page,"vcc %4d: ",vcc->vci);
 		if (eni_vcc->rx) {
-			length += sprintf(page+length,"0x%06x-0x%06lx "
-			    "(%6ld bytes)",(eni_vcc->recv-eni_dev->ram)*4,
-			    (eni_vcc->recv-eni_dev->ram+eni_vcc->words)*4-1,
+			length += sprintf(page+length,"0x%06lx-0x%06lx "
+			    "(%6ld bytes)",
+			    eni_vcc->recv-eni_dev->ram,
+			    eni_vcc->recv-eni_dev->ram+eni_vcc->words*4-1,
 			    eni_vcc->words*4);
 			if (eni_vcc->tx) length += sprintf(page+length,", ");
 		}
@@ -2157,7 +2162,7 @@
 		unsigned long offset;
 
 		if (--left) continue;
-		offset = (unsigned long) eni_dev->ram+eni_dev->base_diff;
+		offset = eni_dev->ram+eni_dev->base_diff;
 		return sprintf(page,"free      0x%06lx-0x%06lx (%6d bytes)\n",
 		    fe->start-offset,fe->start-offset+(1 << fe->order)-1,
 		    1 << fe->order);
diff -ur --new-file old/linux/drivers/atm/eni.h new/linux/drivers/atm/eni.h
--- old/linux/drivers/atm/eni.h	Thu Jun  3 00:40:49 1999
+++ new/linux/drivers/atm/eni.h	Thu Jun  3 00:42:17 1999
@@ -31,7 +31,7 @@
 };
 
 struct eni_tx {
-	u32 *send;			/* base, NULL if unused */
+	unsigned long send;		/* base, 0 if unused */
 	int prescaler;			/* shaping prescaler */
 	int resolution;			/* shaping divider */
 	unsigned long tx_pos;		/* current TX write position */
@@ -44,7 +44,7 @@
 
 struct eni_vcc {
 	int (*rx)(struct atm_vcc *vcc);	/* RX function, NULL if none */
-	u32 *recv;			/* receive buffer */
+	unsigned long recv;		/* receive buffer */
 	unsigned long words;		/* its size in words */
 	unsigned long descr;		/* next descriptor (RX) */
 	unsigned long rx_pos;		/* current RX descriptor pos */
@@ -61,13 +61,13 @@
 struct eni_dev {
 	/*-------------------------------- base pointers into Midway address
 					   space */
-	u32 *phy;			/* PHY interface chip registers */
-	u32 *reg;			/* register base */
-	u32 *ram;			/* RAM base */
-	u32 *vci;			/* VCI table */
-	u32 *rx_dma;			/* RX DMA queue */
-	u32 *tx_dma;			/* TX DMA queue */
-	u32 *service;			/* service list */
+	unsigned long phy;		/* PHY interface chip registers */
+	unsigned long reg;		/* register base */
+	unsigned long ram;		/* RAM base */
+	unsigned long vci;		/* VCI table */
+	unsigned long rx_dma;		/* RX DMA queue */
+	unsigned long tx_dma;		/* TX DMA queue */
+	unsigned long service;		/* service list */
 	/*-------------------------------- TX part */
 	struct eni_tx tx[NR_CHAN];	/* TX channels */
 	struct eni_tx *ubr;		/* UBR channel */
diff -ur --new-file old/linux/drivers/atm/midway.h new/linux/drivers/atm/midway.h
--- old/linux/drivers/atm/midway.h	Thu Jun  3 00:40:49 1999
+++ new/linux/drivers/atm/midway.h	Thu Jun  3 00:42:17 1999
@@ -1,6 +1,6 @@
 /* drivers/atm/midway.h - Efficient Networks Midway (SAR) description */
  
-/* Written 1995 by Werner Almesberger, EPFL LRC */
+/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
  
 
 #ifndef DRIVERS_ATM_MIDWAY_H
@@ -21,7 +21,7 @@
 #define PHY_BASE	0x00020000	/* offset of PHY register are */
 #define REG_BASE	0x00040000	/* offset of Midway register area */
 #define RAM_BASE	0x00200000	/* offset of RAM area */
-#define RAM_INCREMENT	0x00008000	/* probe for RAM every 128kB (32 kw) */
+#define RAM_INCREMENT	0x00020000	/* probe for RAM every 128kB */
 
 #define MID_VCI_BASE	RAM_BASE
 #define MID_DMA_RX_BASE	(MID_VCI_BASE+NR_VCI*16)
@@ -161,8 +161,8 @@
 struct midway_eprom {
 	unsigned char mac[MAC_LEN],inv_mac[MAC_LEN];
 	unsigned char pad[36];
-	unsigned long serial,inv_serial;
-	unsigned long magic,inv_magic;
+	u32 serial,inv_serial;
+	u32 magic,inv_magic;
 };
 
 
diff -ur --new-file old/linux/drivers/atm/nicstar.c new/linux/drivers/atm/nicstar.c
--- old/linux/drivers/atm/nicstar.c	Thu Jun  3 00:40:49 1999
+++ new/linux/drivers/atm/nicstar.c	Thu Jun  3 00:42:18 1999
@@ -2,7 +2,7 @@
  *
  * nicstar.c
  *
- * Device driver supporting CBR for IDT 77211 "NICStAR" based cards.
+ * Device driver supporting CBR for IDT 77201/77211 "NICStAR" based cards.
  *
  * IMPORTANT: The included file nicstarmac.c was NOT WRITTEN BY ME.
  *            It was taken from the frle-0.22 device driver.
@@ -11,16 +11,12 @@
  *            frle-0.22 device driver.
  *            Some code is based on the nicstar driver by M. Welsh.
  *
- * Author: Rui Prior
+ * Author: Rui Prior (rprior@inescn.pt)
+ * PowerPC support by Jay Talbott (jay_talbott@mcg.mot.com) April 1999
  *
- * URLs:
- *   NICStAR driver homepage
- *     http://jaguar.inescn.pt/~rprior/nicstar/nicstar.html
  *
- *   IDT 77211 documentation
- *     http://www.idt.com/product_files/77211.html
+ * (C) INESC 1999
  *
- * (C) INESC 1998
  *
  ******************************************************************************/
 
@@ -45,6 +41,9 @@
 #include <asm/uaccess.h>
 #include "nicstar.h"
 #include "nicstarmac.h"
+#ifdef CONFIG_ATM_NICSTAR_USE_SUNI
+#include "suni.h"
+#endif /* CONFIG_ATM_NICSTAR_USE_SUNI */
 
 
 /* Additional code ************************************************************/
@@ -153,6 +152,10 @@
 static void ns_poll(unsigned long arg);
 static int ns_parse_mac(char *mac, unsigned char *esi);
 static short ns_h2i(char c);
+static void ns_phy_put(struct atm_dev *dev, unsigned char value,
+                       unsigned long addr);
+static unsigned char ns_phy_get(struct atm_dev *dev, unsigned long addr);
+
 
 
 /* Global variables ***********************************************************/
@@ -170,8 +173,8 @@
    ns_send,		/* send */
    NULL,		/* sg_send */
    NULL,		/* send_oam */
-   NULL,		/* phy_put */
-   NULL,		/* phy_get */
+   ns_phy_put,		/* phy_put */
+   ns_phy_get,		/* phy_get */
    NULL,		/* feedback */
    NULL,		/* change_qos */
    NULL,		/* free_rx_skb */
@@ -452,6 +455,11 @@
    card->index = i;
    card->pcidev = pcidev;
    card->membase = (u32) (pcidev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK);
+#ifdef __powerpc__
+   /* Compensate for different memory map between host CPU and PCI bus.
+      Shouldn't we use a macro for this? */
+   card->membase += KERNELBASE;
+#endif /* __powerpc__ */
    card->membase = (u32) ioremap(card->membase, NS_IOREMAP_SIZE);
    if (card->membase == (u32) (NULL))
    {
@@ -555,7 +563,8 @@
          printk("nicstar%d: unknown PHY type (0x%08X).\n", i, data);
          error = 8;
          ns_init_card_error(card, error);
-         return error; }
+         return error;
+   }
    writel(0x00000000, card->membase + GP);
 
    /* Determine SRAM size */
@@ -597,7 +606,7 @@
 
    if (request_irq(pcidev->irq, &ns_irq_handler, SA_INTERRUPT | SA_SHIRQ, "nicstar", card) != 0)
    {
-      printk("nicstar%d: can't allocate IRQ.\n", i);
+      printk("nicstar%d: can't allocate IRQ %d.\n", i, pcidev->irq);
       error = 9;
       ns_init_card_error(card, error);
       return error;
@@ -848,7 +857,8 @@
           NS_CFG_RSQAFIE |
           NS_CFG_TXEN |
           NS_CFG_TXIE |
-          NS_CFG_TSQFIE_OPT,		/* Only enabled if ENABLE_TSQFIE */ 
+          NS_CFG_TSQFIE_OPT |		/* Only enabled if ENABLE_TSQFIE */ 
+          NS_CFG_PHYIE,
           card->membase + CFG);
 
    /* Register device */
@@ -874,6 +884,18 @@
    card->atmdev->ci_range.vci_bits = card->vcibits;
    card->atmdev->link_rate = card->max_pcr;
 
+#ifdef CONFIG_ATM_NICSTAR_USE_SUNI
+   if (card->max_pcr == ATM_OC3_PCR) {
+      suni_init(card->atmdev);
+#ifdef MODULE
+      MOD_INC_USE_COUNT;
+      /* Can't remove the nicstar driver or the suni driver would oops */
+#endif /* MODULE */
+   }
+#endif /* CONFIG_ATM_NICSTAR_USE_SUNI */
+   if (card->atmdev->phy && card->atmdev->phy->start)
+      card->atmdev->phy->start(card->atmdev);
+
    num_cards++;
 
    return error;
@@ -1138,8 +1160,10 @@
 {
    u32 stat_r;
    ns_dev *card;
+   struct atm_dev *dev;
 
    card = (ns_dev *) dev_id;
+   dev = card->atmdev;
    card->intcnt++;
 
    PRINTK("nicstar%d: NICStAR generated an interrupt\n", card->index);
@@ -1195,7 +1219,10 @@
    if (stat_r & NS_STAT_PHYI)
    {
       writel(NS_STAT_PHYI, card->membase + STAT);
-      printk("nicstar%d: PHY interrupt.\n", card->index);
+      PRINTK("nicstar%d: PHY interrupt.\n", card->index);
+      if (dev->phy && dev->phy->interrupt) {
+         dev->phy->interrupt(dev);
+      }
    }
 
    /* Small Buffer Queue is full */
@@ -1329,7 +1356,7 @@
    ns_dev *card;
    vc_map *vc;
    int error;
-   double tmpd;
+   unsigned long tmpl, modl;
    int tcr, tcra;	/* target cell rate, and absolute value */
    int n = 0;		/* Number of entries in the TST. Initialized to remove
                            the compiler warning. */
@@ -1398,19 +1425,15 @@
          PRINTK("nicstar%d: target cell rate = %d.\n", card->index,
                 vcc->qos.txtp.max_pcr);
 
-         tmpd = ((double) tcra) * ((double) NS_TST_NUM_ENTRIES) /
-                ((double) card->max_pcr);      
+         tmpl = (unsigned long)tcra * (unsigned long)NS_TST_NUM_ENTRIES;
+         modl = tmpl % card->max_pcr;
 
-         n = (int) tmpd;
+         n = (int)(tmpl / card->max_pcr);
          if (tcr > 0)
          {
-            if (tmpd > (double) n) n++;
-         }
-         else if (tcr < 0)
-         {
-            if (tmpd < (double) n) n--;
+            if (modl > 0) n++;
          }
-         else /* tcr == 0 */
+         else if (tcr == 0)
          {
             if ((n = (card->tst_free_entries - NS_TST_RESERVED)) <= 0)
 	    {
@@ -1427,17 +1450,6 @@
             return -EINVAL;
          }
 
-         if (vcc->qos.txtp.max_pcr > 0)
-         {
-            tmpd = (double) n * (double) card->max_pcr /
-	           (double) NS_TST_NUM_ENTRIES;
-            if (tmpd > PCR_TOLERANCE * (double) vcc->qos.txtp.max_pcr)
-            {
-               PRINTK("nicstar%d: target cell rate exceeded requested max_pcr.\n",
-                      card->index);
-            }
-         }
-
          if (n > (card->tst_free_entries - NS_TST_RESERVED))
          {
             PRINTK("nicstar%d: not enough free CBR bandwidth.\n", card->index);
@@ -1677,7 +1689,7 @@
 static void fill_tst(ns_dev *card, int n, vc_map *vc)
 {
    u32 new_tst;
-   double c, q;
+   unsigned long cl;
    int e, r;
    u32 data;
       
@@ -1694,32 +1706,30 @@
       if (card->tste2vc[e] == NULL)
          break;
    }
-   if (e == NS_TST_NUM_ENTRIES)
+   if (e == NS_TST_NUM_ENTRIES) {
       printk("nicstar%d: No free TST entries found. \n", card->index);
+      return;
+   }
 
    r = n;
-   c = 1.0;
-   q = (double) n / (double) NS_TST_NUM_ENTRIES;
-
+   cl = NS_TST_NUM_ENTRIES;
    data = ns_tste_make(NS_TST_OPCODE_FIXED, vc->cbr_scd);
       
-   while (e < NS_TST_NUM_ENTRIES)
+   while (r > 0)
    {
-      if (c >= 1.0 && card->tste2vc[e] == NULL)
+      if (cl >= NS_TST_NUM_ENTRIES && card->tste2vc[e] == NULL)
       {
          card->tste2vc[e] = vc;
          ns_write_sram(card, new_tst + e, &data, 1);
-	 c -= 1.0;
-	 if (--r == 0)
-	    break;
+         cl -= NS_TST_NUM_ENTRIES;
+         r--;
       }
 
-      e++;
-      c += q;
+      if (++e == NS_TST_NUM_ENTRIES) {
+         e = 0;
+      }
+      cl += n;
    }
-   if (r != 0)
-      printk("nicstar%d: Not enough free TST entries. CBR lower than requested.\n",
-             card->index);
    
    /* End of fill procedure */
    
@@ -1780,24 +1790,25 @@
    {
       buflen = (skb->len + 47 + 8) / 48 * 48;	/* Multiple of 48 */
       flags = NS_TBD_AAL5;
-      scqe.word_2 = (u32) virt_to_bus(skb->data);
-      scqe.word_3 = (u32) skb->len;
-      scqe.word_4 = ((u32) vcc->vpi) << NS_TBD_VPI_SHIFT |
-                    ((u32) vcc->vci) << NS_TBD_VCI_SHIFT;
+      scqe.word_2 = cpu_to_le32((u32) virt_to_bus(skb->data));
+      scqe.word_3 = cpu_to_le32((u32) skb->len);
+      scqe.word_4 = cpu_to_le32(((u32) vcc->vpi) << NS_TBD_VPI_SHIFT |
+                                ((u32) vcc->vci) << NS_TBD_VCI_SHIFT);
       flags |= NS_TBD_EOPDU;
    }
    else /* (vcc->qos.aal == ATM_AAL0) */
    {
       buflen = ATM_CELL_PAYLOAD;	/* i.e., 48 bytes */
       flags = NS_TBD_AAL0;
-      scqe.word_2 = (u32) virt_to_bus(skb->data) + NS_AAL0_HEADER;
-      scqe.word_3 = 0x00000000;
+      scqe.word_2 = cpu_to_le32((u32) virt_to_bus(skb->data) + NS_AAL0_HEADER);
+      scqe.word_3 = cpu_to_le32(0x00000000);
       if (*skb->data & 0x02)	/* Payload type 1 - end of pdu */
          flags |= NS_TBD_EOPDU;
-      scqe.word_4 = *((u32 *) skb->data) & ~NS_TBD_VC_MASK;
+      scqe.word_4 = cpu_to_le32(*((u32 *) skb->data) & ~NS_TBD_VC_MASK);
       /* Force the VPI/VCI to be the same as in VCC struct */
-      scqe.word_4 |= (((u32) vcc->vpi) << NS_TBD_VPI_SHIFT |
-                      ((u32) vcc->vci) << NS_TBD_VCI_SHIFT) & NS_TBD_VC_MASK;
+      scqe.word_4 |= cpu_to_le32((((u32) vcc->vpi) << NS_TBD_VPI_SHIFT |
+                                 ((u32) vcc->vci) << NS_TBD_VCI_SHIFT) &
+                                 NS_TBD_VC_MASK);
    }
 
    if (vcc->qos.txtp.traffic_class == ATM_CBR)
@@ -1857,7 +1868,8 @@
    XPRINTK("nicstar%d: sending skb at 0x%x (pos %d).\n",
            card->index, (u32) skb, index);
    XPRINTK("nicstar%d: TBD written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%x.\n",
-           card->index, tbd->word_1, tbd->word_2, tbd->word_3, tbd->word_4,
+           card->index, le32_to_cpu(tbd->word_1), le32_to_cpu(tbd->word_2),
+           le32_to_cpu(tbd->word_3), le32_to_cpu(tbd->word_4),
            (u32) scq->next);
    if (scq->next == scq->last)
       scq->next = scq->base;
@@ -1906,7 +1918,8 @@
          index = (int) scqi;
          scq->skb[index] = NULL;
          XPRINTK("nicstar%d: TSR written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%x.\n",
-	         card->index, tsr.word_1, tsr.word_2, tsr.word_3, tsr.word_4,
+                 card->index, le32_to_cpu(tsr.word_1), le32_to_cpu(tsr.word_2),
+                 le32_to_cpu(tsr.word_3), le32_to_cpu(tsr.word_4),
 		 (u32) scq->next);
          if (scq->next == scq->last)
             scq->next = scq->base;
@@ -1974,7 +1987,7 @@
                ns_tsi_init(card->tsq.next);
                return;
             }
-	    scq = card->scd2vc[scdi]->scq;
+            scq = card->scd2vc[scdi]->scq;
          }
          drain_scq(card, scq, ns_tsi_getscqpos(card->tsq.next));
          scq->full = 0;
@@ -2084,7 +2097,7 @@
    card->sbfqc = ns_stat_sfbqc_get(stat);   
    card->lbfqc = ns_stat_lfbqc_get(stat);
 
-   skb = (struct sk_buff *) rsqe->buffer_handle;
+   skb = (struct sk_buff *) le32_to_cpu(rsqe->buffer_handle);
    vpi = ns_rsqe_vpi(rsqe);
    vci = ns_rsqe_vci(rsqe);
    if (vpi >= 1UL << card->vpibits || vci >= 1UL << card->vcibits)
@@ -2131,7 +2144,7 @@
             break;
          }
          /* Rebuild the header */
-         *((u32 *) sb->data) = rsqe->word_1 << 4 |
+         *((u32 *) sb->data) = le32_to_cpu(rsqe->word_1) << 4 |
                                (ns_rsqe_clp(rsqe) ? 0x00000001 : 0x00000000);
          if (i == 1 && ns_rsqe_eopdu(rsqe))
             *((u32 *) sb->data) |= 0x00000002;
@@ -2231,10 +2244,10 @@
 
    if (ns_rsqe_eopdu(rsqe))
    {
-      aal5_len = *((unsigned short *) ((u32) skb->data + iov->iov_len - 6));
-      /* Swap byte order. Is it just me or the nicstar manual sais this should
-         already be in little endian format? */
-      aal5_len = ((aal5_len & 0x00ff) << 8 | (aal5_len & 0xff00) >> 8);
+      /* This works correctly regardless of the endianness of the host */
+      unsigned char *L1L2 = (unsigned char *)((u32)skb->data +
+                                              iov->iov_len - 6);
+      aal5_len = L1L2[0] << 8 | L1L2[1];
       len = (aal5_len == 0x0000) ? 0x10000 : aal5_len;
       if (ns_rsqe_crcerr(rsqe) ||
           len + 8 > iovb->len || len + (47 + 8) < iovb->len)
@@ -2896,8 +2909,14 @@
          return 0;
 
       default:
-         if (dev->phy->ioctl == NULL) return -EINVAL;
-	 return dev->phy->ioctl(dev, cmd, arg);
+         if (dev->phy && dev->phy->ioctl) {
+            return dev->phy->ioctl(dev, cmd, arg);
+         }
+         else {
+            printk("nicstar%d: %s == NULL \n", card->index,
+                   dev->phy ? "dev->phy->ioctl" : "dev->phy");
+            return -EINVAL;
+         }
    }
 }
 
@@ -2951,7 +2970,7 @@
       process_tsq(card);
       process_rsq(card);
 
-      writel(card->membase + STAT, stat_w);
+      writel(stat_w, card->membase + STAT);
       card->in_poll = 0;
       restore_flags(flags);
    }
@@ -2996,4 +3015,40 @@
    if (c >= 'a' && c <= 'f')
       return (short) (c - 'a' + 10);
    return -1;
+}
+
+
+
+static void ns_phy_put(struct atm_dev *dev, unsigned char value,
+                    unsigned long addr)
+{
+   ns_dev *card;
+   unsigned long flags;
+
+   card = dev->dev_data;
+   save_flags(flags); cli();
+   while(CMD_BUSY(card));
+   writel((unsigned long) value, card->membase + DR0);
+   writel(NS_CMD_WRITE_UTILITY | 0x00000200 | (addr & 0x000000FF),
+          card->membase + CMD);
+   restore_flags(flags);
+}
+
+
+
+static unsigned char ns_phy_get(struct atm_dev *dev, unsigned long addr)
+{
+   ns_dev *card;
+   unsigned long flags;
+   unsigned long data;
+
+   card = dev->dev_data;
+   save_flags(flags); cli();
+   while(CMD_BUSY(card));
+   writel(NS_CMD_READ_UTILITY | 0x00000200 | (addr & 0x000000FF),
+          card->membase + CMD);
+   while(CMD_BUSY(card));
+   data = readl(card->membase + DR0) & 0x000000FF;
+   restore_flags(flags);
+   return (unsigned char) data;
 }
diff -ur --new-file old/linux/drivers/atm/nicstar.h new/linux/drivers/atm/nicstar.h
--- old/linux/drivers/atm/nicstar.h	Thu Jun  3 00:40:49 1999
+++ new/linux/drivers/atm/nicstar.h	Thu Jun  3 00:42:17 1999
@@ -4,7 +4,8 @@
  *
  * Header file for the nicstar device driver.
  *
- * Author: Rui Prior
+ * Author: Rui Prior (rprior@inescn.pt)
+ * PowerPC support by Jay Talbott (jay_talbott@mcg.mot.com) April 1999
  *
  * (C) INESC 1998
  *
@@ -135,8 +136,10 @@
    u32 word_4;
 } ns_rsqe;
 
-#define ns_rsqe_vpi(ns_rsqep) (((ns_rsqep)->word_1 & 0x00FF0000) >> 16)
-#define ns_rsqe_vci(ns_rsqep) ((ns_rsqep)->word_1 & 0x0000FFFF)
+#define ns_rsqe_vpi(ns_rsqep) \
+        ((le32_to_cpu((ns_rsqep)->word_1) & 0x00FF0000) >> 16)
+#define ns_rsqe_vci(ns_rsqep) \
+        (le32_to_cpu((ns_rsqep)->word_1) & 0x0000FFFF)
 
 #define NS_RSQE_VALID      0x80000000
 #define NS_RSQE_NZGFC      0x00004000
@@ -149,16 +152,25 @@
 #define NS_RSQE_BUFSIZE_SM 0x00000000
 #define NS_RSQE_BUFSIZE_LG 0x00001000
 
-#define ns_rsqe_valid(ns_rsqep) ((ns_rsqep)->word_4 & NS_RSQE_VALID)
-#define ns_rsqe_nzgfc(ns_rsqep) ((ns_rsqep)->word_4 & NS_RSQE_NZGFC)
-#define ns_rsqe_eopdu(ns_rsqep) ((ns_rsqep)->word_4 & NS_RSQE_EOPDU)
-#define ns_rsqe_bufsize(ns_rsqep) ((ns_rsqep)->word_4 & NS_RSQE_BUFSIZE)
-#define ns_rsqe_congestion(ns_rsqep) ((ns_rsqep)->word_4 & NS_RSQE_CONGESTION)
-#define ns_rsqe_clp(ns_rsqep) ((ns_rsqep)->word_4 & NS_RSQE_CLP)
-#define ns_rsqe_crcerr(ns_rsqep) ((ns_rsqep)->word_4 & NS_RSQE_CRCERR)
-
-#define ns_rsqe_cellcount(ns_rsqep) ((ns_rsqep)->word_4 & 0x000001FF)
-#define ns_rsqe_init(ns_rsqep) ((ns_rsqep)->word_4 = 0x00000000)
+#define ns_rsqe_valid(ns_rsqep) \
+        (le32_to_cpu((ns_rsqep)->word_4) & NS_RSQE_VALID)
+#define ns_rsqe_nzgfc(ns_rsqep) \
+        (le32_to_cpu((ns_rsqep)->word_4) & NS_RSQE_NZGFC)
+#define ns_rsqe_eopdu(ns_rsqep) \
+        (le32_to_cpu((ns_rsqep)->word_4) & NS_RSQE_EOPDU)
+#define ns_rsqe_bufsize(ns_rsqep) \
+        (le32_to_cpu((ns_rsqep)->word_4) & NS_RSQE_BUFSIZE)
+#define ns_rsqe_congestion(ns_rsqep) \
+        (le32_to_cpu((ns_rsqep)->word_4) & NS_RSQE_CONGESTION)
+#define ns_rsqe_clp(ns_rsqep) \
+        (le32_to_cpu((ns_rsqep)->word_4) & NS_RSQE_CLP)
+#define ns_rsqe_crcerr(ns_rsqep) \
+        (le32_to_cpu((ns_rsqep)->word_4) & NS_RSQE_CRCERR)
+
+#define ns_rsqe_cellcount(ns_rsqep) \
+        (le32_to_cpu((ns_rsqep)->word_4) & 0x000001FF)
+#define ns_rsqe_init(ns_rsqep) \
+        ((ns_rsqep)->word_4 = cpu_to_le32(0x00000000)) 
 
 #define NS_RSQ_NUM_ENTRIES (NS_RSQSIZE / 16)
 #define NS_RSQ_ALIGNMENT NS_RSQSIZE
@@ -186,9 +198,12 @@
 
 #define NS_RCQE_SIZE 64		/* bytes */
 
-#define ns_rcqe_islast(ns_rcqep) ((ns_rcqep)->word_2 != 0x00000000)
-#define ns_rcqe_cellheader(ns_rcqep) ((ns_rcqep)->word_1)
-#define ns_rcqe_nextbufhandle(ns_rcqep) ((ns_rcqep)->word_2)
+#define ns_rcqe_islast(ns_rcqep) \
+        (le32_to_cpu((ns_rcqep)->word_2) != 0x00000000)
+#define ns_rcqe_cellheader(ns_rcqep) \
+        (le32_to_cpu((ns_rcqep)->word_1))
+#define ns_rcqe_nextbufhandle(ns_rcqep) \
+        (le32_to_cpu((ns_rcqep)->word_2))
 
 
 
@@ -224,20 +239,27 @@
 #define NS_TBD_VPI_SHIFT 20
 #define NS_TBD_VCI_SHIFT 4
 
-#define ns_tbd_mkword_1(flags, m, n, buflen) (flags | m << 23 | n << 16 | buflen)
-#define ns_tbd_mkword_1_novbr(flags, buflen) (flags | buflen | 0x00810000)
-#define ns_tbd_mkword_3(control, pdulen) (control << 16 | pdulen)
-#define ns_tbd_mkword_4(gfc, vpi, vci, pt, clp) (gfc << 28 | vpi << 20 | vci << 4 | pt << 1 | clp))
+#define ns_tbd_mkword_1(flags, m, n, buflen) \
+        (cpu_to_le32(flags | m << 23 | n << 16 | buflen))
+#define ns_tbd_mkword_1_novbr(flags, buflen) \
+        (cpu_to_le32(flags | buflen | 0x00810000))
+#define ns_tbd_mkword_3(control, pdulen) \
+        (cpu_to_le32(control << 16 | pdulen))
+#define ns_tbd_mkword_4(gfc, vpi, vci, pt, clp) \
+        (cpu_to_le32(gfc << 28 | vpi << 20 | vci << 4 | pt << 1 | clp)))
 
 
 #define NS_TSR_INTENABLE 0x20000000
 
 #define NS_TSR_SCDISVBR 0xFFFF		/* Use as scdi for VBR SCD */
 
-#define ns_tsr_mkword_1(flags) (NS_SCQE_TYPE_TSR | (flags))
-#define ns_tsr_mkword_2(scdi, scqi) ((scdi) << 16 | 0x00008000 | (scqi))
+#define ns_tsr_mkword_1(flags) \
+        (cpu_to_le32(NS_SCQE_TYPE_TSR | (flags)))
+#define ns_tsr_mkword_2(scdi, scqi) \
+        (cpu_to_le32((scdi) << 16 | 0x00008000 | (scqi)))
 
-#define ns_scqe_is_tsr(ns_scqep) ((ns_scqep)->word_1 & NS_SCQE_TYPE_TSR)
+#define ns_scqe_is_tsr(ns_scqep) \
+        (le32_to_cpu((ns_scqep)->word_1) & NS_SCQE_TYPE_TSR)
 
 #define VBR_SCQ_NUM_ENTRIES 512
 #define VBR_SCQSIZE 8192
@@ -266,10 +288,13 @@
 #define NS_TSI_EMPTY          0x80000000
 #define NS_TSI_TIMESTAMP_MASK 0x00FFFFFF
 
-#define ns_tsi_isempty(ns_tsip) ((ns_tsip)->word_2 & NS_TSI_EMPTY)
-#define ns_tsi_gettimestamp(ns_tsip) ((ns_tsip)->word_2 & NS_TSI_TIMESTAMP_MASK)
+#define ns_tsi_isempty(ns_tsip) \
+        (le32_to_cpu((ns_tsip)->word_2) & NS_TSI_EMPTY)
+#define ns_tsi_gettimestamp(ns_tsip) \
+        (le32_to_cpu((ns_tsip)->word_2) & NS_TSI_TIMESTAMP_MASK)
 
-#define ns_tsi_init(ns_tsip) ((ns_tsip)->word_2 = NS_TSI_EMPTY)
+#define ns_tsi_init(ns_tsip) \
+        ((ns_tsip)->word_2 = cpu_to_le32(NS_TSI_EMPTY))
 
 
 #define NS_TSQSIZE 8192
@@ -279,9 +304,12 @@
 
 #define NS_TSI_SCDISVBR NS_TSR_SCDISVBR
 
-#define ns_tsi_tmrof(ns_tsip) ((ns_tsip)->word_1 == 0x00000000)
-#define ns_tsi_getscdindex(ns_tsip) (((ns_tsip)->word_1 & 0xFFFF0000) >> 16)
-#define ns_tsi_getscqpos(ns_tsip) ((ns_tsip)->word_1 & 0x00007FFF)
+#define ns_tsi_tmrof(ns_tsip) \
+        (le32_to_cpu((ns_tsip)->word_1) == 0x00000000)
+#define ns_tsi_getscdindex(ns_tsip) \
+        ((le32_to_cpu((ns_tsip)->word_1) & 0xFFFF0000) >> 16)
+#define ns_tsi_getscqpos(ns_tsip) \
+        (le32_to_cpu((ns_tsip)->word_1) & 0x00007FFF)
 
 
 
diff -ur --new-file old/linux/include/linux/atm.h new/linux/include/linux/atm.h
--- old/linux/include/linux/atm.h	Thu Jun  3 00:40:51 1999
+++ new/linux/include/linux/atm.h	Thu Jun  3 00:42:18 1999
@@ -1,6 +1,6 @@
 /* atm.h - general ATM declarations */
  
-/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
  
 
 /*
@@ -46,7 +46,6 @@
 #define ATM_AAL2	2		/* AAL2 (VBR) */
 #define ATM_AAL34	3		/* AAL3/4 (data) */
 #define ATM_AAL5	5		/* AAL5 (data) */
-#define ATM_SAAL	12		/* signaling AAL */
 
 /* socket option name coding functions */
 
diff -ur --new-file old/linux/include/linux/atmlec.h new/linux/include/linux/atmlec.h
--- old/linux/include/linux/atmlec.h	Thu Jun  3 00:40:51 1999
+++ new/linux/include/linux/atmlec.h	Thu Jun  3 00:42:18 1999
@@ -18,7 +18,13 @@
 #define ATMLEC_MCAST _IO('a',ATMIOC_LANE+2)
 
 /* Maximum number of LEC interfaces (tweakable) */
-#define MAX_LEC_ITF 16
+#define MAX_LEC_ITF 48
+
+/* From the total of MAX_LEC_ITF, last NUM_TR_DEVS are reserved for Token Ring.
+ * E.g. if MAX_LEC_ITF = 48 and NUM_TR_DEVS = 8, then lec0-lec39 are for
+ * Ethernet ELANs and lec40-lec47 are for Token Ring ELANS.
+ */
+#define NUM_TR_DEVS 8
 
 typedef enum { 
         l_set_mac_addr,   l_del_mac_addr, 
@@ -28,6 +34,7 @@
         l_narp_req, /* LANE2 mandates the use of this */
         l_config,         l_flush_tran_id, 
         l_set_lecid,      l_arp_xmt,
+        l_rdesc_arp_xmt,
         l_associate_req,
         l_should_bridge   /* should we bridge this MAC? */
 } atmlec_msg_type;
diff -ur --new-file old/linux/net/802/tr.c new/linux/net/802/tr.c
--- old/linux/net/802/tr.c	Wed Dec 16 22:35:50 1998
+++ new/linux/net/802/tr.c	Thu Jun  3 00:42:21 1999
@@ -51,7 +51,7 @@
  
 struct rif_cache_s {	
 	unsigned char addr[TR_ALEN];
-	unsigned char iface[5];
+	unsigned char iface[10];
 	__u16 rcf;
 	__u16 rseg[8];
 	rif_cache next;
@@ -354,7 +354,8 @@
 		}
 
 		memcpy(&(entry->addr[0]),&(trh->saddr[0]),TR_ALEN);
-		memcpy(&(entry->iface[0]),dev->name,5);
+		strncpy(entry->iface,dev->name,sizeof(entry->iface));
+		entry->iface[sizeof(entry->iface)-1] = '\0';
 		entry->next=rif_table[hash];
 		entry->last_used=jiffies;
 		rif_table[hash]=entry;
diff -ur --new-file old/linux/net/atm/common.c new/linux/net/atm/common.c
--- old/linux/net/atm/common.c	Thu Jun  3 00:40:52 1999
+++ new/linux/net/atm/common.c	Thu Jun  3 00:42:21 1999
@@ -275,11 +275,14 @@
 	if (vpi != ATM_VPI_UNSPEC && vci != ATM_VCI_UNSPEC)
 		vcc->flags &= ~ATM_VF_PARTIAL;
 	else if (vcc->flags & ATM_VF_PARTIAL) return -EINVAL;
-	printk("atm_connect (TX: cl %d,bw %d-%d,sdu %d; RX: cl %d,bw %d-%d,"
-	    "sdu %d,AAL %d)\n",vcc->qos.txtp.traffic_class,
-	    vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu,
+	printk(KERN_DEBUG "atm_connect (TX: cl %d,bw %d-%d,sdu %d; "
+	    "RX: cl %d,bw %d-%d,sdu %d,AAL %s%d)\n",
+	    vcc->qos.txtp.traffic_class,vcc->qos.txtp.min_pcr,
+	    vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu,
 	    vcc->qos.rxtp.traffic_class,vcc->qos.rxtp.min_pcr,
-	    vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu,vcc->qos.aal);
+	    vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu,
+	    vcc->qos.aal == ATM_AAL5 ? "" : vcc->qos.aal == ATM_AAL0 ? "" :
+	    " ??? code ",vcc->qos.aal == ATM_AAL0 ? 0 : vcc->qos.aal);
 	if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD;
 	if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
 	    vcc->qos.rxtp.traffic_class == ATM_ANYCLASS)
diff -ur --new-file old/linux/net/atm/lec.c new/linux/net/atm/lec.c
--- old/linux/net/atm/lec.c	Thu Jun  3 00:40:52 1999
+++ new/linux/net/atm/lec.c	Thu Jun  3 00:42:21 1999
@@ -19,6 +19,11 @@
 #include <net/dst.h>
 #include <linux/proc_fs.h>
 
+/* TokenRing if needed */
+#ifdef CONFIG_TR
+#include <linux/trdevice.h>
+#endif
+
 /* And atm device */
 #include <linux/atmdev.h>
 #include <linux/atmlec.h>
@@ -75,7 +80,9 @@
 };
 
 /* will be lec0, lec1, lec2 etc. */
-static char myname[] = "lecx";
+static char myname[] = "lecxx";
+
+static unsigned char bus_mac[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff};
 
 /* Device structures */
 static struct device *dev_lec[MAX_LEC_ITF];
@@ -113,10 +120,7 @@
                 mesg->content.normal.flag = *(skb->nh.raw + BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET) & TOPOLOGY_CHANGE;
 
                 priv = (struct lec_priv *)dev->priv;
-                if (atm_charge(priv->lecd, skb2->truesize) == 0) {
-                        kfree_skb(skb2);
-                        return;
-                }
+                atm_force_charge(priv->lecd, skb2->truesize);
                 skb_queue_tail(&priv->lecd->recvq, skb2);
                 wake_up(&priv->lecd->sleep);
         }
@@ -126,6 +130,49 @@
 #endif /* CONFIG_BRIDGE */
 
 /*
+ * Modelled after tr_type_trans
+ * All multicast and ARE or STE frames go to BUS.
+ * Non source routed frames go by destination address.
+ * Last hop source routed frames go by destination address.
+ * Not last hop source routed frames go by _next_ route descriptor.
+ * Returns pointer to destination MAC address or fills in rdesc
+ * and returns NULL.
+ */
+#ifdef CONFIG_TR
+unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc)
+{
+        struct trh_hdr *trh;
+        int riflen, num_rdsc;
+        
+        trh = (struct trh_hdr *)packet;
+        if (trh->daddr[0] & (uint8_t)0x80)
+                return bus_mac; /* multicast */
+
+        if (trh->saddr[0] & TR_RII) {
+                riflen = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
+                if ((ntohs(trh->rcf) >> 13) != 0)
+                        return bus_mac; /* ARE or STE */
+        }
+        else
+                return trh->daddr; /* not source routed */
+
+        if (riflen < 6)
+                return trh->daddr; /* last hop, source routed */
+                
+        /* riflen is 6 or more, packet has more than one route descriptor */
+        num_rdsc = (riflen/2) - 1;
+        memset(rdesc, 0, ETH_ALEN);
+        /* offset 4 comes from LAN destination field in LE control frames */
+        if (trh->rcf & htons((uint16_t)TR_RCF_DIR_BIT))
+                memcpy(&rdesc[4], &trh->rseg[num_rdsc-2], sizeof(uint16_t));
+        else
+                memcpy(&rdesc[4], &trh->rseg[1], sizeof(uint16_t));
+
+        return NULL;
+}
+#endif /* CONFIG_TR */
+
+/*
  * Open/initialize the netdevice. This is called (in the current kernel)
  * sometime after booting when the 'ifconfig' program is run.
  *
@@ -155,7 +202,9 @@
         struct lecdatahdr_8023 *lec_h;
         struct atm_vcc *send_vcc;
 	struct lec_arp_table *entry;
-        unsigned char *nb;
+        unsigned char *nb, *dst;
+        unsigned char rdesc[ETH_ALEN]; /* Token Ring route descriptor */
+        int is_rdesc;
 #if DUMP_PACKETS > 0
         char buf[300];
         int i=0;
@@ -205,7 +254,7 @@
                 }
                 skb_push(skb, 2);
 
-                /* Put le header to place */
+                /* Put le header to place, works for TokenRing too */
                 lec_h = (struct lecdatahdr_8023*)skb->data;
                 lec_h->le_header = htons(priv->lecid); 
 
@@ -247,8 +296,19 @@
                 }
 
                 /* Send to right vcc */
+                is_rdesc = 0;
+                dst = lec_h->h_dest;
+#ifdef CONFIG_TR
+                if (priv->is_trdev) {
+                        dst = get_tr_dst(skb->data+2, rdesc);
+                        if (dst == NULL) {
+                                dst = rdesc;
+                                is_rdesc = 1;
+                        }
+                }
+#endif
                 entry = NULL;
-                send_vcc = lec_arp_resolve(priv, lec_h->h_dest, &entry);
+                send_vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);
                 DPRINTK("%s:send_vcc:%p vcc_flags:%x, entry:%p\n", dev->name,
                         send_vcc, send_vcc?send_vcc->flags:0, entry);
                 if (!send_vcc || !(send_vcc->flags & ATM_VF_READY)) {    
@@ -430,10 +490,7 @@
                         if (skb2 == NULL) break;
                         skb2->len = sizeof(struct atmlec_msg);
                         memcpy(skb2->data, mesg, sizeof(struct atmlec_msg));
-                        if (atm_charge(priv->lecd, skb2->truesize) == 0) {
-                                kfree_skb(skb2);
-                                break;
-                        }
+                        atm_force_charge(priv->lecd, skb2->truesize);
                         skb_queue_tail(&priv->lecd->recvq, skb2);
                         wake_up(&priv->lecd->sleep);
                 }
@@ -540,21 +597,13 @@
 	if (atm_addr)
 		memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
 
-        if (atm_charge(priv->lecd, skb->truesize) == 0) {
-                DPRINTK("lec: send_to_lecd, atm_charge()\n");
-                kfree_skb(skb);
-                return -1;
-        }
+        atm_force_charge(priv->lecd, skb->truesize);
 	skb_queue_tail(&priv->lecd->recvq, skb);
         wake_up(&priv->lecd->sleep);
 
         if (data != NULL) {
                 DPRINTK("lec: about to send %d bytes of data\n", data->len);
-                if (atm_charge(priv->lecd, data->truesize) == 0) {
-                        printk("lec: send_to_lecd, atm_charge\n");
-                        kfree_skb(data);
-                        return -1;
-                }
+                atm_force_charge(priv->lecd, data->truesize);
                 skb_queue_tail(&priv->lecd->recvq, data);
                 wake_up(&priv->lecd->sleep);
         }
@@ -574,13 +623,14 @@
 static int 
 lec_init(struct device *dev)
 {
-        dev->priv = kmalloc(sizeof(struct lec_priv), GFP_KERNEL);
-        if (!dev->priv)
-                return -ENOMEM;
-
-        memset(dev->priv,0,sizeof(struct lec_priv));
+        struct lec_priv *priv;
 
-        ether_setup(dev);
+        priv = (struct lec_priv *)dev->priv;
+        if (priv->is_trdev) {
+#ifdef CONFIG_TR
+                init_trdev(dev, 0);
+#endif
+        } else ether_setup(dev);
         dev->change_mtu = lec_change_mtu;
         dev->open = lec_open;
         dev->stop = lec_close;
@@ -655,6 +705,10 @@
                 }
                 skb->dev = dev;
                 skb->data += 2; /* skip lec_id */
+#ifdef CONFIG_TR
+                if (priv->is_trdev) skb->protocol = tr_type_trans(skb, dev);
+                else
+#endif
                 skb->protocol = eth_type_trans(skb, dev);
                 netif_rx(skb);
                 priv->stats.rx_packets++;
@@ -703,8 +757,13 @@
                 i = 0;
         else
                 i = arg;
+#ifdef CONFIG_TR
         if (arg >= MAX_LEC_ITF)
                 return -EINVAL;
+#else /* Reserve the top NUM_TR_DEVS for TR */
+        if (arg >= (MAX_LEC_ITF-NUM_TR_DEVS))
+                return -EINVAL;
+#endif
         if (!dev_lec[i]) {
                 dev_lec[i] = (struct device*)kmalloc(sizeof(struct device)+
                                                      sizeof(myname)+1, 
@@ -712,13 +771,23 @@
                 if (!dev_lec[i])
                         return -ENOMEM;
                 memset(dev_lec[i],0, sizeof(struct device)+sizeof(myname)+1);
+
+                dev_lec[i]->priv = kmalloc(sizeof(struct lec_priv), GFP_KERNEL);
+                if (!dev_lec[i]->priv)
+                        return -ENOMEM;
+                memset(dev_lec[i]->priv,0,sizeof(struct lec_priv));
+                priv = (struct lec_priv *)dev_lec[i]->priv;
+
+                if (i >= (MAX_LEC_ITF - NUM_TR_DEVS))
+                        priv->is_trdev = 1;
+
                 dev_lec[i]->name = (char*)(dev_lec[i]+1);
                 sprintf(dev_lec[i]->name, "lec%d",i);
                 dev_lec[i]->init = lec_init;
                 if ((result = register_netdev(dev_lec[i])) !=0)
                         return result;
-                priv = (struct lec_priv *)dev_lec[i]->priv;
-	} else {
+                sprintf(dev_lec[i]->name, "lec%d", i); /* init_trdev globbers device name */
+        } else {
                 priv = (struct lec_priv *)dev_lec[i]->priv;
                 if (priv->lecd)
                         return -EADDRINUSE;
@@ -777,6 +846,7 @@
 {
         int i;
         extern struct atm_lane_ops atm_lane_ops;
+        struct lec_priv *priv;
 
         if (MOD_IN_USE) {
                 printk(KERN_NOTICE "lec.c: module in use\n");
@@ -790,7 +860,13 @@
 
         for (i = 0; i < MAX_LEC_ITF; i++) {
                 if (dev_lec[i] != NULL) {
-                        unregister_netdev(dev_lec[i]);
+                        priv = (struct lec_priv *)dev_lec[i]->priv;
+                        if (priv->is_trdev) {
+#ifdef CONFIG_TR
+                                unregister_trdev(dev_lec[i]);
+#endif
+                        } else
+                                unregister_netdev(dev_lec[i]);
                         kfree(dev_lec[i]->priv);
                         kfree(dev_lec[i]);
                         dev_lec[i] = NULL;
@@ -1411,8 +1487,10 @@
         DPRINTK("lec_arp_expire_arp\n");
         if (entry->status == ESI_ARP_PENDING) {
                 if (entry->no_tries <= entry->priv->max_retry_count) {
-                        send_to_lecd(entry->priv, l_arp_xmt, 
-                                     entry->mac_addr, NULL, NULL);
+                        if (entry->is_rdesc)
+                                send_to_lecd(entry->priv, l_rdesc_arp_xmt, entry->mac_addr, NULL, NULL);
+                        else
+                                send_to_lecd(entry->priv, l_arp_xmt, entry->mac_addr, NULL, NULL);
                         entry->no_tries++;
                 }
                 entry->timer.expires = jiffies + (1*HZ);
@@ -1552,10 +1630,9 @@
  * 
  */
 struct atm_vcc*
-lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find,
+lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find, int is_rdesc,
                 struct lec_arp_table **ret_entry)
 {
-        unsigned char bus_mac[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff};
         struct lec_arp_table *entry;
 
         if (mac_to_find[0]&0x01) {
@@ -1611,7 +1688,11 @@
                 entry->status = ESI_ARP_PENDING;
                 entry->no_tries = 1;
                 entry->last_used = entry->timestamp = jiffies;
-                send_to_lecd(priv, l_arp_xmt, mac_to_find, NULL, NULL);
+                entry->is_rdesc = is_rdesc;
+                if (entry->is_rdesc)
+                        send_to_lecd(priv, l_rdesc_arp_xmt, mac_to_find, NULL, NULL);
+                else
+                        send_to_lecd(priv, l_arp_xmt, mac_to_find, NULL, NULL);
                 entry->timer.expires = jiffies + (1*HZ);
                 entry->timer.function = lec_arp_expire_arp;
                 add_timer(&entry->timer);
@@ -1764,7 +1845,6 @@
 {
         struct lec_arp_table *entry;
         int i, found_entry=0;
-        unsigned char bus_mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff,0xff};
 
         lec_arp_lock(priv);
         if (ioc_data->receive == 2) {
@@ -2042,20 +2122,28 @@
         struct lec_arp_table *entry, *prev;
         struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data;
         unsigned long flags;
-  
+        unsigned char *src;
+#ifdef CONFIG_TR
+        struct lecdatahdr_8025 *tr_hdr = (struct lecdatahdr_8025 *)skb->data;
+
+        if (priv->is_trdev) src = tr_hdr->h_source;
+        else
+#endif
+        src = hdr->h_source;
+
         lec_arp_lock(priv);
         entry = priv->lec_arp_empty_ones;
         if (vcc == entry->vcc) {
                 save_flags(flags);
                 cli();
                 del_timer(&entry->timer);
-                memcpy(entry->mac_addr, hdr->h_source, ETH_ALEN);
+                memcpy(entry->mac_addr, src, ETH_ALEN);
                 entry->status = ESI_FORWARD_DIRECT;
                 entry->last_used = jiffies;
                 priv->lec_arp_empty_ones = entry->next;
                 restore_flags(flags);
                 /* We might have got an entry */
-                if ((prev=lec_arp_find(priv,hdr->h_source))) {
+                if ((prev=lec_arp_find(priv,src))) {
                         lec_arp_remove(priv->lec_arp_tables, prev);
                         kfree(prev);
                 }
@@ -2077,12 +2165,12 @@
         save_flags(flags);
         cli();
         del_timer(&entry->timer);
-        memcpy(entry->mac_addr, hdr->h_source, ETH_ALEN);
+        memcpy(entry->mac_addr, src, ETH_ALEN);
         entry->status = ESI_FORWARD_DIRECT;
         entry->last_used = jiffies;
         prev->next = entry->next;
         restore_flags(flags);
-        if ((prev = lec_arp_find(priv, hdr->h_source))) {
+        if ((prev = lec_arp_find(priv, src))) {
                 lec_arp_remove(priv->lec_arp_tables,prev);
                 kfree(prev);
         }
diff -ur --new-file old/linux/net/atm/lec.h new/linux/net/atm/lec.h
--- old/linux/net/atm/lec.h	Thu Jun  3 00:40:52 1999
+++ new/linux/net/atm/lec.h	Thu Jun  3 00:42:21 1999
@@ -26,7 +26,7 @@
   unsigned short le_header;
   unsigned char ac_pad;
   unsigned char fc;
-  unsigned char h_dst[ETH_ALEN];
+  unsigned char h_dest[ETH_ALEN];
   unsigned char h_source[ETH_ALEN];
 };
 
@@ -131,6 +131,7 @@
 	int itfnum;        /* e.g. 2 for lec2, 5 for lec5        */
         struct lane2_ops *lane2_ops; /* can be NULL for LANE v1  */
         int is_proxy;      /* bridge between ATM and Ethernet    */
+        int is_trdev;      /* Device type, 0 = Ethernet, 1 = TokenRing */
 };
 
 int lecd_attach(struct atm_vcc *vcc, int arg);
diff -ur --new-file old/linux/net/atm/lec_arpc.h new/linux/net/atm/lec_arpc.h
--- old/linux/net/atm/lec_arpc.h	Thu Jun  3 00:40:53 1999
+++ new/linux/net/atm/lec_arpc.h	Thu Jun  3 00:42:21 1999
@@ -14,6 +14,7 @@
         struct lec_arp_table *next;          /* Linked entry list */
         unsigned char atm_addr[ATM_ESA_LEN]; /* Atm address */
         unsigned char mac_addr[ETH_ALEN];    /* Mac address */
+        int is_rdesc;                        /* Mac address is a route descriptor */
         struct atm_vcc *vcc;                 /* Vcc this entry is attached */
         struct atm_vcc *recv_vcc;            /* Vcc we receive data from */
         void (*old_push)(struct atm_vcc *vcc,struct sk_buff *skb); 
@@ -96,6 +97,7 @@
 
 struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
                                 unsigned char *mac_to_addr,
+                                int is_rdesc,
                                 struct lec_arp_table **ret_entry);
 void lec_vcc_added(struct lec_priv *dev,
                    struct atmlec_ioc *ioc_data, struct atm_vcc *vcc,
diff -ur --new-file old/linux/net/atm/mpc.c new/linux/net/atm/mpc.c
--- old/linux/net/atm/mpc.c	Thu Jun  3 00:40:53 1999
+++ new/linux/net/atm/mpc.c	Thu Jun  3 00:42:21 1999
@@ -951,12 +951,7 @@
                 return -ENOMEM;
         skb_put(skb, sizeof(struct k_message));
         memcpy(skb->data, mesg, sizeof(struct k_message));
-        if (atm_charge(mpc->mpoad_vcc, skb->truesize) == 0) {
-                printk("mpoa: msg_to_mpoad: atm_charge failed\n");
-                kfree_skb(skb);
-                return -ENOMEM;
-        }
-
+        atm_force_charge(mpc->mpoad_vcc, skb->truesize);
         skb_queue_tail(&mpc->mpoad_vcc->recvq, skb);
         wake_up(&mpc->mpoad_vcc->sleep);
 
@@ -1215,12 +1210,7 @@
         if (entry != NULL)
                 purge_msg->content.eg_info = entry->ctrl_info;
 
-        if (atm_charge(vcc, skb->truesize) == 0) {
-                printk("mpoa: purge_egress_shortcut: atm_charge failed\n");
-                kfree_skb(skb);
-                return;
-        }
-
+        atm_force_charge(vcc, skb->truesize);
         skb_queue_tail(&vcc->recvq, skb);
         wake_up(&vcc->sleep);
         dprintk("mpoa: purge_egress_shortcut: exiting:\n");
diff -ur --new-file old/linux/net/atm/proc.c new/linux/net/atm/proc.c
--- old/linux/net/atm/proc.c	Thu Jun  3 00:40:53 1999
+++ new/linux/net/atm/proc.c	Thu Jun  3 00:42:21 1999
@@ -245,8 +245,10 @@
 {
 	static const char *class_name[] = { "off","UBR","CBR","VBR","ABR" };
 	static const char *aal_name[] = {
-		"0",	"1",	"2",	"3/4",	/*  0- 3 */
-		"???",	"5",	"???",	"???" };/*  4- 7 */
+		"---",	"1",	"2",	"3/4",	/*  0- 3 */
+		"???",	"5",	"???",	"???",	/*  4- 7 */
+		"???",	"???",	"???",	"???",	/*  8-11 */
+		"???",	"0",	"???",	"???"};	/* 12-15 */
 	int off;
 
 	off = sprintf(buf,"%3d %3d %5d %-3s %7d %-5s %7d %-6s",