patch-2.2.18 linux/drivers/usb/ohci-root-hub.c

Next file: linux/drivers/usb/ohci-root-hub.h
Previous file: linux/drivers/usb/ohci-hcd.h
Back to the patch index
Back to the overall index

diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/usb/ohci-root-hub.c linux/drivers/usb/ohci-root-hub.c
@@ -1,604 +0,0 @@
-/*
- * HCD (OHCI) Virtual Root Hub for USB.
- *
- * (C) Copyright 1999 Roman Weissgaerber (weissg@vienna.at)
- *
- * The Root Hub is build into the HC (UHCI or OHCI) hardware. 
- * This piece of code lets it look like it resides on the usb
- * like the other hubs.
- * (for anyone who wants to do a control operation on the root hub)
- *  
- * v2.1 1999/05/09 
- * v2.0 1999/05/04
- * v1.0 1999/04/27
- * ohci-root-hub.c
- *  
- */
- 
-
-
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/malloc.h>
-#include <linux/string.h>
-
-#include "usb.h"
-#include "ohci-hcd.h" 
-
-#ifdef VROOTHUB 
-
-#include "ohci-root-hub.h"
-
-
-static __u8 root_hub_dev_des[] =
-{
-        0x12,       /*  __u8  bLength; */
-		0x01,       /*  __u8  bDescriptorType; Device */
-		0x00,	    /*  __u16 bcdUSB; v1.0 */
-        0x01,
-		0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
-		0x00,	    /*  __u8  bDeviceSubClass; */
-		0x00,       /*  __u8  bDeviceProtocol; */
-		0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
-		0x00,       /*  __u16 idVendor; */
-        0x00,
-		0x00,       /*  __u16 idProduct; */
-        0x00,
-		0x00,       /*  __u16 bcdDevice; */
-        0x00,
-		0x00,       /*  __u8  iManufacturer; */
-		0x00,       /*  __u8  iProduct; */
-		0x00,       /*  __u8  iSerialNumber; */
-        0x01        /*  __u8  bNumConfigurations; */
-};
-
-
-/* Configuration descriptor */
-static __u8 root_hub_config_des[] =
-{
-		0x09,       /*  __u8  bLength; */
-		0x02,       /*  __u8  bDescriptorType; Configuration */
-		0x19,       /*  __u16 wTotalLength; */
-        0x00,
-		0x01,       /*  __u8  bNumInterfaces; */
-		0x01,       /*  __u8  bConfigurationValue; */
-		0x00,       /*  __u8  iConfiguration; */
-		0x40,       /*  __u8  bmAttributes; 
-                 Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
-		0x00,       /*  __u8  MaxPower; */
-      
-     /* interface */	  
-        0x09,       /*  __u8  if_bLength; */
-        0x04,       /*  __u8  if_bDescriptorType; Interface */
-        0x00,       /*  __u8  if_bInterfaceNumber; */
-        0x00,       /*  __u8  if_bAlternateSetting; */
-        0x01,       /*  __u8  if_bNumEndpoints; */
-        0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
-        0x00,       /*  __u8  if_bInterfaceSubClass; */
-        0x00,       /*  __u8  if_bInterfaceProtocol; */
-        0x00,       /*  __u8  if_iInterface; */
-     
-     /* endpoint */
-        0x07,       /*  __u8  ep_bLength; */
-        0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
-        0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
-        0x03,       /*  __u8  ep_bmAttributes; Interrupt */
-        0x40,       /*  __u16 ep_wMaxPacketSize; 64 Bytes */
-        0x00,
-        0xff        /*  __u8  ep_bInterval; 255 ms */
-};
-
-/* 
-For OHCI we need just the  2nd Byte, so we 
-don't need this constant byte-array 
-
-static __u8 root_hub_hub_des[] =
-{ 
-        0x00,       *  __u8  bLength; *
-		0x29,       *  __u8  bDescriptorType; Hub-descriptor *
-        0x02,       *  __u8  bNbrPorts; *
-        0x00,       * __u16  wHubCharacteristics; *
-        0x00,
-        0x01,       *  __u8  bPwrOn2pwrGood; 2ms * 
-        0x00,       *  __u8  bHubContrCurrent; 0 mA *
-        0x00,       *  __u8  DeviceRemovable; *** 8 Ports max *** *
-        0xff        *  __u8  PortPwrCtrlMask; *** 8 ports max *** *
-};
-*/
-
-
-int root_hub_control_msg(struct ohci *ohci, int cmd_len, void *rh_cmd, void *rh_data, int leni, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler)
-{ 
-
-  __u32 stat;
-  __u32 rep_handler;
-  int req_reply=0;
-  union ep_addr_ ep_addr;
-  union ep_addr_ ep_addr_ret;
-        __u8 * cmd = rh_cmd;
-	__u8 * data = rh_data;
-	int i;
-	int len =leni;
-
-        __u8  bmRequestType = cmd[0];
-        __u8  bRequest      = cmd[1];
-        __u16 wValue        = cmd[3] << 8 | cmd [2];
-        __u16 wIndex        = cmd[5] << 8 | cmd [4];
-        __u16 wLength       = cmd[7] << 8 | cmd [6];
-printk("USB root hub: adr: %8x cmd(%8x): ", ohci->root_hub_funct_addr, 8);
-for(i=0;i<8;i++)
-	printk("%2x", ((char *)rh_cmd)[i]);
- 
-printk(" ; \n");
-
-	ep_addr_ret.iep = 0;
-	ep_addr_ret.bep.fa = ohci->root_hub_funct_addr;
-	ep_addr_ret.bep.ep =  (bmRequestType & 0x80) | 0x40;
-
-  switch (bmRequestType | bRequest << 8) {
-   /* Request Destination:
-      without flags: Device, 
-      RH_INTERFACE: interface, 
-      RH_ENDPOINT: endpoint,
-      RH_CLASS means HUB here, 
-      RH_OTHER | RH_CLASS  almost ever means HUB_PORT here 
-   */
-  
-   case RH_GET_STATUS:
-     len = 2; 
-     data[0] = 0x01;
-     data[1] = 0x00;
-     req_reply = RH_ACK; 
-     break;
-   case RH_GET_STATUS | RH_INTERFACE:
-     len = 2; 
-     data[0] = 0x00;
-     data[1] = 0x00;     
-     req_reply = RH_ACK;
-     break;
-   case RH_GET_STATUS | RH_ENDPOINT:
-     len = 2; 
-     data[0] = 0x00;
-     data[1] = 0x00;     
-     req_reply = RH_ACK;
-     break;
-   case RH_GET_STATUS | RH_CLASS: /* HUB_STATUS */
-     stat = readl(&ohci->regs->roothub.status) & 0x7fff7fff; /* bit 31 u. 15 has other meaning */ 
-     data[0] = stat & 0xff;
-     data[1] = (stat >> 8) & 0xff;
-     data[2] = (stat >> 16) & 0xff;
-     data[3] = (stat >> 24) & 0xff;
-     len = 4;
-     req_reply = RH_ACK; 
-     break;
-   case RH_GET_STATUS | RH_OTHER | RH_CLASS: /* PORT_STATUS */
-     stat = readl(&ohci->regs->roothub.portstatus[wIndex-1]);
-     data[0] = stat & 0xff;
-     data[1] = (stat >> 8) & 0xff;
-     data[2] = (stat >> 16) & 0xff;
-     data[3] = (stat >> 24) & 0xff;
-     len = 4;
-     req_reply = RH_ACK; 
-     printk("rh: stat %4x wIndex %4x;\n", stat , wIndex);
-     break;
-
-   case RH_CLEAR_FEATURE:
-     switch (wValue) {
-       case (RH_DEVICE_REMOTE_WAKEUP):
-       default:
-     }
-     break;
-
-   case RH_CLEAR_FEATURE | RH_ENDPOINT:  
-     switch (wValue) {
-       case (RH_ENDPOINT_STALL): 
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       default:
-     }
-     break;
-
-   case RH_CLEAR_FEATURE | RH_CLASS:
-     switch (wValue) {
-       /*     case (RH_C_HUB_LOCAL_POWER):  OHCI says: no switching of this one */
-       case (RH_C_HUB_OVER_CURRENT):
-         writel(RH_PS_OCIC, &ohci->regs->roothub.status);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       default:
-     }
-     break;
-   case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
-     switch (wValue) {
-       case (RH_PORT_ENABLE):
-	     writel(RH_PS_CCS, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       case (RH_PORT_SUSPEND):
-         writel(RH_PS_POCI, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       case (RH_PORT_POWER):
-         writel(RH_PS_LSDA, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       case (RH_C_PORT_CONNECTION):
-         writel(RH_PS_CSC, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       case (RH_C_PORT_ENABLE):
-         writel(RH_PS_PESC, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       case (RH_C_PORT_SUSPEND):
-         writel(RH_PS_PSSC, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       case (RH_C_PORT_OVER_CURRENT):
-         writel(RH_PS_OCIC, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       case (RH_C_PORT_RESET):
-         writel(RH_PS_PRSC, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       /*
-       case (RH_PORT_CONNECTION):
-       case (RH_PORT_OVER_CURRENT):
-       case (RH_PORT_RESET):
-       case (RH_PORT_LOW_SPEED):
-       */
-       default:
-     }
-     break;
-   case RH_SET_FEATURE:  
-     switch (wValue) {
-       case (RH_DEVICE_REMOTE_WAKEUP):
-       default:
-     }
-     break;
-
-   case RH_SET_FEATURE | RH_ENDPOINT:
-     switch (wValue) {
-       case (RH_ENDPOINT_STALL):
-       default:
-     }
-     break;
-
-   case RH_SET_FEATURE | RH_CLASS: 
-     switch (wValue) {
-       /* case (RH_C_HUB_LOCAL_POWER): Root Hub has no local Power 
-       case (RH_C_HUB_OVER_CURRENT): */
-      default:
-     }
-     break;
-   case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
-     switch (wValue) {
-       case (RH_PORT_SUSPEND):
-         writel(RH_PS_PSS, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       case (RH_PORT_RESET):
-         if((readl(&ohci->regs->roothub.portstatus[wIndex-1]) &1) != 0)  /* BUG IN HUP CODE *********/
-         writel(RH_PS_PRS, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       case (RH_PORT_POWER):
-         writel(RH_PS_PPS, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       case (RH_PORT_ENABLE):
-         writel(RH_PS_PES, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       /*
-       case (RH_PORT_CONNECTION):
-       case (RH_PORT_OVER_CURRENT):
-       case (RH_PORT_LOW_SPEED):
-       case (RH_C_PORT_CONNECTION):
-       case (RH_C_PORT_ENABLE):
-       case (RH_C_PORT_SUSPEND):
-       case (RH_C_PORT_OVER_CURRENT):
-       case (RH_C_PORT_RESET):
-       */
-       default:  
-     }
-     break;
-
-  case RH_SET_ADDRESS:
-     ohci->root_hub_funct_addr = wValue; 
-	/* ohci->ed_func_ep0[wValue] = &ohci->ed_rh_ep0;
-	 ohci->ed_func_ep0[wValue]->ep_addr.bep.fa = wValue; 
-	 ohci->ed_func_ep0[wValue]->ed_list = &ohci->ed_rh_epi; */
-	 ohci->ed_rh_epi.ed_list = NULL;
-	 ohci->ed_rh_epi.ep_addr.bep.fa = wValue;
-	 ohci->ed_rh_epi.ep_addr.bep.ep = 0xa1; /* Int in port 1 */
-     ohci->ed_func_ep0[0]= NULL;
-     len = 0;
-     req_reply = RH_ACK;
-     break;
-
-   case RH_GET_DESCRIPTOR:
-     switch ((wValue & 0xff00) >> 8) {
-     case (0x01): /* device descriptor */
-       len = min(sizeof(root_hub_dev_des), wLength);
-       memcpy(data, root_hub_dev_des, len);
-       req_reply = RH_ACK;
-       break;
-     case (0x02): /* configuration descriptor */
-       len = min(sizeof(root_hub_config_des), wLength);
-       memcpy(data, root_hub_config_des, len);
-       req_reply = RH_ACK;
-       break;
-     case (0x03): /* string descriptors */
-     default:
-     }
-     break;
-  case RH_GET_DESCRIPTOR | RH_CLASS:
-     data[1] = 0x29;
-     stat = readl(&ohci->regs->roothub.a);  
-     data[2] = stat & 0xff;        /* number of ports */
-     data[0] = (data[2] / 8) * 2 + 9; /* length of descriptor */
-     if(data[0] > wLength) {
-       req_reply =  RH_REQ_ERR;
-       break;
-     }
-     data[3] = (stat >> 8) & 0xff;
-     data[4] = (stat >> 16) & 0xff;
-     data[5] = (stat >> 24) & 0xff;
-     data[6] = 0; /* Root Hub needs no current from bus */
-     stat = readl(&ohci->regs->roothub.b); 
-     if(data[2] <= 8) { /* less than 8 Ports */
-       data[7] = stat & 0xff;
-       data[8] = (stat >> 16) & 0xff; /* 0xff for USB Rev. 1.1 ?, stat >> 16 for USB Rev. 1.0 */
-     }
-     else {
-       data[7] = stat & 0xff;
-       data[8] = (stat >> 8) & 0xff;
-       data[9] = (stat >> 16) & 0xff;  /* 0xff for USB Rev. 1.1?, stat >> 16 for USB Rev. 1.0 */
-       data[10] = (stat >> 24) & 0xff; /* 0xff for USB Rev. 1.1?, stat >> 24 for USB Rev. 1.0 */
-     }
-     len = data[0];
-     req_reply = RH_ACK;
-     break;
-
-   case RH_SET_DESCRIPTOR:
-     break;
-
-   case RH_GET_CONFIGURATION:
-     len = 1;
-     data[0] = 0x01;
-     req_reply = RH_ACK;
-     break;
-
-   case RH_SET_CONFIGURATION: /* start it up */
-     writel( 0x10000, &ohci->regs->roothub.status);
-     /*writel( OHCI_INTR_RHSC, &ohci->regs->intrenable);*/
-     len = 0;
-     req_reply = RH_ACK;
-     break;
-   /*  Optional or meaningless requests 
-     case RH_GET_STATE | RH_OTHER | RH_CLASS:
-     case RH_GET_INTERFACE | RH_INTERFACE:
-     case RH_SET_INTERFACE | RH_INTERFACE:
-     case RH_SYNC_FRAME | RH_ENDPOINT: 
-   */
-
-  /* Vendor Requests, we are the vendor!
-	Will the USB-Consortium give us a Vendor Id
-	for a virtual hub-device :-) ?
-     We could use these requests for configuration purposes on the HCD Driver, not used in the altenate usb !*/ 
-
-  case RH_SET_FEATURE | RH_VENDOR: /* remove all endpoints of device wIndex = Dev << 8  */
-    switch(wValue) {
-    case RH_REMOVE_EP:
-      ep_addr.iep = 0;
-      ep_addr.bep.ep = wIndex & 0xff;
-      ep_addr.bep.fa = (wIndex << 8) & 0xff00;
-      usb_ohci_rm_function(ohci, ep_addr.iep);
-      len=0;
-      req_reply = RH_ACK;
-      break;
-    }
-    break;
-  case RH_SET_FEATURE | RH_ENDPOINT | RH_VENDOR: /* remove endpoint wIndex = Dev << 8 | EP */
-    switch(wValue) {
-    case RH_REMOVE_EP: 
-      ep_addr.iep = 0;
-      ep_addr.bep.ep = wIndex & 0xff;
-      ep_addr.bep.fa = (wIndex << 8) & 0xff00;
-      usb_ohci_rm_ep(ohci, ohci_find_ep(ohci, ep_addr.iep));
-      len=0;
-      req_reply = RH_ACK;
-      break;
-    }
-    break;
-  case RH_SET_EP | RH_ENDPOINT | RH_VENDOR:   
-    ep_addr.bep.ep = data[0];
-    ep_addr.bep.fa = data[1];
-    ep_addr.bep.hc = data[2];
-    ep_addr.bep.host = data[3];  
-    rep_handler  = data[7] << 24 |data[6] << 16 | data[5] << 8 | data[4];
-    /*  struct usb_ohci_ed *usb_ohci_add_ep(union ep_addr_ ep_addr,
-	struct ohci * ohci, int interval, int load, int (*handler)(int, void*), int ep_size, int speed) */
-    usb_ohci_add_ep(ohci, ep_addr.iep, data[8], data[9], (f_handler) rep_handler, data[11] << 8 | data[10] , data[12]);
-    len=0;
-    req_reply = RH_ACK;
-    break;
-
-  default: 
-  }
- printk("USB HC roothubstat1: %x \n", readl( &(ohci->regs->roothub.portstatus[0]) ));
-  printk("USB HC roothubstat2: %x \n", readl( &(ohci->regs->roothub.portstatus[1]) ));
-
-  /* if (req_reply == RH_ACK) len; */
-  queue_reply(ohci, ep_addr_ret.iep, 8, rh_cmd, data, len, lw0, lw1, handler);
-  return 0;
-}
-
-int root_hub_int_req(struct ohci * ohci, int cmd_len, void * ctrl, void *  data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler){
-
-	struct ohci_rep_td *td;
- 	struct ohci_rep_td *tmp;
- 	union ep_addr_ ep_addr;
- 	
- 	td = kmalloc(sizeof(td),GFP_KERNEL);
- 	tmp = ohci->td_rh_epi;
- 	td->next_td = NULL;
- 	if(tmp == NULL) { /* queue td */
- 		ohci->td_rh_epi = td;	
- 	}
- 	else {
- 		while(tmp->next_td != NULL) tmp = tmp->next_td;
- 		tmp->next_td = td;
- 	}
- 	ep_addr.iep = 0;
- 	ep_addr.bep.fa = ohci->root_hub_funct_addr;
- 	ep_addr.bep.ep = 0xA1; /* INT IN EP endpoint 1 */
-  	td->cmd_len = 0;
-  	td->cmd = NULL;
-  	td->data = data;
-  	td->data_len = data_len;
-  	td->handler = handler; 
-  	td->next_td = NULL;
-  	td->ep_addr = ep_addr.iep;
-	td->lw0 = lw0;
-	td->lw1 = lw1;
-	ohci_init_rh_int_timer(ohci, 255);
-	return 0;
-}
-
-
-/* prepare Interrupt pipe transaction data; HUP INTERRUPT ENDPOINT */ 
-int root_hub_send_irq(struct ohci * ohci, void * rh_data, int rh_len ) {
-
-  int num_ports;
-  int i;
-  int ret;
-  int len;
-
-  __u8 * data = rh_data;
-
-  num_ports = readl(&ohci->regs->roothub.a) & 0xff; 
-  data[0] = (readl(&ohci->regs->roothub.status) & 0x00030000)>0?1:0;
-  ret = data[0];
-
-  for(i=0; i < num_ports; i++) {
-    data[i/8] |= ((readl(&ohci->regs->roothub.portstatus[i]) & 0x001f0000)>0?1:0) << ((i+1) % 8);
-    ret += data[i/8];
-  }
-  len = i/8 + 1;
-  
-  if (ret > 0) return len;
-
-  return  RH_NACK;
-}
-
-
-
-
- 
-static struct timer_list rh_int_timer;
-
-/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
-static void rh_int_timer_do(unsigned long ptr) {
-	int len; 
-	int interval;
-	struct ohci * ohci = (struct ohci *) ptr;
-    struct ohci_rep_td *td = ohci->td_rh_epi;
-
-	if(td != NULL) { /* if ther is a TD handle the INT request */
-		
-		len = root_hub_send_irq(ohci, td->data, td->data_len );
-		if(len > 0) {
-			ohci->td_rh_epi = td->next_td;
-			td->next_td = ohci->repl_queue; 
-			ohci->repl_queue = td;
-			send_replies(ohci);
-		}
-	}	
-	interval = ohci->rh_int_interval;
-	init_timer(& rh_int_timer);
-	rh_int_timer.function = rh_int_timer_do;
-	rh_int_timer.data = (unsigned long) ohci;
-	rh_int_timer.expires = jiffies + (HZ * (interval<30?30: interval)) /1000;
-	add_timer(&rh_int_timer);
-}
-
-/* Root Hub INTs are polled by this timer */
-int ohci_init_rh_int_timer(struct ohci * ohci, int interval) {
-
-	if(!(ohci->rh_int_timer)) { 
-		ohci->rh_int_timer = 1;
-		ohci->rh_int_interval = interval;
-		init_timer(& rh_int_timer);
-		rh_int_timer.function = rh_int_timer_do;
-		rh_int_timer.data = (unsigned long) ohci;
-		rh_int_timer.expires = jiffies + (HZ * (interval<30?30: interval)) /1000;
-		add_timer(&rh_int_timer);
-	}
-	return 0;
-}
-
-int ohci_del_rh_int_timer(struct ohci * ohci) {
-	del_timer(&rh_int_timer);
-	return 0;
-}
-/* for root hub replies, queue the reply, (it will be sent immediately now) */
-
-int queue_reply(struct ohci * ohci, unsigned int ep_addr, int cmd_len,void * cmd, void * data,int  len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler) {
-
- struct ohci_rep_td *td;
- int status = 0;
- 
-printk("queue_reply ep: %x len: %x\n", ep_addr, len);
-td = kmalloc(sizeof(td), GFP_KERNEL);
-
-  if (len < 0) { status = len; len = 0;}
-  td->cmd_len = cmd_len;
-  td->cmd = cmd;
-  td->data = data;
-  td->data_len = len;
-  td->handler = handler; 
-  td->next_td = ohci->repl_queue; ohci->repl_queue = td;
-  td->ep_addr = ep_addr;
-  td->lw0 = lw0;
-  td->lw1 = lw1;
-  td->status = status;
-  send_replies(ohci);
-return 0;
-}
-
-/* for root hub replies; send the reply */
-int send_replies(struct ohci * ohci) { 
-	struct ohci_rep_td *td;
-	struct ohci_rep_td *tmp;
-
-	td = ohci->repl_queue; ohci->repl_queue = NULL;
-	while ( td != NULL) {
-		td->handler((void *) ohci, td->ep_addr,td->cmd_len,td->cmd, td->data, td->data_len, td->status, td->lw0, td->lw1); 
-		tmp = td;
-		td = td->next_td;
-	
-		kfree(tmp);
-	}
-	return 0;
-}
- 
-#endif

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