/* Slightly modified to fill uuu by nark
 *
/
 * Copyright (c) 2006-2007 <brynet@gmail.com
 * All rights reserved
 
 * Redistribution and use in source and binary forms, with or withou
 * modification, are permitted provided that the following condition
 * are met
 * 1. Redistributions of source code must retain the above copyrigh
 *    notice, this list of conditions and the following disclaimer
 * 2. Redistributions in binary form must reproduce the above copyrigh
 *    notice, this list of conditions and the following disclaimer in th
 *    documentation and/or other materials provided with the distribution
 * 3. The name of the author may not be used to endorse or promote product
 *    derived from this software without specific prior written permission
 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILIT
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHAL
 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE O
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN I
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
 *

#include <python2.3/Python.h
#include <string.h
/* You need to include a file with fairly(ish) compliant printf prototype, Decimal and String support like %s and %d and this is truely all you need! *
//#include <stdio.h> /* for printf(); *

/* Required Declarations *
int do_intel(void)
int do_amd(void)
void printregs(int eax, int ebx, int ecx, int edx)

#define cpuid(in, a, b, c, d) asm("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (in))

/* Simply call this function detect_cpu(); *
/* or main() if your trying to port this as an independant application *
static PyObject *detect_cpu(PyObject *self, PyObject *args

	unsigned long ebx, unused
	cpuid(0, unused, ebx, unused, unused)
	switch(ebx
	
		case 0x756e6547: /* Intel Magic Code *
			do_intel()
			break
		case 0x68747541: /* AMD Magic Code *
			do_amd()
			break
		default
			printf("Unknown x86 CPU Detected\n")
	

	Py_INCREF( Py_None )
	return Py_None


char *Brands[9] = 
	"Unknown"
	"Celeron Processor"
	"Pentium III Processor"
	"Intel Pentium III Xeon Processor"
	"Unknown"
	"Unknown"
	"Unknown"
	"Unknown"
	"Intel Pentium 4 Processor"
}

/* Intel-specific information *
int do_intel(void

	printf("Intel-specific functions:\n")
	unsigned long eax, ebx, unused
	int model, family, type, brand, stepping, reserved
	int extended_family = -1
	cpuid(1, eax, ebx, unused, unused)
	model = (eax >> 4) & 0xf
	family = (eax >> 8) & 0xf
	type = (eax >> 12) & 0x3
	brand = ebx & 0xff
	stepping = eax & 0xf
	reserved = eax >> 14
	printf("Type %d - ", type)
	switch(type
	
		case 0
			printf("Original OEM")
			break
		case 1
			printf("Overdrive")
			break
		case 2
			printf("Dual-capable")
			break
		case 3
			printf("Reserved")
			break
	
	printf("\n")
	printf("Family %d - ", family)
	switch(family
	
		case 3
			printf("i386")
			break
		case 4
			printf("i486")
			break
		case 5
			printf("Pentium")
			break
		case 6
			printf("Pentium Pro")
			break
		case 15
			printf("Pentium 4")
	
	printf("\n")
	if(family == 15
	
		extended_family = (eax >> 20) & 0xff
		printf("Extended family %d\n", extended_family)
	
	printf("Model %d - ", model)
	switch(family
	
		case 3
			break
		case 4
			switch(model
			
				case 0
				case 1
					printf("DX")
					break
				case 2
					printf("SX")
					break
				case 3
					printf("487/DX2")
					break
				case 4
					printf("SL")
					break
				case 5
					printf("SX2")
					break
				case 7
					printf("Write-back enhanced DX2")
					break
				case 8
					printf("DX4")
					break
			
			break
		case 5
			switch(model
			
				case 1
					printf("60/66")
					break
				case 2
					printf("75-200")
					break
				case 3
					printf("for 486 system")
					break
				case 4
					printf("MMX")
					break
			
			break
		case 6
			switch(model
			
				case 1
					printf("Pentium Pro")
					break
				case 3
					printf("Pentium II Model 3")
					break
				case 5
					printf("Pentium II Model 5/Xeon/Celeron")
					break
				case 6
					printf("Celeron")
					break
				case 7
					printf("Pentium III/Pentium III Xeon - external L2 cache")
					break
				case 8
					printf("Pentium III/Pentium III Xeon - internal L2 cache")
				break
			
			break
		case 15
			break
	
	printf("\n")
	if(brand > 0
	
		printf("Brand %d - ", brand)
		if(brand < 9
		
			printf("%s\n", Brands[brand])
		}
		else
		
			printf("Unknown\n")
		
	
	printf("Stepping %d\n", stepping)
	printf("Reserved %d\n", reserved)
	return 0


/* Print Registers *
void printregs(int eax, int ebx, int ecx, int edx

	int j
	char string[17]
	string[16] = '\0'
	for(j = 0; j < 4; j++
	
		string[j] = eax >> (8*j)
		string[j + 4] = ebx >> (8*j)
		string[j + 8] = ecx >> (8*j)
		string[j + 12] = edx >> (8*j)
	
	printf("%s", string)


/* AMD-specific information *
int do_amd(void

	printf("AMD-specific functions\n")
	unsigned long maxei, eax, unused
	int family, model, stepping, reserved
	cpuid(1, eax, unused, unused, unused)
	model = (eax >> 4) & 0xf
	family = (eax >> 8) & 0xf
	stepping = eax & 0xf
	reserved = eax >> 12
	printf("Family: %d Model: %d [", family, model)
	switch(family
	
		case 4
			printf("486 Model %d", model)
			break
		case 5
			switch(model
			
				case 0
				case 1
				case 2
				case 3
				case 6
				case 7
					printf("K6 Model %d", model)
					break
				case 8
					printf("K6-2 Model 8")
					break
				case 9
					printf("K6-III Model 9")
					break
				default
					printf("K5/K6 Model %d", model)
					break
			
			break
		case 6
			switch(model
			
				case 1
				case 2
				case 4
					printf("Athlon Model %d", model)
					break
				case 3
					printf("Duron Model 3")
					break
				case 6
					printf("Athlon MP/Mobile Athlon Model 6")
					break
				case 7
					printf("Mobile Duron Model 7")
					break
				default
					printf("Duron/Athlon Model %d", model)
					break
		
		break
	
	printf("]\n")
	cpuid(0x80000000, maxei, unused, unused, unused)
	if(maxei == 0
	
		return 0
	}
	else
	if(maxei >= 0x80000002
	
		unsigned int j
		printf("Detected Processor Name: ")
		for(j = 0x80000002; j <= 0x80000004; j++
		
			unsigned long eax, ebx, ecx, edx
			cpuid(j, eax, ebx, ecx, edx)
			printregs(eax, ebx, ecx, edx)
		
		printf("\n")
	
	printf("Stepping %d\n", stepping)
	printf("Reserved %d\n", reserved)
	return 0


/********************
** About the module *
*********************

static PyMethodDef CpuMethods[] = 
  {"detect_cpu", detect_cpu, METH_VARARGS, "CPU type detection"}
  {NULL, NULL, 0, NULL
}

void init_cpumodule() 
  Py_InitModule( "cpu", CpuMethods )

