patch-2.3.42 linux/drivers/ieee1394/ohci1394.c

Next file: linux/drivers/ieee1394/ohci1394.h
Previous file: linux/drivers/ieee1394/ieee1394_transactions.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.41/linux/drivers/ieee1394/ohci1394.c linux/drivers/ieee1394/ohci1394.c
@@ -1,5 +1,5 @@
 /*
- * ti_ohci1394.c - Texas Instruments Ohci1394 driver
+ * ohci1394.c - driver for OHCI 1394 boards
  * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
  *                        Gord Peters <GordPeters@smarttech.com>
  *
@@ -18,6 +18,7 @@
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
@@ -40,8 +41,6 @@
 #include "ieee1394_core.h"
 #include "ohci1394.h"
 
-#undef CONFIG_PROC_FS
-
 /* print general (card independent) information */
 #define PRINT_G(level, fmt, args...) \
 printk(level "ohci1394: " fmt "\n" , ## args)
@@ -68,7 +67,6 @@
  * IEEE-1394 functionality section *
  ***********************************/
 
-
 #if 0 /* not needed at this time */
 static int get_phy_reg(struct ti_ohci *ohci, int addr) 
 {
@@ -324,31 +322,53 @@
 	}
 
 	/* Initialize AR dma */
-	ohci->AR_resp_prg->control=0x283C << 16 | AR_RESP_BUF_SIZE;
-	ohci->AR_resp_prg->address=virt_to_bus(ohci->AR_resp_buf);
-	ohci->AR_resp_prg->status=AR_RESP_BUF_SIZE;
-	PRINT(KERN_INFO, ohci->id, "AR control: %x",
-	      ohci->AR_resp_prg->control);
-	PRINT(KERN_INFO, ohci->id, "AR status: %x %d",
-	      ohci->AR_resp_prg->status & 0xffff,
-	      ohci->AR_resp_prg->status & 0xffff);
-
-	/* Tell the controller where the AR program is */
-	reg_write(ohci, OHCI1394_AsRspRcvCommandPtr,
-		  virt_to_bus(ohci->AR_resp_prg)|0x00000001);
+	/* make sure the context isn't running, dead, or active */
+	if (!(reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) & 0x00008F00)) {
 
-#if 1
-        /* Accept phy packets into AR request context */
-        reg_write(ohci, OHCI1394_LinkControlSet, 0x00000400);
-#endif
+                /* initialize AR program */
+                for (i= 0; i < AR_RESP_NUM_DESC; i++) {
+
+			/* end of descriptor list? */
+                        if ((i + 1) < AR_RESP_NUM_DESC) {
+                                ohci->AR_resp_prg[i]->control=
+				  (0x283C << 16) | AR_RESP_BUF_SIZE;
+                                ohci->AR_resp_prg[i]->branchAddress=
+				  (virt_to_bus(ohci->AR_resp_prg[i + 1])
+                                         & 0xfffffff0) | 0x1;
+                        } else {
+                                ohci->AR_resp_prg[i]->control=
+                                        (0x283C << 16) | AR_RESP_BUF_SIZE;
+                                ohci->AR_resp_prg[i]->branchAddress=
+                                        (virt_to_bus(ohci->AR_resp_prg[0])
+                                         & 0xfffffff0) | 0x1;
+                        }
+
+                        ohci->AR_resp_prg[i]->address=
+                                virt_to_bus(ohci->AR_resp_buf[i]);
+                        ohci->AR_resp_prg[i]->status= AR_RESP_BUF_SIZE;
+		}
+
+		/* Tell the controller where the first AR program is */
+		reg_write(ohci, OHCI1394_AsRspRcvCommandPtr,
+			  virt_to_bus(ohci->AR_resp_prg[0]) | 0x1 );
+
+		/* Accept phy packets into AR request context */
+		reg_write(ohci, OHCI1394_LinkControlSet, 0x00000400);
+
+		/* Run AR context */
+		reg_write(ohci, OHCI1394_AsRspRcvContextControlSet, 0x00008000);
+	}
 
-	/* Run AR context */
-	reg_write(ohci, OHCI1394_AsRspRcvContextControlSet, 0x00008000);
+	/* Specify AT retries */
+	reg_write(ohci, OHCI1394_ATRetries, 
+		  OHCI1394_MAX_AT_REQ_RETRIES |
+		  (OHCI1394_MAX_AT_RESP_RETRIES<<4) |
+		  (OHCI1394_MAX_PHYS_RESP_RETRIES<<8));
 
 #ifndef __BIG_ENDIAN
-	reg_write(ohci, OHCI1394_HCControlSet, 0x40000000);
-#else
 	reg_write(ohci, OHCI1394_HCControlClear, 0x40000000);
+#else
+	reg_write(ohci, OHCI1394_HCControlSet, 0x40000000);
 #endif
 
 	/* Enable interrupts */
@@ -386,8 +406,9 @@
 	int i=0;
 	struct hpsb_packet *packet = ohci->async_queue;
 	struct dma_cmd prg;
+#if 0
 	quadlet_t *ptr = (quadlet_t *)ohci->AT_req_prg;
-
+#endif
 	//HPSB_TRACE();
 
         /* stop the channel program if it's still running */
@@ -435,14 +456,14 @@
                         prg.status = 0;
                         memcpy(ohci->AT_req_prg, &prg, 16);
                         memcpy(ohci->AT_req_prg + 1, packet->header, 16);
-
+#if 0
                         PRINT(KERN_INFO, ohci->id,
                               "dma_cmd: %08x %08x %08x %08x",
                               *ptr, *(ptr+1), *(ptr+2), *(ptr+3));
                         PRINT(KERN_INFO, ohci->id,
                               "header: %08x %08x %08x %08x",
                               *(ptr+4), *(ptr+5), *(ptr+6), *(ptr+7));
-
+#endif
                         reg_write(ohci, OHCI1394_AsReqTrCommandPtr, 
                                   virt_to_bus(ohci->AT_req_prg)|0x2);
                 }
@@ -455,11 +476,11 @@
                 prg.branchAddress = 0;
                 prg.status = 0;
                 memcpy(ohci->AT_req_prg, &prg, 16);
-
+#if 0
                 PRINT(KERN_INFO, ohci->id,
                       "dma_cmd: %08x %08x %08x %08x",
                       *ptr, *(ptr+1), *(ptr+2), *(ptr+3));
-
+#endif
                 reg_write(ohci, OHCI1394_AsReqTrCommandPtr, 
                           virt_to_bus(ohci->AT_req_prg)|0x2);
         }
@@ -638,6 +659,26 @@
  * Global stuff (interrupt handler, init/shutdown code) *
  ********************************************************/
 
+static void stop_ar_resp_context(struct ti_ohci *ohci, char *msg)
+{
+	int i=0;
+
+	/* stop the channel program if it's still running */
+	reg_write(ohci, OHCI1394_AsRspRcvContextControlClear, 0x8000);
+   
+	/* Wait until it effectively stops */
+	while (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) 
+	       & 0x400) {
+		i++;
+		if (i>5000) {
+			PRINT(KERN_ERR, ohci->id, 
+			      "runaway loop in Dma Ar Resp. bailing out...");
+			break;
+		}
+	}
+	PRINT(KERN_ERR, ohci->id, "%s\n async response receive dma stopped\n", msg);
+}
+
 static void ohci_irq_handler(int irq, void *dev_id,
                              struct pt_regs *regs_are_unused)
 {
@@ -656,15 +697,14 @@
 	   event,reg_read(ohci, OHCI1394_IntMaskSet)); */
 
 	if (event & OHCI1394_busReset) {
+#if 0
 		PRINT(KERN_INFO, ohci->id, "bus reset interrupt");
+#endif
 		if (!host->in_bus_reset) {
 			hpsb_bus_reset(host);
 		}
 		ohci->NumBusResets++;
 	}
-	if (event & OHCI1394_reqTxComplete) {
-		PRINT(KERN_INFO, ohci->id, "reqTxComplete int received");
-	}
 	if (event & OHCI1394_RQPkt) {
 		PRINT(KERN_INFO, ohci->id, "RQPkt int received");
 	}
@@ -673,58 +713,55 @@
 		      reg_read(ohci, OHCI1394_AsReqRcvContextControlSet));
 	}
 	if (event & OHCI1394_RSPkt) {
-		int rcv_bytes;
-		int i=0;
+		unsigned int idx,offset,rescount;
 
-		/* we calculate the number of received bytes from the
-		   residual count field */
-		rcv_bytes = AR_RESP_BUF_SIZE - 
-		  (ohci->AR_resp_prg->status & 0xFFFF);
-
-		PRINT(KERN_INFO, ohci->id, "AR_status 0x%x %d, %d bytes read", 
-		      ohci->AR_resp_prg->status, 
-		      ohci->AR_resp_prg->status & 0xffff, 
-		      rcv_bytes);
-
-		ohci->AR_resp_active = 0;
-
-		if ((ohci->AR_resp_prg->status & 0x84000000) 
-		    && (ohci->AR_resp_prg->status & 0xFFFF) >= 8 ) {
-			hpsb_packet_received(host, ohci->AR_resp_buf, 
-					     rcv_bytes);
-		} else {
-			//HPSB_TRACE();
-			PRINT(KERN_ERR, ohci->id, 
-			      "AR resp DMA program status value 0x%x is incorrect!",
-			      ohci->AR_resp_prg->status);
-		}
+                spin_lock(&ohci->AR_resp_lock);
 
+		idx = ohci->AR_resp_buf_th_ind;
+		offset = ohci->AR_resp_buf_th_offset;
 
-		/* --------------- FIXME ---------------------------------
-		   this is a complete hack... we stop the dma prg
-		   and start it again so as to reset the dma buffer address
-		   Very slow, very bad design... to change ASAP */
-		  
-		/* stop the channel program if it's still running */
-		reg_write(ohci, OHCI1394_AsRspRcvContextControlClear, 0x8000);
-   
-		/* Wait until it effectively stops */
-		while (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) 
-		       & 0x400) {
-			i++;
-			if (i>5000) {
-				PRINT(KERN_ERR, ohci->id, 
-				      "runaway loop in DmaAT. bailing out...");
-				break;
+		rescount = ohci->AR_resp_prg[idx]->status&0xffff;
+		ohci->AR_resp_bytes_left +=  AR_RESP_BUF_SIZE - rescount - offset;
+		offset = AR_RESP_BUF_SIZE - rescount;
+
+		if (!rescount) { /* We cross a buffer boundary */
+			idx = (idx+1) % AR_RESP_NUM_DESC;
+
+#if 0 
+			/* This bit of code does not work */
+			/* Let's see how many bytes were written in the async response 
+			   receive buf since last interrupt. This is done by finding 
+			   the next active context (See OHCI Spec p91) */
+			while (ohci->AR_resp_bytes_left <= AR_RESP_TOTAL_BUF_SIZE) {
+				if (ohci->AR_resp_prg[idx]->status&0x04000000) break;
+				idx = (idx+1) % AR_RESP_NUM_DESC;
+				PRINT(KERN_INFO,ohci->id,"crossing more than one buffer boundary !!!");
+				ohci->AR_resp_bytes_left += AR_RESP_BUF_SIZE;
 			}
+#endif 
+			/* ASSUMPTION: only one buffer boundary is crossed */
+			rescount = ohci->AR_resp_prg[idx]->status&0xffff;
+			offset = AR_RESP_BUF_SIZE - rescount;
+			ohci->AR_resp_bytes_left += offset;
+		}
+		if (offset==AR_RESP_BUF_SIZE) {
+			offset=0;
+			idx = (idx+1) % AR_RESP_NUM_DESC;
 		}
+		ohci->AR_resp_buf_th_ind = idx;
+		ohci->AR_resp_buf_th_offset = offset;
 
-		reg_write(ohci, OHCI1394_AsRspRcvCommandPtr,
-			  virt_to_bus(ohci->AR_resp_prg)|0x00000001);
-		ohci->AR_resp_prg->status=AR_RESP_BUF_SIZE;
-		reg_write(ohci, OHCI1394_AsRspRcvContextControlSet, 0x8000);
+                /* is buffer processing too slow? (all buffers used) */
+		if (ohci->AR_resp_bytes_left > AR_RESP_TOTAL_BUF_SIZE) {
+			stop_ar_resp_context(ohci,"async response receive processing too slow");
+                        spin_unlock(&ohci->AR_resp_lock);
+			return;
+		}
+                spin_unlock(&ohci->AR_resp_lock);
 
-		/* ---------------- end of FIXME --------------------------*/
+		/* queue bottom half in immediate queue */
+		queue_task(&ohci->AR_resp_pdl_task, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
 	}
 	if (event & OHCI1394_isochRx) {
 		quadlet_t isoRecvIntEvent;
@@ -826,8 +863,10 @@
 				send_next_async(ohci);
 			}
 			spin_unlock(&ohci->async_queue_lock);
+#if 0
 			PRINT(KERN_INFO,ohci->id,
 			      "packet sent with ack code %d",ack);
+#endif
 			hpsb_packet_sent(host, packet, ack);	    
 		} else 
 		  PRINT(KERN_INFO,ohci->id,
@@ -839,6 +878,129 @@
 	ohci->NumInterrupts++;
 }
 
+
+/* This is the bottom half that processes async response receive descriptor buffers. */
+static void ohci_ar_resp_proc_desc(void *data)
+{
+	quadlet_t *buf_ptr;
+	char *split_ptr;
+	unsigned int split_left;
+	struct ti_ohci *ohci= (struct ti_ohci*)data;
+        unsigned int packet_length;
+        unsigned int idx,offset,tcode;
+        unsigned long flags;
+	char msg[256];
+
+        spin_lock_irqsave(&ohci->AR_resp_lock, flags);
+
+	idx = ohci->AR_resp_buf_bh_ind;
+	offset = ohci->AR_resp_buf_bh_offset;
+
+	buf_ptr = ohci->AR_resp_buf[idx];
+	buf_ptr += offset/4;
+
+        while(ohci->AR_resp_bytes_left > 0) {
+
+                /* check to see if a fatal error occurred */
+                if ((ohci->AR_resp_prg[idx]->status >> 16) & 0x800) {
+			sprintf(msg,"fatal async response receive error -- status is %d",
+				ohci->AR_resp_prg[idx]->status & 0x1F);
+			stop_ar_resp_context(ohci, msg);
+                        spin_unlock_irqrestore(&ohci->AR_resp_lock, flags);
+                        return;
+                }
+
+                spin_unlock_irqrestore(&ohci->AR_resp_lock, flags);
+
+		/* Let's see what kind of packet is in there */
+		tcode = (buf_ptr[0]>>4)&0xf;
+		if (tcode==2) /* no-data receive */
+		  packet_length=16;
+		else if (tcode==6) /* quadlet receive */
+		  packet_length=20;
+		else if (tcode==7) { /* block receive */
+			/* Where is the data length ? */
+			if (offset+12>=AR_RESP_BUF_SIZE) 
+			  packet_length=(ohci->AR_resp_buf[(idx+1)%AR_RESP_NUM_DESC]
+					 [3-(AR_RESP_BUF_SIZE-offset)/4]>>16)+20;
+			else 
+			  packet_length=(buf_ptr[3]>>16)+20;
+                        if (packet_length % 4)
+			  packet_length += 4 - (packet_length % 4);
+		}
+		else /* something is wrong */ {
+			sprintf(msg,"unexpected packet tcode %d in async response receive buffer",tcode);
+			stop_ar_resp_context(ohci,msg);
+			return;
+		}
+		if ((offset+packet_length)>AR_RESP_BUF_SIZE) {
+			/* we have a split packet */
+			if (packet_length>AR_RESP_SPLIT_PACKET_BUF_SIZE) {
+				sprintf(msg,"packet size %d bytes exceed split packet buffer size %d bytes",
+					packet_length,AR_RESP_SPLIT_PACKET_BUF_SIZE);
+				stop_ar_resp_context(ohci, msg);
+				return;
+			}
+			split_left = packet_length;
+			split_ptr = (char *)ohci->AR_resp_spb;
+			while (split_left>0) {
+				memcpy(split_ptr,buf_ptr,AR_RESP_BUF_SIZE-offset);
+				split_left -= AR_RESP_BUF_SIZE-offset;
+				split_ptr += AR_RESP_BUF_SIZE-offset;
+				ohci->AR_resp_prg[idx]->status = AR_RESP_BUF_SIZE;
+				idx = (idx+1) % AR_RESP_NUM_DESC;
+				buf_ptr = ohci->AR_resp_buf[idx];
+				offset=0;
+				while (split_left >= AR_RESP_BUF_SIZE) {
+					memcpy(split_ptr,buf_ptr,AR_RESP_BUF_SIZE);
+					split_ptr += AR_RESP_BUF_SIZE;
+					split_left -= AR_RESP_BUF_SIZE;
+					ohci->AR_resp_prg[idx]->status = AR_RESP_BUF_SIZE;
+					idx = (idx+1) % AR_RESP_NUM_DESC;
+					buf_ptr = ohci->AR_resp_buf[idx];
+				}
+				if (split_left>0) {
+					memcpy(split_ptr,buf_ptr,split_left);
+					offset = split_left;
+					split_left=0;
+					buf_ptr += split_left/4;
+				}
+			}
+#if 0
+			PRINT(KERN_INFO,ohci->id,"AR resp: received split packet tcode=%d length=%d",
+			      tcode,packet_length);
+#endif
+			hpsb_packet_received(ohci->host, ohci->AR_resp_spb, packet_length);
+			ohci->AR_resp_bytes_left -= packet_length;
+		}
+		else {
+#if 0
+			PRINT(KERN_INFO,ohci->id,"AR resp: received packet tcode=%d length=%d",
+			      tcode,packet_length);
+#endif
+			hpsb_packet_received(ohci->host, buf_ptr, packet_length);
+			offset += packet_length;
+			buf_ptr += packet_length/4;
+			ohci->AR_resp_bytes_left -= packet_length;
+			if (offset==AR_RESP_BUF_SIZE) {
+				ohci->AR_resp_prg[idx]->status = AR_RESP_BUF_SIZE;
+				idx = (idx+1) % AR_RESP_NUM_DESC;
+				buf_ptr = ohci->AR_resp_buf[idx];
+				offset=0;
+			}
+		}
+		
+	}
+	
+	if (ohci->AR_resp_bytes_left<0) 
+	  stop_ar_resp_context(ohci, "Sync problem in AR resp dma buffer");
+
+	ohci->AR_resp_buf_bh_ind = idx;
+	ohci->AR_resp_buf_bh_offset = offset;
+
+        spin_unlock_irqrestore(&ohci->AR_resp_lock, flags);
+}
+
 /* This is the bottom half that processes iso receive descriptor buffers. */
 static void ohci_ir_proc_desc(void *data)
 {
@@ -1023,23 +1185,61 @@
 		FAIL("failed to allocate DMA buffer for self-id packets");
 	}
 
-	/* AR dma buffer allocation */
-	ohci->AR_resp_buf = kmalloc(AR_RESP_BUF_SIZE, GFP_KERNEL);
-	if (ohci->AR_resp_buf != NULL) {
-		memset(ohci->AR_resp_buf, 0, AR_RESP_BUF_SIZE);
-	} else {
-		FAIL("failed to allocate AR response DMA buffer");
+	/* AR dma buffer and program allocation */
+	ohci->AR_resp_buf=
+	        kmalloc(AR_RESP_NUM_DESC * sizeof(quadlet_t*),
+			GFP_KERNEL);
+
+	if (ohci->AR_resp_buf == NULL) {
+		FAIL("failed to allocate AR response receive DMA buffer");
 	}
 
-	/* AR dma program allocation */
-	ohci->AR_resp_prg = (struct dma_cmd *) kmalloc(AR_RESP_PRG_SIZE, 
-						       GFP_KERNEL);
-	if (ohci->AR_resp_prg != NULL) {
-		memset(ohci->AR_resp_prg, 0, AR_RESP_PRG_SIZE);
-	} else {
-		FAIL("failed to allocate AR response DMA program");
+	ohci->AR_resp_prg=
+		kmalloc(AR_RESP_NUM_DESC * sizeof(struct dma_cmd*),
+			GFP_KERNEL);
+
+	if (ohci->AR_resp_prg == NULL) {
+		FAIL("failed to allocate AR response receive DMA program");
 	}
 
+	ohci->AR_resp_spb= kmalloc(AR_RESP_SPLIT_PACKET_BUF_SIZE, GFP_KERNEL);
+
+	if (ohci->AR_resp_spb == NULL) {
+		FAIL("failed to allocate AR response split packet buffer");
+	}
+
+	for (i= 0; i < AR_RESP_NUM_DESC; i++) {
+                ohci->AR_resp_buf[i]= kmalloc(AR_RESP_BUF_SIZE, GFP_KERNEL);
+
+                if (ohci->AR_resp_buf[i] != NULL) {
+                        memset(ohci->AR_resp_buf[i], 0, AR_RESP_BUF_SIZE);
+                } else {
+                        FAIL("failed to allocate AR response DMA buffer");
+                }
+
+                ohci->AR_resp_prg[i]= kmalloc(sizeof(struct dma_cmd),
+                                                   GFP_KERNEL);
+
+                if (ohci->AR_resp_prg[i] != NULL) {
+                        memset(ohci->AR_resp_prg[i], 0,
+                               sizeof(struct dma_cmd));
+                } else {
+                        FAIL("failed to allocate AR response DMA buffer");
+                }
+
+	}
+
+        ohci->AR_resp_buf_th_ind = 0;
+        ohci->AR_resp_buf_th_offset = 0;
+        ohci->AR_resp_buf_bh_ind = 0;
+        ohci->AR_resp_buf_bh_offset = 0;
+        ohci->AR_resp_bytes_left = 0;
+        spin_lock_init(&ohci->AR_resp_lock);
+
+        /* initialize AR response receive task */
+        ohci->AR_resp_pdl_task.routine= ohci_ar_resp_proc_desc;
+        ohci->AR_resp_pdl_task.data= (void*)ohci;
+
 	/* AT dma program allocation */
 	ohci->AT_req_prg = (struct dma_cmd *) kmalloc(AT_REQ_PRG_SIZE, 
 						      GFP_KERNEL);
@@ -1129,8 +1329,12 @@
 p += sprintf(p,fmt,reg_read(ohci, reg0),\
 	       reg_read(ohci, reg1),reg_read(ohci, reg2));
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+static int ohci_get_status(char *buf)
+#else
 int ohci_get_info(char *buf, char **start, off_t fpos, 
 		  int length, int dummy)
+#endif
 {
 	struct ti_ohci *ohci=&cards[0];
 	struct hpsb_host *host=ohci->host;
@@ -1165,15 +1369,23 @@
 		     host->is_irm ? "iso_res_mgr" : "",
 		     host->is_busmgr ? "bus_mgr" : "");
   
-	p += sprintf(p,"\n### ohci data ###\n");
-	p += sprintf(p,"AR_resp_buf : %p  AR_resp_prg: %p\n",
-		     ohci->AR_resp_buf, ohci->AR_resp_prg);
-
+	p += sprintf(p,"\n---Iso Receive DMA---\n");
         for (i= 0; i < IR_NUM_DESC; i++) {
                 p += sprintf(p, "IR_recv_buf[%d] : %p  IR_recv_prg[%d]: %p\n",
                              i, ohci->IR_recv_buf[i], i, ohci->IR_recv_prg[i]);
 	}
 
+	
+	p += sprintf(p,"\n---Async Reponse Receive DMA---\n");
+        for (i= 0; i < AR_RESP_NUM_DESC; i++) {
+                p += sprintf(p, "AR_resp_buf[%d] : %p  AR_resp_prg[%d]: %p\n",
+                             i, ohci->AR_resp_buf[i], i, ohci->AR_resp_prg[i]);
+	}
+	p += sprintf(p, "Current AR resp buf in irq handler: %d offset: %d\n",
+		     ohci->AR_resp_buf_th_ind,ohci->AR_resp_buf_th_offset);
+	p += sprintf(p, "Current AR resp buf in bottom half: %d offset: %d\n",
+		     ohci->AR_resp_buf_bh_ind,ohci->AR_resp_buf_bh_offset);
+	
 	/* ----- Register Dump ----- */
 	p += sprintf(p,"\n### HC Register dump ###\n");
 	SR("Version     : %08x  GUID_ROM    : %08x  ATRetries   : %08x\n",
@@ -1242,12 +1454,27 @@
 		     phyreg&0x3f);
 #endif
 
+#if 0
 	p += sprintf(p,"AR_resp_prg ctrl: %08x\n",ohci->AR_resp_prg->control);
 	p += sprintf(p,"AR_resp_prg status: %08x\n",ohci->AR_resp_prg->status);
+#endif
 
 	return  p - buf;
 }
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+static int ohci1394_read_proc(char *page, char **start, off_t off,
+			      int count, int *eof, void *data)
+{
+        int len = ohci_get_status(page);
+        if (len <= off+count) *eof = 1;
+        *start = page + off;
+        len -= off;
+        if (len>count) len = count;
+        if (len<0) len = 0;
+        return len;
+}
+#else
 struct proc_dir_entry ohci_proc_entry = 
 {
 	0,			/* Inode number - dynamic */
@@ -1261,18 +1488,36 @@
 	ohci_get_info,		/* The read function for this file */
 	NULL
 }; 
-#endif
+#endif /* LINUX_VERSION_CODE */
+#endif /* CONFIG_PROC_FS */
 
 static void remove_card(struct ti_ohci *ohci)
 {
 	if (ohci->registers) 
 	  iounmap(ohci->registers);
-	if (ohci->AR_resp_buf) 
-	  kfree(ohci->AR_resp_buf);
-	if (ohci->AR_resp_prg) 
-	  kfree(ohci->AR_resp_prg);
+
+	/* Free AR response buffers and programs */
+	if (ohci->AR_resp_buf) {
+		int i;
+                for (i= 0; i < AR_RESP_NUM_DESC; i++) {
+			kfree(ohci->AR_resp_buf[i]);
+		}
+		kfree(ohci->AR_resp_buf);
+	}
+	if (ohci->AR_resp_prg) {
+		int i;
+		for (i= 0; i < AR_RESP_NUM_DESC; i++) {
+			kfree(ohci->AR_resp_prg[i]);
+		}
+		kfree(ohci->AR_resp_prg);
+	}
+	kfree(ohci->AR_resp_spb);
+
+	/* Free AT request buffer and program */
 	if (ohci->AT_req_prg) 
 	  kfree(ohci->AT_req_prg);
+
+	/* Free Iso receive buffers and programs */
 	if (ohci->IR_recv_buf) {
 		int i;
                 for (i= 0; i < IR_NUM_DESC; i++) {
@@ -1288,11 +1533,16 @@
 		kfree(ohci->IR_recv_prg);
 	}
 	kfree(ohci->IR_spb);
+
+	/* Free self-id buffer */
 	if (ohci->self_id_buffer)
 	  kfree(ohci->self_id_buffer);
+	
+	/* Free config rom */
 	if (ohci->csr_config_rom)
 	  kfree(ohci->csr_config_rom);
 
+	/* Free the IRQ */
 	free_irq(ohci->dev->irq, ohci);
 
 	ohci->state = 0;
@@ -1327,11 +1577,15 @@
 	}
 
 #ifdef CONFIG_PROC_FS
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+	create_proc_read_entry ("ohci1394", 0, NULL, ohci1394_read_proc, NULL);
+#else
 	if (proc_register(&proc_root, &ohci_proc_entry)) {
 		PRINT_G(KERN_ERR, "unable to register proc file\n");
 		return -EIO;
 	}
 #endif
+#endif
 	return 0;
 }
 
@@ -1384,7 +1638,11 @@
 {
 	hpsb_unregister_lowlevel(get_ohci_template());
 #ifdef CONFIG_PROC_FS
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+	remove_proc_entry ("ohci1394", NULL);
+#else
 	proc_unregister(&proc_root, ohci_proc_entry.low_ino);
+#endif
 #endif
 	PRINT_G(KERN_INFO, "removed " OHCI1394_DRIVER_NAME " module\n");
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)