int mm_support(void)

{

    int rval;

    int eax, ebx, ecx, edx;

    

    __asm__ __volatile__ (

                          /* See if CPUID instruction is supported ... */

                          /* ... Get copies of EFLAGS into eax and ecx */

                          "pushf\n\t"

                          "pop %0\n\t"

                          "movl %0, %1\n\t"

                          

                          /* ... Toggle the ID bit in one copy and store */

                          /*     to the EFLAGS reg */

                          "xorl $0x200000, %0\n\t"

                          "push %0\n\t"

                          "popf\n\t"

                          

                          /* ... Get the (hopefully modified) EFLAGS */

                          "pushf\n\t"

                          "pop %0\n\t"

                          : "=a" (eax), "=c" (ecx)

                          :

                          : "cc" 

                          );

    

    if (eax == ecx)

        return 0; /* CPUID not supported */

    

    cpuid(0, eax, ebx, ecx, edx);



    if (ebx == 0x756e6547 &&

        edx == 0x49656e69 &&

        ecx == 0x6c65746e) {

        

        /* intel */

    inteltest:

        cpuid(1, eax, ebx, ecx, edx);

        if ((edx & 0x00800000) == 0)

            return 0;

        rval = MM_MMX;

        if (edx & 0x02000000) 

            rval |= MM_MMXEXT | MM_SSE;

        if (edx & 0x04000000) 

            rval |= MM_SSE2;

        return rval;

    } else if (ebx == 0x68747541 &&

               edx == 0x69746e65 &&

               ecx == 0x444d4163) {

        /* AMD */

        cpuid(0x80000000, eax, ebx, ecx, edx);

        if ((unsigned)eax < 0x80000001)

            goto inteltest;

        cpuid(0x80000001, eax, ebx, ecx, edx);

        if ((edx & 0x00800000) == 0)

            return 0;

        rval = MM_MMX;

        if (edx & 0x80000000)

            rval |= MM_3DNOW;

        if (edx & 0x00400000)

            rval |= MM_MMXEXT;

        return rval;

    } else if (ebx == 0x746e6543 &&

               edx == 0x48727561 &&

               ecx == 0x736c7561) {  /*  "CentaurHauls" */

        /* VIA C3 */

        cpuid(0x80000000, eax, ebx, ecx, edx);

        if ((unsigned)eax < 0x80000001)

            goto inteltest;	

	cpuid(0x80000001, eax, ebx, ecx, edx);

	rval = 0;      

	if( edx & ( 1 << 31) )

	  rval |= MM_3DNOW;

	if( edx & ( 1 << 23) )

	  rval |= MM_MMX;

	if( edx & ( 1 << 24) )

	  rval |= MM_MMXEXT;

        if(rval==0)

            goto inteltest;

	return rval;

    } else if (ebx == 0x69727943 &&

               edx == 0x736e4978 &&

               ecx == 0x64616574) {

        /* Cyrix Section */

        /* See if extended CPUID level 80000001 is supported */

        /* The value of CPUID/80000001 for the 6x86MX is undefined

           according to the Cyrix CPU Detection Guide (Preliminary

           Rev. 1.01 table 1), so we'll check the value of eax for

           CPUID/0 to see if standard CPUID level 2 is supported.

           According to the table, the only CPU which supports level

           2 is also the only one which supports extended CPUID levels.

        */

        if (eax != 2) 

            goto inteltest;

        cpuid(0x80000001, eax, ebx, ecx, edx);

        if ((eax & 0x00800000) == 0)

            return 0;

        rval = MM_MMX;

        if (eax & 0x01000000)

            rval |= MM_MMXEXT;

        return rval;

    } else if (ebx == 0x756e6547 &&

               edx == 0x54656e69 &&

               ecx == 0x3638784d) {

        /* Tranmeta Crusoe */

        cpuid(0x80000000, eax, ebx, ecx, edx);

        if ((unsigned)eax < 0x80000001)

            return 0;

        cpuid(0x80000001, eax, ebx, ecx, edx);

        if ((edx & 0x00800000) == 0)

            return 0;

        return MM_MMX;

    } else {

        return 0;

    }

}
