153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2004-2006 Lennart Poettering 553a5a1b3Sopenharmony_ci Copyright 2009 Wim Taymans <wim.taymans@collabora.co.uk> 653a5a1b3Sopenharmony_ci 753a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 853a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 953a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 1053a5a1b3Sopenharmony_ci or (at your option) any later version. 1153a5a1b3Sopenharmony_ci 1253a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1353a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1453a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1553a5a1b3Sopenharmony_ci General Public License for more details. 1653a5a1b3Sopenharmony_ci 1753a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1853a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1953a5a1b3Sopenharmony_ci***/ 2053a5a1b3Sopenharmony_ci 2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2253a5a1b3Sopenharmony_ci#include <config.h> 2353a5a1b3Sopenharmony_ci#endif 2453a5a1b3Sopenharmony_ci 2553a5a1b3Sopenharmony_ci#include <stdint.h> 2653a5a1b3Sopenharmony_ci#include <sys/types.h> 2753a5a1b3Sopenharmony_ci#include <fcntl.h> 2853a5a1b3Sopenharmony_ci 2953a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 3053a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h> 3153a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 3253a5a1b3Sopenharmony_ci 3353a5a1b3Sopenharmony_ci#include "cpu-arm.h" 3453a5a1b3Sopenharmony_ci 3553a5a1b3Sopenharmony_ci#if defined (__arm__) && defined (__linux__) 3653a5a1b3Sopenharmony_ci 3753a5a1b3Sopenharmony_ci#define MAX_BUFFER 4096 3853a5a1b3Sopenharmony_cistatic char * 3953a5a1b3Sopenharmony_ciget_cpuinfo_line(char *cpuinfo, const char *tag) { 4053a5a1b3Sopenharmony_ci char *line, *end, *colon; 4153a5a1b3Sopenharmony_ci 4253a5a1b3Sopenharmony_ci if (!(line = strstr(cpuinfo, tag))) 4353a5a1b3Sopenharmony_ci return NULL; 4453a5a1b3Sopenharmony_ci 4553a5a1b3Sopenharmony_ci if (!(end = strchr(line, '\n'))) 4653a5a1b3Sopenharmony_ci return NULL; 4753a5a1b3Sopenharmony_ci 4853a5a1b3Sopenharmony_ci if (!(colon = strchr(line, ':'))) 4953a5a1b3Sopenharmony_ci return NULL; 5053a5a1b3Sopenharmony_ci 5153a5a1b3Sopenharmony_ci if (++colon >= end) 5253a5a1b3Sopenharmony_ci return NULL; 5353a5a1b3Sopenharmony_ci 5453a5a1b3Sopenharmony_ci return pa_xstrndup(colon, end - colon); 5553a5a1b3Sopenharmony_ci} 5653a5a1b3Sopenharmony_ci 5753a5a1b3Sopenharmony_cistatic char *get_cpuinfo(void) { 5853a5a1b3Sopenharmony_ci char *cpuinfo; 5953a5a1b3Sopenharmony_ci int n, fd; 6053a5a1b3Sopenharmony_ci 6153a5a1b3Sopenharmony_ci cpuinfo = pa_xmalloc(MAX_BUFFER); 6253a5a1b3Sopenharmony_ci 6353a5a1b3Sopenharmony_ci if ((fd = pa_open_cloexec("/proc/cpuinfo", O_RDONLY, 0)) < 0) { 6453a5a1b3Sopenharmony_ci pa_xfree(cpuinfo); 6553a5a1b3Sopenharmony_ci return NULL; 6653a5a1b3Sopenharmony_ci } 6753a5a1b3Sopenharmony_ci 6853a5a1b3Sopenharmony_ci if ((n = pa_read(fd, cpuinfo, MAX_BUFFER-1, NULL)) < 0) { 6953a5a1b3Sopenharmony_ci pa_xfree(cpuinfo); 7053a5a1b3Sopenharmony_ci pa_close(fd); 7153a5a1b3Sopenharmony_ci return NULL; 7253a5a1b3Sopenharmony_ci } 7353a5a1b3Sopenharmony_ci cpuinfo[n] = 0; 7453a5a1b3Sopenharmony_ci pa_close(fd); 7553a5a1b3Sopenharmony_ci 7653a5a1b3Sopenharmony_ci return cpuinfo; 7753a5a1b3Sopenharmony_ci} 7853a5a1b3Sopenharmony_ci#endif /* defined (__arm__) && defined (__linux__) */ 7953a5a1b3Sopenharmony_ci 8053a5a1b3Sopenharmony_civoid pa_cpu_get_arm_flags(pa_cpu_arm_flag_t *flags) { 8153a5a1b3Sopenharmony_ci#if defined (__arm__) && defined (__linux__) 8253a5a1b3Sopenharmony_ci char *cpuinfo, *line; 8353a5a1b3Sopenharmony_ci int arch, part; 8453a5a1b3Sopenharmony_ci 8553a5a1b3Sopenharmony_ci /* We need to read the CPU flags from /proc/cpuinfo because there is no user 8653a5a1b3Sopenharmony_ci * space support to get the CPU features. This only works on linux AFAIK. */ 8753a5a1b3Sopenharmony_ci if (!(cpuinfo = get_cpuinfo())) { 8853a5a1b3Sopenharmony_ci pa_log("Can't read cpuinfo"); 8953a5a1b3Sopenharmony_ci return; 9053a5a1b3Sopenharmony_ci } 9153a5a1b3Sopenharmony_ci 9253a5a1b3Sopenharmony_ci *flags = 0; 9353a5a1b3Sopenharmony_ci 9453a5a1b3Sopenharmony_ci /* get the CPU architecture */ 9553a5a1b3Sopenharmony_ci if ((line = get_cpuinfo_line(cpuinfo, "CPU architecture"))) { 9653a5a1b3Sopenharmony_ci arch = strtoul(line, NULL, 0); 9753a5a1b3Sopenharmony_ci if (arch >= 6) 9853a5a1b3Sopenharmony_ci *flags |= PA_CPU_ARM_V6; 9953a5a1b3Sopenharmony_ci if (arch >= 7) 10053a5a1b3Sopenharmony_ci *flags |= PA_CPU_ARM_V7; 10153a5a1b3Sopenharmony_ci 10253a5a1b3Sopenharmony_ci pa_xfree(line); 10353a5a1b3Sopenharmony_ci } 10453a5a1b3Sopenharmony_ci 10553a5a1b3Sopenharmony_ci /* get the CPU features */ 10653a5a1b3Sopenharmony_ci if ((line = get_cpuinfo_line(cpuinfo, "Features"))) { 10753a5a1b3Sopenharmony_ci const char *state = NULL; 10853a5a1b3Sopenharmony_ci char *current; 10953a5a1b3Sopenharmony_ci 11053a5a1b3Sopenharmony_ci while ((current = pa_split_spaces(line, &state))) { 11153a5a1b3Sopenharmony_ci if (pa_streq(current, "vfp")) 11253a5a1b3Sopenharmony_ci *flags |= PA_CPU_ARM_VFP; 11353a5a1b3Sopenharmony_ci else if (pa_streq(current, "edsp")) 11453a5a1b3Sopenharmony_ci *flags |= PA_CPU_ARM_EDSP; 11553a5a1b3Sopenharmony_ci else if (pa_streq(current, "neon")) 11653a5a1b3Sopenharmony_ci *flags |= PA_CPU_ARM_NEON; 11753a5a1b3Sopenharmony_ci else if (pa_streq(current, "vfpv3")) 11853a5a1b3Sopenharmony_ci *flags |= PA_CPU_ARM_VFPV3; 11953a5a1b3Sopenharmony_ci 12053a5a1b3Sopenharmony_ci pa_xfree(current); 12153a5a1b3Sopenharmony_ci } 12253a5a1b3Sopenharmony_ci pa_xfree(line); 12353a5a1b3Sopenharmony_ci } 12453a5a1b3Sopenharmony_ci 12553a5a1b3Sopenharmony_ci /* get the CPU part number */ 12653a5a1b3Sopenharmony_ci if ((line = get_cpuinfo_line(cpuinfo, "CPU part"))) { 12753a5a1b3Sopenharmony_ci part = strtoul(line, NULL, 0); 12853a5a1b3Sopenharmony_ci if (part == 0xc08) 12953a5a1b3Sopenharmony_ci *flags |= PA_CPU_ARM_CORTEX_A8; 13053a5a1b3Sopenharmony_ci pa_xfree(line); 13153a5a1b3Sopenharmony_ci } 13253a5a1b3Sopenharmony_ci pa_xfree(cpuinfo); 13353a5a1b3Sopenharmony_ci 13453a5a1b3Sopenharmony_ci pa_log_info("CPU flags: %s%s%s%s%s%s%s", 13553a5a1b3Sopenharmony_ci (*flags & PA_CPU_ARM_V6) ? "V6 " : "", 13653a5a1b3Sopenharmony_ci (*flags & PA_CPU_ARM_V7) ? "V7 " : "", 13753a5a1b3Sopenharmony_ci (*flags & PA_CPU_ARM_VFP) ? "VFP " : "", 13853a5a1b3Sopenharmony_ci (*flags & PA_CPU_ARM_EDSP) ? "EDSP " : "", 13953a5a1b3Sopenharmony_ci (*flags & PA_CPU_ARM_NEON) ? "NEON " : "", 14053a5a1b3Sopenharmony_ci (*flags & PA_CPU_ARM_VFPV3) ? "VFPV3 " : "", 14153a5a1b3Sopenharmony_ci (*flags & PA_CPU_ARM_CORTEX_A8) ? "Cortex-A8 " : ""); 14253a5a1b3Sopenharmony_ci#endif 14353a5a1b3Sopenharmony_ci} 14453a5a1b3Sopenharmony_ci 14553a5a1b3Sopenharmony_cibool pa_cpu_init_arm(pa_cpu_arm_flag_t *flags) { 14653a5a1b3Sopenharmony_ci#if defined (__arm__) 14753a5a1b3Sopenharmony_ci#if defined (__linux__) 14853a5a1b3Sopenharmony_ci pa_cpu_get_arm_flags(flags); 14953a5a1b3Sopenharmony_ci 15053a5a1b3Sopenharmony_ci if (*flags & PA_CPU_ARM_V6) 15153a5a1b3Sopenharmony_ci pa_volume_func_init_arm(*flags); 15253a5a1b3Sopenharmony_ci 15353a5a1b3Sopenharmony_ci#ifdef HAVE_NEON 15453a5a1b3Sopenharmony_ci if (*flags & PA_CPU_ARM_NEON) { 15553a5a1b3Sopenharmony_ci pa_convert_func_init_neon(*flags); 15653a5a1b3Sopenharmony_ci pa_mix_func_init_neon(*flags); 15753a5a1b3Sopenharmony_ci pa_remap_func_init_neon(*flags); 15853a5a1b3Sopenharmony_ci } 15953a5a1b3Sopenharmony_ci#endif 16053a5a1b3Sopenharmony_ci 16153a5a1b3Sopenharmony_ci return true; 16253a5a1b3Sopenharmony_ci 16353a5a1b3Sopenharmony_ci#else /* defined (__linux__) */ 16453a5a1b3Sopenharmony_ci pa_log("Reading ARM CPU features not yet supported on this OS"); 16553a5a1b3Sopenharmony_ci#endif /* defined (__linux__) */ 16653a5a1b3Sopenharmony_ci 16753a5a1b3Sopenharmony_ci#else /* defined (__arm__) */ 16853a5a1b3Sopenharmony_ci return false; 16953a5a1b3Sopenharmony_ci#endif /* defined (__arm__) */ 17053a5a1b3Sopenharmony_ci} 171