1/*** 2 This file is part of PulseAudio. 3 4 Copyright 2004-2006 Lennart Poettering 5 Copyright 2009 Wim Taymans <wim.taymans@collabora.co.uk.com> 6 7 PulseAudio is free software; you can redistribute it and/or modify 8 it under the terms of the GNU Lesser General Public License as published 9 by the Free Software Foundation; either version 2.1 of the License, 10 or (at your option) any later version. 11 12 PulseAudio is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 General Public License for more details. 16 17 You should have received a copy of the GNU Lesser General Public License 18 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 19***/ 20 21#ifdef HAVE_CONFIG_H 22#include <config.h> 23#endif 24 25#include <string.h> 26 27#include <pulse/xmalloc.h> 28#include <pulse/sample.h> 29#include <pulse/volume.h> 30#include <pulsecore/log.h> 31#include <pulsecore/macro.h> 32 33#include "cpu.h" 34#include "remap.h" 35 36static void remap_mono_to_stereo_s16ne_c(pa_remap_t *m, int16_t *dst, const int16_t *src, unsigned n) { 37 unsigned i; 38 39 for (i = n >> 2; i; i--) { 40 dst[0] = dst[1] = src[0]; 41 dst[2] = dst[3] = src[1]; 42 dst[4] = dst[5] = src[2]; 43 dst[6] = dst[7] = src[3]; 44 src += 4; 45 dst += 8; 46 } 47 for (i = n & 3; i; i--) { 48 dst[0] = dst[1] = src[0]; 49 src++; 50 dst += 2; 51 } 52} 53 54static void remap_mono_to_stereo_s32ne_c(pa_remap_t *m, int32_t *dst, const int32_t *src, unsigned n) { 55 unsigned i; 56 57 for (i = n >> 2; i; i--) { 58 dst[0] = dst[1] = src[0]; 59 dst[2] = dst[3] = src[1]; 60 dst[4] = dst[5] = src[2]; 61 dst[6] = dst[7] = src[3]; 62 src += 4; 63 dst += 8; 64 } 65 for (i = n & 3; i; i--) { 66 dst[0] = dst[1] = src[0]; 67 src++; 68 dst += 2; 69 } 70} 71 72static void remap_mono_to_stereo_float32ne_c(pa_remap_t *m, float *dst, const float *src, unsigned n) { 73 unsigned i; 74 75 for (i = n >> 2; i; i--) { 76 dst[0] = dst[1] = src[0]; 77 dst[2] = dst[3] = src[1]; 78 dst[4] = dst[5] = src[2]; 79 dst[6] = dst[7] = src[3]; 80 src += 4; 81 dst += 8; 82 } 83 for (i = n & 3; i; i--) { 84 dst[0] = dst[1] = src[0]; 85 src++; 86 dst += 2; 87 } 88} 89 90static void remap_stereo_to_mono_s16ne_c(pa_remap_t *m, int16_t *dst, const int16_t *src, unsigned n) { 91 unsigned i; 92 93 for (i = n >> 2; i > 0; i--) { 94 dst[0] = (src[0] + src[1])/2; 95 dst[1] = (src[2] + src[3])/2; 96 dst[2] = (src[4] + src[5])/2; 97 dst[3] = (src[6] + src[7])/2; 98 src += 8; 99 dst += 4; 100 } 101 for (i = n & 3; i; i--) { 102 dst[0] = (src[0] + src[1])/2; 103 src += 2; 104 dst += 1; 105 } 106} 107 108static void remap_stereo_to_mono_s32ne_c(pa_remap_t *m, int32_t *dst, const int32_t *src, unsigned n) { 109 unsigned i; 110 111 for (i = n >> 2; i > 0; i--) { 112 /* Avoid overflow by performing division first. We accept a 113 * difference of +/- 1 to the ideal result. */ 114 dst[0] = (src[0]/2 + src[1]/2); 115 dst[1] = (src[2]/2 + src[3]/2); 116 dst[2] = (src[4]/2 + src[5]/2); 117 dst[3] = (src[6]/2 + src[7]/2); 118 src += 8; 119 dst += 4; 120 } 121 for (i = n & 3; i; i--) { 122 /* Avoid overflow by performing division first. We accept a 123 * difference of +/- 1 to the ideal result. */ 124 dst[0] = (src[0]/2 + src[1]/2); 125 src += 2; 126 dst += 1; 127 } 128} 129 130static void remap_stereo_to_mono_float32ne_c(pa_remap_t *m, float *dst, const float *src, unsigned n) { 131 unsigned i; 132 133 for (i = n >> 2; i > 0; i--) { 134 dst[0] = (src[0] + src[1])*0.5f; 135 dst[1] = (src[2] + src[3])*0.5f; 136 dst[2] = (src[4] + src[5])*0.5f; 137 dst[3] = (src[6] + src[7])*0.5f; 138 src += 8; 139 dst += 4; 140 } 141 for (i = n & 3; i; i--) { 142 dst[0] = (src[0] + src[1])*0.5f; 143 src += 2; 144 dst += 1; 145 } 146} 147 148static void remap_mono_to_ch4_s16ne_c(pa_remap_t *m, int16_t *dst, const int16_t *src, unsigned n) { 149 unsigned i; 150 151 for (i = n >> 2; i; i--) { 152 dst[0] = dst[1] = dst[2] = dst[3] = src[0]; 153 dst[4] = dst[5] = dst[6] = dst[7] = src[1]; 154 dst[8] = dst[9] = dst[10] = dst[11] = src[2]; 155 dst[12] = dst[13] = dst[14] = dst[15] = src[3]; 156 src += 4; 157 dst += 16; 158 } 159 for (i = n & 3; i; i--) { 160 dst[0] = dst[1] = dst[2] = dst[3] = src[0]; 161 src++; 162 dst += 4; 163 } 164} 165 166static void remap_mono_to_ch4_s32ne_c(pa_remap_t *m, int32_t *dst, const int32_t *src, unsigned n) { 167 unsigned i; 168 169 for (i = n >> 2; i; i--) { 170 dst[0] = dst[1] = dst[2] = dst[3] = src[0]; 171 dst[4] = dst[5] = dst[6] = dst[7] = src[1]; 172 dst[8] = dst[9] = dst[10] = dst[11] = src[2]; 173 dst[12] = dst[13] = dst[14] = dst[15] = src[3]; 174 src += 4; 175 dst += 16; 176 } 177 for (i = n & 3; i; i--) { 178 dst[0] = dst[1] = dst[2] = dst[3] = src[0]; 179 src++; 180 dst += 4; 181 } 182} 183 184static void remap_mono_to_ch4_float32ne_c(pa_remap_t *m, float *dst, const float *src, unsigned n) { 185 unsigned i; 186 187 for (i = n >> 2; i; i--) { 188 dst[0] = dst[1] = dst[2] = dst[3] = src[0]; 189 dst[4] = dst[5] = dst[6] = dst[7] = src[1]; 190 dst[8] = dst[9] = dst[10] = dst[11] = src[2]; 191 dst[12] = dst[13] = dst[14] = dst[15] = src[3]; 192 src += 4; 193 dst += 16; 194 } 195 for (i = n & 3; i; i--) { 196 dst[0] = dst[1] = dst[2] = dst[3] = src[0]; 197 src++; 198 dst += 4; 199 } 200} 201 202static void remap_ch4_to_mono_s16ne_c(pa_remap_t *m, int16_t *dst, const int16_t *src, unsigned n) { 203 unsigned i; 204 205 for (i = n >> 2; i > 0; i--) { 206 dst[0] = (src[0] + src[1] + src[2] + src[3])/4; 207 dst[1] = (src[4] + src[5] + src[6] + src[7])/4; 208 dst[2] = (src[8] + src[9] + src[10] + src[11])/4; 209 dst[3] = (src[12] + src[13] + src[14] + src[15])/4; 210 src += 16; 211 dst += 4; 212 } 213 for (i = n & 3; i; i--) { 214 dst[0] = (src[0] + src[1] + src[2] + src[3])/4; 215 src += 4; 216 dst += 1; 217 } 218} 219 220static void remap_ch4_to_mono_s32ne_c(pa_remap_t *m, int32_t *dst, const int32_t *src, unsigned n) { 221 unsigned i; 222 223 for (i = n >> 2; i > 0; i--) { 224 /* Avoid overflow by performing division first. We accept a 225 * difference of +/- 3 to the ideal result. */ 226 dst[0] = (src[0]/4 + src[1]/4 + src[2]/4 + src[3]/4); 227 dst[1] = (src[4]/4 + src[5]/4 + src[6]/4 + src[7]/4); 228 dst[2] = (src[8]/4 + src[9]/4 + src[10]/4 + src[11]/4); 229 dst[3] = (src[12]/4 + src[13]/4 + src[14]/4 + src[15]/4); 230 src += 16; 231 dst += 4; 232 } 233 for (i = n & 3; i; i--) { 234 /* Avoid overflow by performing division first. We accept a 235 * difference of +/- 3 to the ideal result. */ 236 dst[0] = (src[0]/4 + src[1]/4 + src[2]/4 + src[3]/4); 237 src += 4; 238 dst += 1; 239 } 240} 241 242static void remap_ch4_to_mono_float32ne_c(pa_remap_t *m, float *dst, const float *src, unsigned n) { 243 unsigned i; 244 245 for (i = n >> 2; i > 0; i--) { 246 dst[0] = (src[0] + src[1] + src[2] + src[3])*0.25f; 247 dst[1] = (src[4] + src[5] + src[6] + src[7])*0.25f; 248 dst[2] = (src[8] + src[9] + src[10] + src[11])*0.25f; 249 dst[3] = (src[12] + src[13] + src[14] + src[15])*0.25f; 250 src += 16; 251 dst += 4; 252 } 253 for (i = n & 3; i; i--) { 254 dst[0] = (src[0] + src[1] + src[2] + src[3])*0.25f; 255 src += 4; 256 dst += 1; 257 } 258} 259 260static void remap_channels_matrix_s16ne_c(pa_remap_t *m, int16_t *dst, const int16_t *src, unsigned n) { 261 262 unsigned oc, ic, i; 263 unsigned n_ic, n_oc; 264 265 n_ic = m->i_ss.channels; 266 n_oc = m->o_ss.channels; 267 268 memset(dst, 0, n * sizeof(int16_t) * n_oc); 269 270 for (oc = 0; oc < n_oc; oc++) { 271 272 for (ic = 0; ic < n_ic; ic++) { 273 int16_t *d = dst + oc; 274 const int16_t *s = src + ic; 275 int32_t vol = m->map_table_i[oc][ic]; 276 277 if (vol <= 0) 278 continue; 279 280 if (vol >= 0x10000) { 281 for (i = n; i > 0; i--, s += n_ic, d += n_oc) 282 *d += *s; 283 } else { 284 for (i = n; i > 0; i--, s += n_ic, d += n_oc) 285 *d += (int16_t) (((int32_t)*s * vol) >> 16); 286 } 287 } 288 } 289} 290 291static void remap_channels_matrix_s32ne_c(pa_remap_t *m, int32_t *dst, const int32_t *src, unsigned n) { 292 unsigned oc, ic, i; 293 unsigned n_ic, n_oc; 294 295 n_ic = m->i_ss.channels; 296 n_oc = m->o_ss.channels; 297 298 memset(dst, 0, n * sizeof(int32_t) * n_oc); 299 300 for (oc = 0; oc < n_oc; oc++) { 301 302 for (ic = 0; ic < n_ic; ic++) { 303 int32_t *d = dst + oc; 304 const int32_t *s = src + ic; 305 int32_t vol = m->map_table_i[oc][ic]; 306 307 if (vol <= 0) 308 continue; 309 310 if (vol >= 0x10000) { 311 for (i = n; i > 0; i--, s += n_ic, d += n_oc) 312 *d += *s; 313 } else { 314 for (i = n; i > 0; i--, s += n_ic, d += n_oc) 315 *d += (int32_t) (((int64_t)*s * vol) >> 16); 316 } 317 } 318 } 319} 320 321static void remap_channels_matrix_float32ne_c(pa_remap_t *m, float *dst, const float *src, unsigned n) { 322 unsigned oc, ic, i; 323 unsigned n_ic, n_oc; 324 325 n_ic = m->i_ss.channels; 326 n_oc = m->o_ss.channels; 327 328 memset(dst, 0, n * sizeof(float) * n_oc); 329 330 for (oc = 0; oc < n_oc; oc++) { 331 332 for (ic = 0; ic < n_ic; ic++) { 333 float *d = dst + oc; 334 const float *s = src + ic; 335 float vol = m->map_table_f[oc][ic]; 336 337 if (vol <= 0.0f) 338 continue; 339 340 if (vol >= 1.0f) { 341 for (i = n; i > 0; i--, s += n_ic, d += n_oc) 342 *d += *s; 343 } else { 344 for (i = n; i > 0; i--, s += n_ic, d += n_oc) 345 *d += *s * vol; 346 } 347 } 348 } 349} 350 351/* Produce an array containing input channel indices to map to output channels. 352 * If the output channel is empty, the array element is -1. */ 353bool pa_setup_remap_arrange(const pa_remap_t *m, int8_t arrange[PA_CHANNELS_MAX]) { 354 unsigned ic, oc; 355 unsigned n_ic, n_oc; 356 unsigned count_output = 0; 357 358 pa_assert(m); 359 360 n_ic = m->i_ss.channels; 361 n_oc = m->o_ss.channels; 362 363 for (oc = 0; oc < n_oc; oc++) { 364 arrange[oc] = -1; 365 for (ic = 0; ic < n_ic; ic++) { 366 int32_t vol = m->map_table_i[oc][ic]; 367 368 /* input channel is not used */ 369 if (vol == 0) 370 continue; 371 372 /* if mixing this channel, we cannot just rearrange */ 373 if (vol != 0x10000 || arrange[oc] >= 0) 374 return false; 375 376 arrange[oc] = ic; 377 count_output++; 378 } 379 } 380 381 return count_output > 0; 382} 383 384static void remap_arrange_mono_s16ne_c(pa_remap_t *m, int16_t *dst, const int16_t *src, unsigned n) { 385 const unsigned n_ic = m->i_ss.channels; 386 const int8_t *arrange = m->state; 387 388 src += arrange[0]; 389 for (; n > 0; n--) { 390 *dst++ = *src; 391 src += n_ic; 392 } 393} 394 395static void remap_arrange_stereo_s16ne_c(pa_remap_t *m, int16_t *dst, const int16_t *src, unsigned n) { 396 const unsigned n_ic = m->i_ss.channels; 397 const int8_t *arrange = m->state; 398 const int8_t ic0 = arrange[0], ic1 = arrange[1]; 399 400 for (; n > 0; n--) { 401 *dst++ = (ic0 >= 0) ? *(src + ic0) : 0; 402 *dst++ = (ic1 >= 0) ? *(src + ic1) : 0; 403 src += n_ic; 404 } 405} 406 407static void remap_arrange_ch4_s16ne_c(pa_remap_t *m, int16_t *dst, const int16_t *src, unsigned n) { 408 const unsigned n_ic = m->i_ss.channels; 409 const int8_t *arrange = m->state; 410 const int8_t ic0 = arrange[0], ic1 = arrange[1], 411 ic2 = arrange[2], ic3 = arrange[3]; 412 413 for (; n > 0; n--) { 414 *dst++ = (ic0 >= 0) ? *(src + ic0) : 0; 415 *dst++ = (ic1 >= 0) ? *(src + ic1) : 0; 416 *dst++ = (ic2 >= 0) ? *(src + ic2) : 0; 417 *dst++ = (ic3 >= 0) ? *(src + ic3) : 0; 418 src += n_ic; 419 } 420} 421 422static void remap_arrange_mono_s32ne_c(pa_remap_t *m, int32_t *dst, const int32_t *src, unsigned n) { 423 const unsigned n_ic = m->i_ss.channels; 424 const int8_t *arrange = m->state; 425 426 src += arrange[0]; 427 for (; n > 0; n--) { 428 *dst++ = *src; 429 src += n_ic; 430 } 431} 432 433static void remap_arrange_stereo_s32ne_c(pa_remap_t *m, int32_t *dst, const int32_t *src, unsigned n) { 434 const unsigned n_ic = m->i_ss.channels; 435 const int8_t *arrange = m->state; 436 const int ic0 = arrange[0], ic1 = arrange[1]; 437 438 for (; n > 0; n--) { 439 *dst++ = (ic0 >= 0) ? *(src + ic0) : 0; 440 *dst++ = (ic1 >= 0) ? *(src + ic1) : 0; 441 src += n_ic; 442 } 443} 444 445static void remap_arrange_ch4_s32ne_c(pa_remap_t *m, int32_t *dst, const int32_t *src, unsigned n) { 446 const unsigned n_ic = m->i_ss.channels; 447 const int8_t *arrange = m->state; 448 const int ic0 = arrange[0], ic1 = arrange[1], 449 ic2 = arrange[2], ic3 = arrange[3]; 450 451 for (; n > 0; n--) { 452 *dst++ = (ic0 >= 0) ? *(src + ic0) : 0; 453 *dst++ = (ic1 >= 0) ? *(src + ic1) : 0; 454 *dst++ = (ic2 >= 0) ? *(src + ic2) : 0; 455 *dst++ = (ic3 >= 0) ? *(src + ic3) : 0; 456 src += n_ic; 457 } 458} 459 460static void remap_arrange_mono_float32ne_c(pa_remap_t *m, float *dst, const float *src, unsigned n) { 461 const unsigned n_ic = m->i_ss.channels; 462 const int8_t *arrange = m->state; 463 464 src += arrange[0]; 465 for (; n > 0; n--) { 466 *dst++ = *src; 467 src += n_ic; 468 } 469} 470 471static void remap_arrange_stereo_float32ne_c(pa_remap_t *m, float *dst, const float *src, unsigned n) { 472 const unsigned n_ic = m->i_ss.channels; 473 const int8_t *arrange = m->state; 474 const int ic0 = arrange[0], ic1 = arrange[1]; 475 476 for (; n > 0; n--) { 477 *dst++ = (ic0 >= 0) ? *(src + ic0) : 0.0f; 478 *dst++ = (ic1 >= 0) ? *(src + ic1) : 0.0f; 479 src += n_ic; 480 } 481} 482 483static void remap_arrange_ch4_float32ne_c(pa_remap_t *m, float *dst, const float *src, unsigned n) { 484 const unsigned n_ic = m->i_ss.channels; 485 const int8_t *arrange = m->state; 486 const int ic0 = arrange[0], ic1 = arrange[1], 487 ic2 = arrange[2], ic3 = arrange[3]; 488 489 for (; n > 0; n--) { 490 *dst++ = (ic0 >= 0) ? *(src + ic0) : 0.0f; 491 *dst++ = (ic1 >= 0) ? *(src + ic1) : 0.0f; 492 *dst++ = (ic2 >= 0) ? *(src + ic2) : 0.0f; 493 *dst++ = (ic3 >= 0) ? *(src + ic3) : 0.0f; 494 src += n_ic; 495 } 496} 497 498void pa_set_remap_func(pa_remap_t *m, pa_do_remap_func_t func_s16, 499 pa_do_remap_func_t func_s32, pa_do_remap_func_t func_float) { 500 501 pa_assert(m); 502 503 if (m->format == PA_SAMPLE_S16NE) 504 m->do_remap = func_s16; 505 else if (m->format == PA_SAMPLE_S32NE) 506 m->do_remap = func_s32; 507 else if (m->format == PA_SAMPLE_FLOAT32NE) 508 m->do_remap = func_float; 509 else 510 pa_assert_not_reached(); 511 pa_assert(m->do_remap); 512} 513 514static bool force_generic_code = false; 515 516/* set the function that will execute the remapping based on the matrices */ 517static void init_remap_c(pa_remap_t *m) { 518 unsigned n_oc, n_ic; 519 int8_t arrange[PA_CHANNELS_MAX]; 520 521 n_oc = m->o_ss.channels; 522 n_ic = m->i_ss.channels; 523 524 /* find some common channel remappings, fall back to full matrix operation. */ 525 if (force_generic_code) { 526 pa_log_info("Forced to use generic matrix remapping"); 527 pa_set_remap_func(m, (pa_do_remap_func_t) remap_channels_matrix_s16ne_c, 528 (pa_do_remap_func_t) remap_channels_matrix_s32ne_c, 529 (pa_do_remap_func_t) remap_channels_matrix_float32ne_c); 530 return; 531 } 532 533 if (n_ic == 1 && n_oc == 2 && 534 m->map_table_i[0][0] == 0x10000 && m->map_table_i[1][0] == 0x10000) { 535 536 pa_log_info("Using mono to stereo remapping"); 537 pa_set_remap_func(m, (pa_do_remap_func_t) remap_mono_to_stereo_s16ne_c, 538 (pa_do_remap_func_t) remap_mono_to_stereo_s32ne_c, 539 (pa_do_remap_func_t) remap_mono_to_stereo_float32ne_c); 540 } else if (n_ic == 2 && n_oc == 1 && 541 m->map_table_i[0][0] == 0x8000 && m->map_table_i[0][1] == 0x8000) { 542 543 pa_log_info("Using stereo to mono remapping"); 544 pa_set_remap_func(m, (pa_do_remap_func_t) remap_stereo_to_mono_s16ne_c, 545 (pa_do_remap_func_t) remap_stereo_to_mono_s32ne_c, 546 (pa_do_remap_func_t) remap_stereo_to_mono_float32ne_c); 547 } else if (n_ic == 1 && n_oc == 4 && 548 m->map_table_i[0][0] == 0x10000 && m->map_table_i[1][0] == 0x10000 && 549 m->map_table_i[2][0] == 0x10000 && m->map_table_i[3][0] == 0x10000) { 550 551 pa_log_info("Using mono to 4-channel remapping"); 552 pa_set_remap_func(m, (pa_do_remap_func_t)remap_mono_to_ch4_s16ne_c, 553 (pa_do_remap_func_t) remap_mono_to_ch4_s32ne_c, 554 (pa_do_remap_func_t) remap_mono_to_ch4_float32ne_c); 555 } else if (n_ic == 4 && n_oc == 1 && 556 m->map_table_i[0][0] == 0x4000 && m->map_table_i[0][1] == 0x4000 && 557 m->map_table_i[0][2] == 0x4000 && m->map_table_i[0][3] == 0x4000) { 558 559 pa_log_info("Using 4-channel to mono remapping"); 560 pa_set_remap_func(m, (pa_do_remap_func_t) remap_ch4_to_mono_s16ne_c, 561 (pa_do_remap_func_t) remap_ch4_to_mono_s32ne_c, 562 (pa_do_remap_func_t) remap_ch4_to_mono_float32ne_c); 563 } else if (pa_setup_remap_arrange(m, arrange) && n_oc == 1) { 564 565 pa_log_info("Using mono arrange remapping"); 566 pa_set_remap_func(m, (pa_do_remap_func_t) remap_arrange_mono_s16ne_c, 567 (pa_do_remap_func_t) remap_arrange_mono_s32ne_c, 568 (pa_do_remap_func_t) remap_arrange_mono_float32ne_c); 569 570 /* setup state */ 571 m->state = pa_xnewdup(int8_t, arrange, PA_CHANNELS_MAX); 572 } else if (pa_setup_remap_arrange(m, arrange) && n_oc == 2) { 573 574 pa_log_info("Using stereo arrange remapping"); 575 pa_set_remap_func(m, (pa_do_remap_func_t) remap_arrange_stereo_s16ne_c, 576 (pa_do_remap_func_t) remap_arrange_stereo_s32ne_c, 577 (pa_do_remap_func_t) remap_arrange_stereo_float32ne_c); 578 579 /* setup state */ 580 m->state = pa_xnewdup(int8_t, arrange, PA_CHANNELS_MAX); 581 } else if (pa_setup_remap_arrange(m, arrange) && n_oc == 4) { 582 583 pa_log_info("Using 4-channel arrange remapping"); 584 pa_set_remap_func(m, (pa_do_remap_func_t) remap_arrange_ch4_s16ne_c, 585 (pa_do_remap_func_t) remap_arrange_ch4_s32ne_c, 586 (pa_do_remap_func_t) remap_arrange_ch4_float32ne_c); 587 588 /* setup state */ 589 m->state = pa_xnewdup(int8_t, arrange, PA_CHANNELS_MAX); 590 } else { 591 592 pa_log_info("Using generic matrix remapping"); 593 pa_set_remap_func(m, (pa_do_remap_func_t) remap_channels_matrix_s16ne_c, 594 (pa_do_remap_func_t) remap_channels_matrix_s32ne_c, 595 (pa_do_remap_func_t) remap_channels_matrix_float32ne_c); 596 } 597} 598 599/* default C implementation */ 600static pa_init_remap_func_t init_remap_func = init_remap_c; 601 602void pa_init_remap_func(pa_remap_t *m) { 603 pa_assert(init_remap_func); 604 605 m->do_remap = NULL; 606 607 /* call the installed remap init function */ 608 init_remap_func(m); 609 610 if (m->do_remap == NULL) { 611 /* nothing was installed, fallback to C version */ 612 init_remap_c(m); 613 } 614} 615 616pa_init_remap_func_t pa_get_init_remap_func(void) { 617 return init_remap_func; 618} 619 620void pa_set_init_remap_func(pa_init_remap_func_t func) { 621 init_remap_func = func; 622} 623 624void pa_remap_func_init(const pa_cpu_info *cpu_info) { 625 force_generic_code = cpu_info->force_generic_code; 626} 627