+/*****************************************************************************
+ * InstructionSignalHandler: system signal handler
+ *****************************************************************************
+ * This function is called when a illegal instruction signal is received by
+ * the program.
+ * We use this function to test OS and CPU_Capabilities
+ *****************************************************************************/
+static void InstructionSignalHandler( int i_signal )
+{
+ /* Once a signal has been trapped, the termination sequence will be
+ * armed and following signals will be ignored to avoid sending messages
+ * to an interface having been destroyed */
+
+ /* Acknowledge the signal received */
+ i_illegal = 1;
+
+#ifdef HAVE_SIGRELSE
+ sigrelse( i_signal );
+#endif
+ longjmp( env, 1 );
+}
+
+/*****************************************************************************
+ * CPUCapabilities: list the processors MMX support and other capabilities
+ *****************************************************************************
+ * This function is called to list extensions the CPU may have.
+ *****************************************************************************/
+static int CPUCapabilities( void )
+{
+ volatile int i_capabilities = CPU_CAPABILITY_NONE;
+
+#if defined( SYS_BEOS )
+ i_capabilities |= CPU_CAPABILITY_FPU
+ | CPU_CAPABILITY_486
+ | CPU_CAPABILITY_586
+ | CPU_CAPABILITY_MMX;
+
+ return( i_capabilities );
+
+#elif defined( SYS_DARWIN )
+ struct host_basic_info hi;
+ kern_return_t ret;
+ host_name_port_t host;
+
+ int i_size;
+ char *psz_name, *psz_subname;
+
+ i_capabilities |= CPU_CAPABILITY_FPU;
+
+ /* Should 'never' fail? */
+ host = mach_host_self();
+
+ i_size = sizeof( hi ) / sizeof( int );
+ ret = host_info( host, HOST_BASIC_INFO, ( host_info_t )&hi, &i_size );
+
+ if( ret != KERN_SUCCESS )
+ {
+ fprintf( stderr, "error: couldn't get CPU information\n" );
+ return( i_capabilities );
+ }
+
+ slot_name( hi.cpu_type, hi.cpu_subtype, &psz_name, &psz_subname );
+ /* FIXME: need better way to detect newer proccessors.
+ * could do strncmp(a,b,5), but that's real ugly */
+ if( !strcmp(psz_name, "ppc7400") || !strcmp(psz_name, "ppc7450") )
+ {
+ i_capabilities |= CPU_CAPABILITY_ALTIVEC;
+ }
+
+ return( i_capabilities );
+
+#elif defined( __i386__ )
+ volatile unsigned int i_eax, i_ebx, i_ecx, i_edx;
+ volatile boolean_t b_amd;
+
+ i_capabilities |= CPU_CAPABILITY_FPU;
+
+ signal( SIGILL, InstructionSignalHandler );
+
+ /* test for a 486 CPU */
+ asm volatile ( "pushfl\n\t"
+ "popl %%eax\n\t"
+ "movl %%eax, %%ebx\n\t"
+ "xorl $0x200000, %%eax\n\t"
+ "pushl %%eax\n\t"
+ "popfl\n\t"
+ "pushfl\n\t"
+ "popl %%eax"
+ : "=a" ( i_eax ),
+ "=b" ( i_ebx )
+ :
+ : "cc" );
+
+ if( i_eax == i_ebx )
+ {
+ signal( SIGILL, NULL );
+ return( i_capabilities );
+ }
+
+ i_capabilities |= CPU_CAPABILITY_486;
+
+ /* the CPU supports the CPUID instruction - get its level */
+ cpuid( 0x00000000 );
+
+ if( !i_eax )
+ {
+ signal( SIGILL, NULL );
+ return( i_capabilities );
+ }
+
+ /* FIXME: this isn't correct, since some 486s have cpuid */
+ i_capabilities |= CPU_CAPABILITY_586;
+
+ /* borrowed from mpeg2dec */
+ b_amd = ( i_ebx == 0x68747541 ) && ( i_ecx == 0x444d4163 )
+ && ( i_edx == 0x69746e65 );
+
+ /* test for the MMX flag */
+ cpuid( 0x00000001 );
+
+ if( ! (i_edx & 0x00800000) )
+ {
+ signal( SIGILL, NULL );
+ return( i_capabilities );
+ }
+
+ i_capabilities |= CPU_CAPABILITY_MMX;
+
+ if( i_edx & 0x02000000 )
+ {
+ i_capabilities |= CPU_CAPABILITY_MMXEXT;
+
+#ifdef CAN_COMPILE_SSE
+ /* We test if OS support the SSE instructions */
+ i_illegal = 0;
+ if( setjmp( env ) == 0 )
+ {
+ /* Test a SSE instruction */
+ __asm__ __volatile__ ( "xorps %%xmm0,%%xmm0\n" : : );
+ }
+
+ if( i_illegal == 0 )
+ {
+ i_capabilities |= CPU_CAPABILITY_SSE;
+ }
+ else
+ {
+ fprintf( stderr, "warning: your OS doesn't have support for "
+ "SSE instructions, "
+ "some optimizations\nwill be disabled\n" );
+#ifdef SYS_LINUX
+ fprintf( stderr, "(you will need Linux kernel 2.4.x or later)\n" );
+#endif
+ }
+#endif
+ }
+
+ /* test for additional capabilities */
+ cpuid( 0x80000000 );
+
+ if( i_eax < 0x80000001 )
+ {
+ signal( SIGILL, NULL );
+ return( i_capabilities );
+ }
+
+ /* list these additional capabilities */
+ cpuid( 0x80000001 );
+
+#ifdef CAN_COMPILE_3DNOW
+ if( i_edx & 0x80000000 )
+ {
+ i_illegal = 0;
+ if( setjmp( env ) == 0 )
+ {
+ /* Test a 3D Now! instruction */
+ __asm__ __volatile__ ( "pfadd %%mm0,%%mm0\n" "femms\n" : : );
+ }
+
+ if( i_illegal == 0 )
+ {
+ i_capabilities |= CPU_CAPABILITY_3DNOW;
+ }
+ }
+#endif
+
+ if( b_amd && ( i_edx & 0x00400000 ) )
+ {
+ i_capabilities |= CPU_CAPABILITY_MMXEXT;
+ }
+
+ signal( SIGILL, NULL );
+ return( i_capabilities );
+
+#elif defined( __powerpc__ )
+
+ i_capabilities |= CPU_CAPABILITY_FPU;
+
+ /* Test for Altivec */
+ signal( SIGILL, InstructionSignalHandler );
+
+#ifdef CAN_COMPILE_ALTIVEC
+ i_illegal = 0;
+ if( setjmp( env ) == 0 )
+ {
+ asm volatile ("mtspr 256, %0\n\t"
+ "vand %%v0, %%v0, %%v0"
+ :
+ : "r" (-1));
+ }
+
+ if( i_illegal == 0 )
+ {
+ i_capabilities |= CPU_CAPABILITY_ALTIVEC;
+ }
+#endif
+
+ signal( SIGILL, NULL );
+ return( i_capabilities );
+
+#else
+ /* default behaviour */
+ return( i_capabilities );
+
+#endif
+}
+
+/*****************************************************************************
+ * RedirectSTDOUT: redirect stdout and stderr to a file
+ *****************************************************************************
+ * This function will redirect stdout and stderr to a file if the user has
+ * specified so.
+ *****************************************************************************/
+static int RedirectSTDOUT( void )
+{
+ int i_fd;
+ char *psz_filename;
+
+ psz_filename = main_GetPszVariable( INTF_STDOUT_VAR, INTF_STDOUT_DEFAULT );
+
+ if( *psz_filename )
+ {
+ ShowConsole();
+ i_fd = open( psz_filename, O_CREAT | O_TRUNC | O_RDWR,
+ S_IREAD | S_IWRITE );
+ if( dup2( i_fd, fileno(stdout) ) == -1 )
+ {
+ intf_ErrMsg( "warning: unable to redirect stdout" );
+ }
+
+ if( dup2( i_fd, fileno(stderr) ) == -1 )
+ {
+ intf_ErrMsg( "warning: unable to redirect stderr" );
+ }
+
+ close( i_fd );
+ }
+ else
+ {
+ /* No stdout redirection has been asked so open a console */
+ if( p_main->i_warning_level )
+ {
+ ShowConsole();
+ }
+
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+ * ShowConsole: On Win32, create an output console for debug messages
+ *****************************************************************************
+ * This function is usefull only on Win32.
+ *****************************************************************************/
+static void ShowConsole( void )
+{
+#ifdef WIN32 /* */
+ AllocConsole();
+ freopen( "CONOUT$", "w", stdout );
+ freopen( "CONOUT$", "w", stderr );
+ freopen( "CONIN$", "r", stdin );
+#endif
+ return;
+}
+