1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 3 /* 4 * Xen para-virtual sound device 5 * 6 * Copyright (C) 2016-2018 EPAM Systems Inc. 7 * 8 * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> 9 */ 10 11 #include <xen/xenbus.h> 12 13 #include <xen/interface/io/sndif.h> 14 15 #include "xen_snd_front.h" 16 #include "xen_snd_front_cfg.h" 17 18 /* Maximum number of supported streams. */ 19 #define VSND_MAX_STREAM 8 20 21 struct cfg_hw_sample_rate { 22 const char *name; 23 unsigned int mask; 24 unsigned int value; 25 }; 26 27 static const struct cfg_hw_sample_rate CFG_HW_SUPPORTED_RATES[] = { 28 { .name = "5512", .mask = SNDRV_PCM_RATE_5512, .value = 5512 }, 29 { .name = "8000", .mask = SNDRV_PCM_RATE_8000, .value = 8000 }, 30 { .name = "11025", .mask = SNDRV_PCM_RATE_11025, .value = 11025 }, 31 { .name = "16000", .mask = SNDRV_PCM_RATE_16000, .value = 16000 }, 32 { .name = "22050", .mask = SNDRV_PCM_RATE_22050, .value = 22050 }, 33 { .name = "32000", .mask = SNDRV_PCM_RATE_32000, .value = 32000 }, 34 { .name = "44100", .mask = SNDRV_PCM_RATE_44100, .value = 44100 }, 35 { .name = "48000", .mask = SNDRV_PCM_RATE_48000, .value = 48000 }, 36 { .name = "64000", .mask = SNDRV_PCM_RATE_64000, .value = 64000 }, 37 { .name = "96000", .mask = SNDRV_PCM_RATE_96000, .value = 96000 }, 38 { .name = "176400", .mask = SNDRV_PCM_RATE_176400, .value = 176400 }, 39 { .name = "192000", .mask = SNDRV_PCM_RATE_192000, .value = 192000 }, 40 }; 41 42 struct cfg_hw_sample_format { 43 const char *name; 44 u64 mask; 45 }; 46 47 static const struct cfg_hw_sample_format CFG_HW_SUPPORTED_FORMATS[] = { 48 { 49 .name = XENSND_PCM_FORMAT_U8_STR, 50 .mask = SNDRV_PCM_FMTBIT_U8 51 }, 52 { 53 .name = XENSND_PCM_FORMAT_S8_STR, 54 .mask = SNDRV_PCM_FMTBIT_S8 55 }, 56 { 57 .name = XENSND_PCM_FORMAT_U16_LE_STR, 58 .mask = SNDRV_PCM_FMTBIT_U16_LE 59 }, 60 { 61 .name = XENSND_PCM_FORMAT_U16_BE_STR, 62 .mask = SNDRV_PCM_FMTBIT_U16_BE 63 }, 64 { 65 .name = XENSND_PCM_FORMAT_S16_LE_STR, 66 .mask = SNDRV_PCM_FMTBIT_S16_LE 67 }, 68 { 69 .name = XENSND_PCM_FORMAT_S16_BE_STR, 70 .mask = SNDRV_PCM_FMTBIT_S16_BE 71 }, 72 { 73 .name = XENSND_PCM_FORMAT_U24_LE_STR, 74 .mask = SNDRV_PCM_FMTBIT_U24_LE 75 }, 76 { 77 .name = XENSND_PCM_FORMAT_U24_BE_STR, 78 .mask = SNDRV_PCM_FMTBIT_U24_BE 79 }, 80 { 81 .name = XENSND_PCM_FORMAT_S24_LE_STR, 82 .mask = SNDRV_PCM_FMTBIT_S24_LE 83 }, 84 { 85 .name = XENSND_PCM_FORMAT_S24_BE_STR, 86 .mask = SNDRV_PCM_FMTBIT_S24_BE 87 }, 88 { 89 .name = XENSND_PCM_FORMAT_U32_LE_STR, 90 .mask = SNDRV_PCM_FMTBIT_U32_LE 91 }, 92 { 93 .name = XENSND_PCM_FORMAT_U32_BE_STR, 94 .mask = SNDRV_PCM_FMTBIT_U32_BE 95 }, 96 { 97 .name = XENSND_PCM_FORMAT_S32_LE_STR, 98 .mask = SNDRV_PCM_FMTBIT_S32_LE 99 }, 100 { 101 .name = XENSND_PCM_FORMAT_S32_BE_STR, 102 .mask = SNDRV_PCM_FMTBIT_S32_BE 103 }, 104 { 105 .name = XENSND_PCM_FORMAT_A_LAW_STR, 106 .mask = SNDRV_PCM_FMTBIT_A_LAW 107 }, 108 { 109 .name = XENSND_PCM_FORMAT_MU_LAW_STR, 110 .mask = SNDRV_PCM_FMTBIT_MU_LAW 111 }, 112 { 113 .name = XENSND_PCM_FORMAT_F32_LE_STR, 114 .mask = SNDRV_PCM_FMTBIT_FLOAT_LE 115 }, 116 { 117 .name = XENSND_PCM_FORMAT_F32_BE_STR, 118 .mask = SNDRV_PCM_FMTBIT_FLOAT_BE 119 }, 120 { 121 .name = XENSND_PCM_FORMAT_F64_LE_STR, 122 .mask = SNDRV_PCM_FMTBIT_FLOAT64_LE 123 }, 124 { 125 .name = XENSND_PCM_FORMAT_F64_BE_STR, 126 .mask = SNDRV_PCM_FMTBIT_FLOAT64_BE 127 }, 128 { 129 .name = XENSND_PCM_FORMAT_IEC958_SUBFRAME_LE_STR, 130 .mask = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE 131 }, 132 { 133 .name = XENSND_PCM_FORMAT_IEC958_SUBFRAME_BE_STR, 134 .mask = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE 135 }, 136 { 137 .name = XENSND_PCM_FORMAT_IMA_ADPCM_STR, 138 .mask = SNDRV_PCM_FMTBIT_IMA_ADPCM 139 }, 140 { 141 .name = XENSND_PCM_FORMAT_MPEG_STR, 142 .mask = SNDRV_PCM_FMTBIT_MPEG 143 }, 144 { 145 .name = XENSND_PCM_FORMAT_GSM_STR, 146 .mask = SNDRV_PCM_FMTBIT_GSM 147 }, 148 }; 149 150 static void cfg_hw_rates(char *list, unsigned int len, 151 const char *path, struct snd_pcm_hardware *pcm_hw) 152 { 153 char *cur_rate; 154 unsigned int cur_mask; 155 unsigned int cur_value; 156 unsigned int rates; 157 unsigned int rate_min; 158 unsigned int rate_max; 159 int i; 160 161 rates = 0; 162 rate_min = -1; 163 rate_max = 0; 164 while ((cur_rate = strsep(&list, XENSND_LIST_SEPARATOR))) { 165 for (i = 0; i < ARRAY_SIZE(CFG_HW_SUPPORTED_RATES); i++) 166 if (!strncasecmp(cur_rate, 167 CFG_HW_SUPPORTED_RATES[i].name, 168 XENSND_SAMPLE_RATE_MAX_LEN)) { 169 cur_mask = CFG_HW_SUPPORTED_RATES[i].mask; 170 cur_value = CFG_HW_SUPPORTED_RATES[i].value; 171 rates |= cur_mask; 172 if (rate_min > cur_value) 173 rate_min = cur_value; 174 if (rate_max < cur_value) 175 rate_max = cur_value; 176 } 177 } 178 179 if (rates) { 180 pcm_hw->rates = rates; 181 pcm_hw->rate_min = rate_min; 182 pcm_hw->rate_max = rate_max; 183 } 184 } 185 186 static void cfg_formats(char *list, unsigned int len, 187 const char *path, struct snd_pcm_hardware *pcm_hw) 188 { 189 u64 formats; 190 char *cur_format; 191 int i; 192 193 formats = 0; 194 while ((cur_format = strsep(&list, XENSND_LIST_SEPARATOR))) { 195 for (i = 0; i < ARRAY_SIZE(CFG_HW_SUPPORTED_FORMATS); i++) 196 if (!strncasecmp(cur_format, 197 CFG_HW_SUPPORTED_FORMATS[i].name, 198 XENSND_SAMPLE_FORMAT_MAX_LEN)) 199 formats |= CFG_HW_SUPPORTED_FORMATS[i].mask; 200 } 201 202 if (formats) 203 pcm_hw->formats = formats; 204 } 205 206 #define MAX_BUFFER_SIZE (64 * 1024) 207 #define MIN_PERIOD_SIZE 64 208 #define MAX_PERIOD_SIZE MAX_BUFFER_SIZE 209 #define USE_FORMATS (SNDRV_PCM_FMTBIT_U8 | \ 210 SNDRV_PCM_FMTBIT_S16_LE) 211 #define USE_RATE (SNDRV_PCM_RATE_CONTINUOUS | \ 212 SNDRV_PCM_RATE_8000_48000) 213 #define USE_RATE_MIN 5512 214 #define USE_RATE_MAX 48000 215 #define USE_CHANNELS_MIN 1 216 #define USE_CHANNELS_MAX 2 217 #define USE_PERIODS_MIN 2 218 #define USE_PERIODS_MAX (MAX_BUFFER_SIZE / MIN_PERIOD_SIZE) 219 220 static const struct snd_pcm_hardware SND_DRV_PCM_HW_DEFAULT = { 221 .info = (SNDRV_PCM_INFO_MMAP | 222 SNDRV_PCM_INFO_INTERLEAVED | 223 SNDRV_PCM_INFO_RESUME | 224 SNDRV_PCM_INFO_MMAP_VALID), 225 .formats = USE_FORMATS, 226 .rates = USE_RATE, 227 .rate_min = USE_RATE_MIN, 228 .rate_max = USE_RATE_MAX, 229 .channels_min = USE_CHANNELS_MIN, 230 .channels_max = USE_CHANNELS_MAX, 231 .buffer_bytes_max = MAX_BUFFER_SIZE, 232 .period_bytes_min = MIN_PERIOD_SIZE, 233 .period_bytes_max = MAX_PERIOD_SIZE, 234 .periods_min = USE_PERIODS_MIN, 235 .periods_max = USE_PERIODS_MAX, 236 .fifo_size = 0, 237 }; 238 239 static void cfg_read_pcm_hw(const char *path, 240 struct snd_pcm_hardware *parent_pcm_hw, 241 struct snd_pcm_hardware *pcm_hw) 242 { 243 char *list; 244 int val; 245 size_t buf_sz; 246 unsigned int len; 247 248 /* Inherit parent's PCM HW and read overrides from XenStore. */ 249 if (parent_pcm_hw) 250 *pcm_hw = *parent_pcm_hw; 251 else 252 *pcm_hw = SND_DRV_PCM_HW_DEFAULT; 253 254 val = xenbus_read_unsigned(path, XENSND_FIELD_CHANNELS_MIN, 0); 255 if (val) 256 pcm_hw->channels_min = val; 257 258 val = xenbus_read_unsigned(path, XENSND_FIELD_CHANNELS_MAX, 0); 259 if (val) 260 pcm_hw->channels_max = val; 261 262 list = xenbus_read(XBT_NIL, path, XENSND_FIELD_SAMPLE_RATES, &len); 263 if (!IS_ERR(list)) { 264 cfg_hw_rates(list, len, path, pcm_hw); 265 kfree(list); 266 } 267 268 list = xenbus_read(XBT_NIL, path, XENSND_FIELD_SAMPLE_FORMATS, &len); 269 if (!IS_ERR(list)) { 270 cfg_formats(list, len, path, pcm_hw); 271 kfree(list); 272 } 273 274 buf_sz = xenbus_read_unsigned(path, XENSND_FIELD_BUFFER_SIZE, 0); 275 if (buf_sz) 276 pcm_hw->buffer_bytes_max = buf_sz; 277 278 /* Update configuration to match new values. */ 279 if (pcm_hw->channels_min > pcm_hw->channels_max) 280 pcm_hw->channels_min = pcm_hw->channels_max; 281 282 if (pcm_hw->rate_min > pcm_hw->rate_max) 283 pcm_hw->rate_min = pcm_hw->rate_max; 284 285 pcm_hw->period_bytes_max = pcm_hw->buffer_bytes_max; 286 287 pcm_hw->periods_max = pcm_hw->period_bytes_max / 288 pcm_hw->period_bytes_min; 289 } 290 291 static int cfg_get_stream_type(const char *path, int index, 292 int *num_pb, int *num_cap) 293 { 294 char *str = NULL; 295 char *stream_path; 296 int ret; 297 298 *num_pb = 0; 299 *num_cap = 0; 300 stream_path = kasprintf(GFP_KERNEL, "%s/%d", path, index); 301 if (!stream_path) { 302 ret = -ENOMEM; 303 goto fail; 304 } 305 306 str = xenbus_read(XBT_NIL, stream_path, XENSND_FIELD_TYPE, NULL); 307 if (IS_ERR(str)) { 308 ret = PTR_ERR(str); 309 goto fail; 310 } 311 312 if (!strncasecmp(str, XENSND_STREAM_TYPE_PLAYBACK, 313 sizeof(XENSND_STREAM_TYPE_PLAYBACK))) { 314 (*num_pb)++; 315 } else if (!strncasecmp(str, XENSND_STREAM_TYPE_CAPTURE, 316 sizeof(XENSND_STREAM_TYPE_CAPTURE))) { 317 (*num_cap)++; 318 } else { 319 ret = -EINVAL; 320 goto fail; 321 } 322 ret = 0; 323 324 fail: 325 kfree(stream_path); 326 kfree(str); 327 return ret; 328 } 329 330 static int cfg_stream(struct xen_snd_front_info *front_info, 331 struct xen_front_cfg_pcm_instance *pcm_instance, 332 const char *path, int index, int *cur_pb, int *cur_cap, 333 int *stream_cnt) 334 { 335 char *str = NULL; 336 char *stream_path; 337 struct xen_front_cfg_stream *stream; 338 int ret; 339 340 stream_path = devm_kasprintf(&front_info->xb_dev->dev, 341 GFP_KERNEL, "%s/%d", path, index); 342 if (!stream_path) { 343 ret = -ENOMEM; 344 goto fail; 345 } 346 347 str = xenbus_read(XBT_NIL, stream_path, XENSND_FIELD_TYPE, NULL); 348 if (IS_ERR(str)) { 349 ret = PTR_ERR(str); 350 goto fail; 351 } 352 353 if (!strncasecmp(str, XENSND_STREAM_TYPE_PLAYBACK, 354 sizeof(XENSND_STREAM_TYPE_PLAYBACK))) { 355 stream = &pcm_instance->streams_pb[(*cur_pb)++]; 356 } else if (!strncasecmp(str, XENSND_STREAM_TYPE_CAPTURE, 357 sizeof(XENSND_STREAM_TYPE_CAPTURE))) { 358 stream = &pcm_instance->streams_cap[(*cur_cap)++]; 359 } else { 360 ret = -EINVAL; 361 goto fail; 362 } 363 364 /* Get next stream index. */ 365 stream->index = (*stream_cnt)++; 366 stream->xenstore_path = stream_path; 367 /* 368 * Check XenStore if PCM HW configuration exists for this stream 369 * and update if so, e.g. we inherit all values from device's PCM HW, 370 * but can still override some of the values for the stream. 371 */ 372 cfg_read_pcm_hw(stream->xenstore_path, 373 &pcm_instance->pcm_hw, &stream->pcm_hw); 374 ret = 0; 375 376 fail: 377 kfree(str); 378 return ret; 379 } 380 381 static int cfg_device(struct xen_snd_front_info *front_info, 382 struct xen_front_cfg_pcm_instance *pcm_instance, 383 struct snd_pcm_hardware *parent_pcm_hw, 384 const char *path, int node_index, int *stream_cnt) 385 { 386 char *str; 387 char *device_path; 388 int ret, i, num_streams; 389 int num_pb, num_cap; 390 int cur_pb, cur_cap; 391 char node[3]; 392 393 device_path = kasprintf(GFP_KERNEL, "%s/%d", path, node_index); 394 if (!device_path) 395 return -ENOMEM; 396 397 str = xenbus_read(XBT_NIL, device_path, XENSND_FIELD_DEVICE_NAME, NULL); 398 if (!IS_ERR(str)) { 399 strncpy(pcm_instance->name, str, sizeof(pcm_instance->name)); 400 kfree(str); 401 } 402 403 pcm_instance->device_id = node_index; 404 405 /* 406 * Check XenStore if PCM HW configuration exists for this device 407 * and update if so, e.g. we inherit all values from card's PCM HW, 408 * but can still override some of the values for the device. 409 */ 410 cfg_read_pcm_hw(device_path, parent_pcm_hw, &pcm_instance->pcm_hw); 411 412 /* Find out how many streams were configured in Xen store. */ 413 num_streams = 0; 414 do { 415 snprintf(node, sizeof(node), "%d", num_streams); 416 if (!xenbus_exists(XBT_NIL, device_path, node)) 417 break; 418 419 num_streams++; 420 } while (num_streams < VSND_MAX_STREAM); 421 422 pcm_instance->num_streams_pb = 0; 423 pcm_instance->num_streams_cap = 0; 424 /* Get number of playback and capture streams. */ 425 for (i = 0; i < num_streams; i++) { 426 ret = cfg_get_stream_type(device_path, i, &num_pb, &num_cap); 427 if (ret < 0) 428 goto fail; 429 430 pcm_instance->num_streams_pb += num_pb; 431 pcm_instance->num_streams_cap += num_cap; 432 } 433 434 if (pcm_instance->num_streams_pb) { 435 pcm_instance->streams_pb = 436 devm_kcalloc(&front_info->xb_dev->dev, 437 pcm_instance->num_streams_pb, 438 sizeof(struct xen_front_cfg_stream), 439 GFP_KERNEL); 440 if (!pcm_instance->streams_pb) { 441 ret = -ENOMEM; 442 goto fail; 443 } 444 } 445 446 if (pcm_instance->num_streams_cap) { 447 pcm_instance->streams_cap = 448 devm_kcalloc(&front_info->xb_dev->dev, 449 pcm_instance->num_streams_cap, 450 sizeof(struct xen_front_cfg_stream), 451 GFP_KERNEL); 452 if (!pcm_instance->streams_cap) { 453 ret = -ENOMEM; 454 goto fail; 455 } 456 } 457 458 cur_pb = 0; 459 cur_cap = 0; 460 for (i = 0; i < num_streams; i++) { 461 ret = cfg_stream(front_info, pcm_instance, device_path, i, 462 &cur_pb, &cur_cap, stream_cnt); 463 if (ret < 0) 464 goto fail; 465 } 466 ret = 0; 467 468 fail: 469 kfree(device_path); 470 return ret; 471 } 472 473 int xen_snd_front_cfg_card(struct xen_snd_front_info *front_info, 474 int *stream_cnt) 475 { 476 struct xenbus_device *xb_dev = front_info->xb_dev; 477 struct xen_front_cfg_card *cfg = &front_info->cfg; 478 int ret, num_devices, i; 479 char node[3]; 480 481 *stream_cnt = 0; 482 num_devices = 0; 483 do { 484 snprintf(node, sizeof(node), "%d", num_devices); 485 if (!xenbus_exists(XBT_NIL, xb_dev->nodename, node)) 486 break; 487 488 num_devices++; 489 } while (num_devices < SNDRV_PCM_DEVICES); 490 491 if (!num_devices) { 492 dev_warn(&xb_dev->dev, 493 "No devices configured for sound card at %s\n", 494 xb_dev->nodename); 495 return -ENODEV; 496 } 497 498 /* Start from default PCM HW configuration for the card. */ 499 cfg_read_pcm_hw(xb_dev->nodename, NULL, &cfg->pcm_hw); 500 501 cfg->pcm_instances = 502 devm_kcalloc(&front_info->xb_dev->dev, num_devices, 503 sizeof(struct xen_front_cfg_pcm_instance), 504 GFP_KERNEL); 505 if (!cfg->pcm_instances) 506 return -ENOMEM; 507 508 for (i = 0; i < num_devices; i++) { 509 ret = cfg_device(front_info, &cfg->pcm_instances[i], 510 &cfg->pcm_hw, xb_dev->nodename, i, stream_cnt); 511 if (ret < 0) 512 return ret; 513 } 514 cfg->num_pcm_instances = num_devices; 515 return 0; 516 } 517 518