patch-2.1.115 linux/arch/ppc/kernel/residual.c

Next file: linux/arch/ppc/kernel/setup.c
Previous file: linux/arch/ppc/kernel/ptrace.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.114/linux/arch/ppc/kernel/residual.c linux/arch/ppc/kernel/residual.c
@@ -1,11 +1,28 @@
 /*
- * $Id: residual.c,v 1.7 1998/03/08 05:49:20 davem Exp $
+ * $Id: residual.c,v 1.10 1998/07/09 22:23:18 cort Exp $
  *
  * Code to deal with the PReP residual data.
  *
  * Written by: Cort Dougan (cort@cs.nmt.edu)
  * Improved _greatly_ and rewritten by Gabriel Paubert (paubert@iram.es)
+ *
+ *  This file is based on the following documentation:
+ *
+ *	IBM Power Personal Systems Architecture
+ *	Residual Data
+ * 	Document Number: PPS-AR-FW0001
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive
+ *  for more details.
+ *
  */
+
+#include <linux/string.h>
+#include <asm/residual.h>
+#include <asm/pnp.h>
+#include <asm/byteorder.h>
+
 #if 0
 #include <linux/errno.h>
 #include <linux/sched.h>
@@ -28,11 +45,9 @@
 
 #include <asm/mmu.h>
 #include <asm/processor.h>
-#include <asm/residual.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/ide.h>
-#include <asm/pnp.h>
 
 
 const char * PnP_BASE_TYPES[]= {
@@ -492,17 +507,17 @@
 return;
 	
 	/* make sure we have residual data first */
-	if ( res.ResidualLength == 0 )
+	if ( res->ResidualLength == 0 )
 		return;
 	
-	printk("Residual: %ld devices\n", res.ActualNumDevices);
+	printk("Residual: %ld devices\n", res->ActualNumDevices);
 	for ( i = 0;
-	      i < res.ActualNumDevices ;
+	      i < res->ActualNumDevices ;
 	      i++)
 	{
 	  	char decomp[4], sn[20];
 		const char * s;
-		dev = &res.Devices[i];
+		dev = &res->Devices[i];
 		s = PnP_INTERFACE_STR(did.BaseType, did.SubType, 
 				      did.Interface);
 		if(!s) {
@@ -538,18 +553,18 @@
 		       PnP_SUB_TYPE_STR(did.BaseType,did.SubType),
 		       s);
 		printpackets( (union _PnP_TAG_PACKET *)
-		      &res.DevicePnPHeap[dev->AllocatedOffset], "allocated");
+		      &res->DevicePnPHeap[dev->AllocatedOffset], "allocated");
 		printpackets( (union _PnP_TAG_PACKET *)
-		      &res.DevicePnPHeap[dev->PossibleOffset], "possible");
+		      &res->DevicePnPHeap[dev->PossibleOffset], "possible");
 		printpackets( (union _PnP_TAG_PACKET *)
-		      &res.DevicePnPHeap[dev->CompatibleOffset], "compatible");
+		      &res->DevicePnPHeap[dev->CompatibleOffset], "compatible");
 	}
 }
 
 
 
 static void printVPD(void) {
-#define vpd res.VitalProductData
+#define vpd res->VitalProductData
 	int ps=vpd.PageSize, i, j;
 	static const char* Usage[]={
 	  "FirmwareStack",  "FirmwareHeap",  "FirmwareCode", "BootImage",
@@ -594,11 +609,11 @@
 	printk("WordWidth, PageSize: %ld, %d\n", vpd.WordWidth, ps);
 	printk("Cache sector size, Lock granularity: %ld, %ld\n",
 	       vpd.CoherenceBlockSize, vpd.GranuleSize);
-	for (i=0; i<res.ActualNumMemSegs; i++) {
-		int mask=res.Segs[i].Usage, first, j;
+	for (i=0; i<res->ActualNumMemSegs; i++) {
+		int mask=res->Segs[i].Usage, first, j;
 		printk("%8.8lx-%8.8lx ", 
-		       res.Segs[i].BasePage*ps,
-		       (res.Segs[i].PageCount+res.Segs[i].BasePage)*ps-1);
+		       res->Segs[i].BasePage*ps,
+		       (res->Segs[i].PageCount+res->Segs[i].BasePage)*ps-1);
 		for(j=15, first=1; j>=0; j--) {
 			if (mask&(1<<j)) {
 				if (first) first=0;
@@ -622,14 +637,14 @@
 #define did dev->DeviceId
 	
 	/* make sure we have residual data first */
-	if ( res.ResidualLength == 0 )
+	if ( res->ResidualLength == 0 )
 		return;
-	printk("Residual: %ld devices\n", res.ActualNumDevices);
+	printk("Residual: %ld devices\n", res->ActualNumDevices);
 	for ( i = 0;
-	      i < res.ActualNumDevices ;
+	      i < res->ActualNumDevices ;
 	      i++)
 	{
-		dev = &res.Devices[i];
+		dev = &res->Devices[i];
 		/*
 		 * pci devices
 		 */
@@ -653,7 +668,7 @@
 				printk(" pnp:");
 				/* get pnp info on the device */
 				pkt = (union _PnP_TAG_PACKET *)
-					&res.DevicePnPHeap[dev->AllocatedOffset];
+					&res->DevicePnPHeap[dev->AllocatedOffset];
 				for (; pkt->S1_Pack.Tag != DF_END_TAG;
 				     pkt++ )
 				{
@@ -714,3 +729,125 @@
 #endif	
 
 #endif /* 0 */
+/* Returns the device index in the residual data, 
+   any of the search items may be set as -1 for wildcard,
+   DevID number field (second halfword) is big endian ! 
+
+   Examples:
+   - search for the Interrupt controller (8259 type), 2 methods:
+     1) i8259 = residual_find_device(~0, 
+                                     NULL, 
+				     SystemPeripheral, 
+				     ProgrammableInterruptController, 
+				     ISA_PIC, 
+				     0);
+     2) i8259 = residual_find_device(~0, "PNP0000", -1, -1, -1, 0) 
+
+   - search for the first two serial devices, whatever their type)
+     iserial1 = residual_find_device(~0,NULL,
+                                     CommunicationsDevice,
+				     RS232Device,
+				     -1, 0)
+     iserial2 = residual_find_device(~0,NULL,
+                                     CommunicationsDevice,
+				     RS232Device,
+				     -1, 1)
+   - but search for typical COM1 and COM2 is not easy due to the
+     fact that the interface may be anything and the name "PNP0500" or 
+     "PNP0501". Quite bad. 
+
+*/
+
+/* devid are easier to uncompress than to compress, so to minimize bloat
+in this rarely used area we unencode and compare */
+
+/* in residual data number is big endian in the device table and
+little endian in the heap, so we use two parameters to avoid writing
+two very similar functions */
+
+static int same_DevID(unsigned short vendor,
+	       unsigned short Number,
+	       char * str) 
+{
+	static unsigned const char hexdigit[]="0123456789ABCDEF";
+	if (strlen(str)!=7) return 0;
+	if ( ( ((vendor>>10)&0x1f)+'A'-1 == str[0])  &&
+	     ( ((vendor>>5)&0x1f)+'A'-1 == str[1])   &&
+	     ( (vendor&0x1f)+'A'-1 == str[2])        &&
+	     (hexdigit[(Number>>12)&0x0f] == str[3]) &&
+	     (hexdigit[(Number>>8)&0x0f] == str[4])  &&
+	     (hexdigit[(Number>>4)&0x0f] == str[5])  &&
+	     (hexdigit[Number&0x0f] == str[6]) ) return 1;
+	return 0;
+}
+
+PPC_DEVICE *residual_find_device(unsigned long BusMask,
+			 unsigned char * DevID,
+			 int BaseType,
+			 int SubType,
+			 int Interface,
+			 int n)
+{
+	int i;
+	if ( !res->ResidualLength ) return NULL;
+	for (i=0; i<res->ActualNumDevices; i++) {
+#define Dev res->Devices[i].DeviceId
+		if ( (Dev.BusId&BusMask)                                  &&
+		     (BaseType==-1 || Dev.BaseType==BaseType)             &&
+		     (SubType==-1 || Dev.SubType==SubType)                &&
+		     (Interface==-1 || Dev.Interface==Interface)          &&
+		     (DevID==NULL || same_DevID((Dev.DevId>>16)&0xffff,
+						Dev.DevId&0xffff, DevID)) &&
+		     !(n--) ) return res->Devices+i;
+#undef Dev
+	}
+	return 0;
+}
+
+PnP_TAG_PACKET *PnP_find_packet(unsigned char *p,
+				unsigned packet_tag,
+				int n)
+{
+	unsigned mask, masked_tag, size;
+	if(!p) return 0;
+	if (tag_type(packet_tag)) mask=0xff; else mask=0xF8;
+	masked_tag = packet_tag&mask;
+	for(; *p != END_TAG; p+=size) {
+		if ((*p & mask) == masked_tag && !(n--)) 
+			return (PnP_TAG_PACKET *) p;
+		if (tag_type(*p))
+			size=ld_le16((unsigned short *)(p+1))+3;
+		else 
+			size=tag_small_count(*p)+1;
+	}
+	return 0; /* not found */
+}
+
+PnP_TAG_PACKET *PnP_find_small_vendor_packet(unsigned char *p,
+					     unsigned packet_type,
+					     int n)
+{
+	int next=0;
+	while (p) {
+		p = (unsigned char *) PnP_find_packet(p, 0x70, next);
+		if (p && p[1]==packet_type && !(n--)) 
+			return (PnP_TAG_PACKET *) p;
+		next = 1;
+	};
+	return 0; /* not found */
+}
+
+PnP_TAG_PACKET *PnP_find_large_vendor_packet(unsigned char *p,
+					   unsigned packet_type,
+					   int n)
+{
+	int next=0;
+	while (p) {
+		p = (unsigned char *) PnP_find_packet(p, 0x84, next);
+		if (p && p[3]==packet_type && !(n--)) 
+			return (PnP_TAG_PACKET *) p;
+		next = 1;
+	};
+	return 0; /* not found */
+}
+

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov