2964 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Asihpi soundcard4 * Copyright (c) by AudioScience Inc <support@audioscience.com>5 *6 * The following is not a condition of use, merely a request:7 * If you modify this program, particularly if you fix errors, AudioScience Inc8 * would appreciate it if you grant us the right to use those modifications9 * for any purpose including commercial applications.10 */11 12#include "hpi_internal.h"13#include "hpi_version.h"14#include "hpimsginit.h"15#include "hpioctl.h"16#include "hpicmn.h"17 18#include <linux/pci.h>19#include <linux/init.h>20#include <linux/jiffies.h>21#include <linux/slab.h>22#include <linux/time.h>23#include <linux/wait.h>24#include <linux/module.h>25#include <sound/core.h>26#include <sound/control.h>27#include <sound/pcm.h>28#include <sound/pcm_params.h>29#include <sound/info.h>30#include <sound/initval.h>31#include <sound/tlv.h>32#include <sound/hwdep.h>33 34MODULE_LICENSE("GPL");35MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>");36MODULE_DESCRIPTION("AudioScience ALSA ASI5xxx ASI6xxx ASI87xx ASI89xx "37 HPI_VER_STRING);38 39#ifdef ASIHPI_VERBOSE_DEBUG40#define asihpi_dbg(format, args...) pr_debug(format, ##args)41#else42#define asihpi_dbg(format, args...) do { } while (0)43#endif44 45static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* index 0-MAX */46static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */47static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;48static bool enable_hpi_hwdep = 1;49 50module_param_array(index, int, NULL, 0444);51MODULE_PARM_DESC(index, "ALSA index value for AudioScience soundcard.");52 53module_param_array(id, charp, NULL, 0444);54MODULE_PARM_DESC(id, "ALSA ID string for AudioScience soundcard.");55 56module_param_array(enable, bool, NULL, 0444);57MODULE_PARM_DESC(enable, "ALSA enable AudioScience soundcard.");58 59module_param(enable_hpi_hwdep, bool, 0644);60MODULE_PARM_DESC(enable_hpi_hwdep,61 "ALSA enable HPI hwdep for AudioScience soundcard ");62 63/* identify driver */64#ifdef KERNEL_ALSA_BUILD65static char *build_info = "Built using headers from kernel source";66module_param(build_info, charp, 0444);67MODULE_PARM_DESC(build_info, "Built using headers from kernel source");68#else69static char *build_info = "Built within ALSA source";70module_param(build_info, charp, 0444);71MODULE_PARM_DESC(build_info, "Built within ALSA source");72#endif73 74/* set to 1 to dump every control from adapter to log */75static const int mixer_dump;76 77#define DEFAULT_SAMPLERATE 4410078static int adapter_fs = DEFAULT_SAMPLERATE;79 80/* defaults */81#define PERIODS_MIN 282#define PERIOD_BYTES_MIN 204883#define BUFFER_BYTES_MAX (512 * 1024)84 85#define MAX_CLOCKSOURCES (HPI_SAMPLECLOCK_SOURCE_LAST + 1 + 7)86 87struct clk_source {88 int source;89 int index;90 const char *name;91};92 93struct clk_cache {94 int count;95 int has_local;96 struct clk_source s[MAX_CLOCKSOURCES];97};98 99/* Per card data */100struct snd_card_asihpi {101 struct snd_card *card;102 struct pci_dev *pci;103 struct hpi_adapter *hpi;104 105 /* In low latency mode there is only one stream, a pointer to its106 * private data is stored here on trigger and cleared on stop.107 * The interrupt handler uses it as a parameter when calling108 * snd_card_asihpi_timer_function().109 */110 struct snd_card_asihpi_pcm *llmode_streampriv;111 void (*pcm_start)(struct snd_pcm_substream *substream);112 void (*pcm_stop)(struct snd_pcm_substream *substream);113 114 u32 h_mixer;115 struct clk_cache cc;116 117 u16 can_dma;118 u16 support_grouping;119 u16 support_mrx;120 u16 update_interval_frames;121 u16 in_max_chans;122 u16 out_max_chans;123 u16 in_min_chans;124 u16 out_min_chans;125};126 127/* Per stream data */128struct snd_card_asihpi_pcm {129 struct timer_list timer;130 unsigned int respawn_timer;131 unsigned int hpi_buffer_attached;132 unsigned int buffer_bytes;133 unsigned int period_bytes;134 unsigned int bytes_per_sec;135 unsigned int pcm_buf_host_rw_ofs; /* Host R/W pos */136 unsigned int pcm_buf_dma_ofs; /* DMA R/W offset in buffer */137 unsigned int pcm_buf_elapsed_dma_ofs; /* DMA R/W offset in buffer */138 unsigned int drained_count;139 struct snd_pcm_substream *substream;140 u32 h_stream;141 struct hpi_format format;142};143 144/* universal stream verbs work with out or in stream handles */145 146/* Functions to allow driver to give a buffer to HPI for busmastering */147 148static u16 hpi_stream_host_buffer_attach(149 u32 h_stream, /* handle to outstream. */150 u32 size_in_bytes, /* size in bytes of bus mastering buffer */151 u32 pci_address152)153{154 struct hpi_message hm;155 struct hpi_response hr;156 unsigned int obj = hpi_handle_object(h_stream);157 158 if (!h_stream)159 return HPI_ERROR_INVALID_OBJ;160 hpi_init_message_response(&hm, &hr, obj,161 obj == HPI_OBJ_OSTREAM ?162 HPI_OSTREAM_HOSTBUFFER_ALLOC :163 HPI_ISTREAM_HOSTBUFFER_ALLOC);164 165 hpi_handle_to_indexes(h_stream, &hm.adapter_index,166 &hm.obj_index);167 168 hm.u.d.u.buffer.buffer_size = size_in_bytes;169 hm.u.d.u.buffer.pci_address = pci_address;170 hm.u.d.u.buffer.command = HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER;171 hpi_send_recv(&hm, &hr);172 return hr.error;173}174 175static u16 hpi_stream_host_buffer_detach(u32 h_stream)176{177 struct hpi_message hm;178 struct hpi_response hr;179 unsigned int obj = hpi_handle_object(h_stream);180 181 if (!h_stream)182 return HPI_ERROR_INVALID_OBJ;183 184 hpi_init_message_response(&hm, &hr, obj,185 obj == HPI_OBJ_OSTREAM ?186 HPI_OSTREAM_HOSTBUFFER_FREE :187 HPI_ISTREAM_HOSTBUFFER_FREE);188 189 hpi_handle_to_indexes(h_stream, &hm.adapter_index,190 &hm.obj_index);191 hm.u.d.u.buffer.command = HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER;192 hpi_send_recv(&hm, &hr);193 return hr.error;194}195 196static inline u16 hpi_stream_start(u32 h_stream)197{198 if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)199 return hpi_outstream_start(h_stream);200 else201 return hpi_instream_start(h_stream);202}203 204static inline u16 hpi_stream_stop(u32 h_stream)205{206 if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)207 return hpi_outstream_stop(h_stream);208 else209 return hpi_instream_stop(h_stream);210}211 212static inline u16 hpi_stream_get_info_ex(213 u32 h_stream,214 u16 *pw_state,215 u32 *pbuffer_size,216 u32 *pdata_in_buffer,217 u32 *psample_count,218 u32 *pauxiliary_data219)220{221 u16 e;222 if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)223 e = hpi_outstream_get_info_ex(h_stream, pw_state,224 pbuffer_size, pdata_in_buffer,225 psample_count, pauxiliary_data);226 else227 e = hpi_instream_get_info_ex(h_stream, pw_state,228 pbuffer_size, pdata_in_buffer,229 psample_count, pauxiliary_data);230 return e;231}232 233static inline u16 hpi_stream_group_add(234 u32 h_master,235 u32 h_stream)236{237 if (hpi_handle_object(h_master) == HPI_OBJ_OSTREAM)238 return hpi_outstream_group_add(h_master, h_stream);239 else240 return hpi_instream_group_add(h_master, h_stream);241}242 243static inline u16 hpi_stream_group_reset(u32 h_stream)244{245 if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)246 return hpi_outstream_group_reset(h_stream);247 else248 return hpi_instream_group_reset(h_stream);249}250 251static u16 handle_error(u16 err, int line, char *filename)252{253 if (err)254 pr_warn("in file %s, line %d: HPI error %d\n",255 filename, line, err);256 return err;257}258 259#define hpi_handle_error(x) handle_error(x, __LINE__, __FILE__)260 261/***************************** GENERAL PCM ****************/262 263static void print_hwparams(struct snd_pcm_substream *substream,264 struct snd_pcm_hw_params *p)265{266 struct device *dev = substream->pcm->card->dev;267 char name[16];268 269 snd_pcm_debug_name(substream, name, sizeof(name));270 dev_dbg(dev, "%s HWPARAMS\n", name);271 dev_dbg(dev, " samplerate=%dHz channels=%d format=%d subformat=%d\n",272 params_rate(p), params_channels(p),273 params_format(p), params_subformat(p));274 dev_dbg(dev, " buffer=%dB period=%dB period_size=%dB periods=%d\n",275 params_buffer_bytes(p), params_period_bytes(p),276 params_period_size(p), params_periods(p));277 dev_dbg(dev, " buffer_size=%d access=%d data_rate=%dB/s\n",278 params_buffer_size(p), params_access(p),279 params_rate(p) * params_channels(p) *280 snd_pcm_format_width(params_format(p)) / 8);281}282 283#define INVALID_FORMAT (__force snd_pcm_format_t)(-1)284 285static const snd_pcm_format_t hpi_to_alsa_formats[] = {286 INVALID_FORMAT, /* INVALID */287 SNDRV_PCM_FORMAT_U8, /* HPI_FORMAT_PCM8_UNSIGNED 1 */288 SNDRV_PCM_FORMAT_S16, /* HPI_FORMAT_PCM16_SIGNED 2 */289 INVALID_FORMAT, /* HPI_FORMAT_MPEG_L1 3 */290 SNDRV_PCM_FORMAT_MPEG, /* HPI_FORMAT_MPEG_L2 4 */291 SNDRV_PCM_FORMAT_MPEG, /* HPI_FORMAT_MPEG_L3 5 */292 INVALID_FORMAT, /* HPI_FORMAT_DOLBY_AC2 6 */293 INVALID_FORMAT, /* HPI_FORMAT_DOLBY_AC3 7 */294 SNDRV_PCM_FORMAT_S16_BE,/* HPI_FORMAT_PCM16_BIGENDIAN 8 */295 INVALID_FORMAT, /* HPI_FORMAT_AA_TAGIT1_HITS 9 */296 INVALID_FORMAT, /* HPI_FORMAT_AA_TAGIT1_INSERTS 10 */297 SNDRV_PCM_FORMAT_S32, /* HPI_FORMAT_PCM32_SIGNED 11 */298 INVALID_FORMAT, /* HPI_FORMAT_RAW_BITSTREAM 12 */299 INVALID_FORMAT, /* HPI_FORMAT_AA_TAGIT1_HITS_EX1 13 */300 SNDRV_PCM_FORMAT_FLOAT, /* HPI_FORMAT_PCM32_FLOAT 14 */301#if 1302 /* ALSA can't handle 3 byte sample size together with power-of-2303 * constraint on buffer_bytes, so disable this format304 */305 INVALID_FORMAT306#else307 /* SNDRV_PCM_FORMAT_S24_3LE */ /* HPI_FORMAT_PCM24_SIGNED 15 */308#endif309};310 311 312static int snd_card_asihpi_format_alsa2hpi(struct snd_card_asihpi *asihpi,313 snd_pcm_format_t alsa_format,314 u16 *hpi_format)315{316 u16 format;317 318 for (format = HPI_FORMAT_PCM8_UNSIGNED;319 format <= HPI_FORMAT_PCM24_SIGNED; format++) {320 if (hpi_to_alsa_formats[format] == alsa_format) {321 *hpi_format = format;322 return 0;323 }324 }325 326 dev_dbg(asihpi->card->dev, "failed match for alsa format %d\n",327 alsa_format);328 *hpi_format = 0;329 return -EINVAL;330}331 332static void snd_card_asihpi_pcm_samplerates(struct snd_card_asihpi *asihpi,333 struct snd_pcm_hardware *pcmhw)334{335 u16 err;336 u32 h_control;337 u32 sample_rate;338 int idx;339 unsigned int rate_min = 200000;340 unsigned int rate_max = 0;341 unsigned int rates = 0;342 343 if (asihpi->support_mrx) {344 rates |= SNDRV_PCM_RATE_CONTINUOUS;345 rates |= SNDRV_PCM_RATE_8000_96000;346 rate_min = 8000;347 rate_max = 100000;348 } else {349 /* on cards without SRC,350 valid rates are determined by sampleclock */351 err = hpi_mixer_get_control(asihpi->h_mixer,352 HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,353 HPI_CONTROL_SAMPLECLOCK, &h_control);354 if (err) {355 dev_err(&asihpi->pci->dev,356 "No local sampleclock, err %d\n", err);357 }358 359 for (idx = -1; idx < 100; idx++) {360 if (idx == -1) {361 if (hpi_sample_clock_get_sample_rate(h_control,362 &sample_rate))363 continue;364 } else if (hpi_sample_clock_query_local_rate(h_control,365 idx, &sample_rate)) {366 break;367 }368 369 rate_min = min(rate_min, sample_rate);370 rate_max = max(rate_max, sample_rate);371 372 switch (sample_rate) {373 case 5512:374 rates |= SNDRV_PCM_RATE_5512;375 break;376 case 8000:377 rates |= SNDRV_PCM_RATE_8000;378 break;379 case 11025:380 rates |= SNDRV_PCM_RATE_11025;381 break;382 case 16000:383 rates |= SNDRV_PCM_RATE_16000;384 break;385 case 22050:386 rates |= SNDRV_PCM_RATE_22050;387 break;388 case 32000:389 rates |= SNDRV_PCM_RATE_32000;390 break;391 case 44100:392 rates |= SNDRV_PCM_RATE_44100;393 break;394 case 48000:395 rates |= SNDRV_PCM_RATE_48000;396 break;397 case 64000:398 rates |= SNDRV_PCM_RATE_64000;399 break;400 case 88200:401 rates |= SNDRV_PCM_RATE_88200;402 break;403 case 96000:404 rates |= SNDRV_PCM_RATE_96000;405 break;406 case 176400:407 rates |= SNDRV_PCM_RATE_176400;408 break;409 case 192000:410 rates |= SNDRV_PCM_RATE_192000;411 break;412 default: /* some other rate */413 rates |= SNDRV_PCM_RATE_KNOT;414 }415 }416 }417 418 pcmhw->rates = rates;419 pcmhw->rate_min = rate_min;420 pcmhw->rate_max = rate_max;421}422 423static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,424 struct snd_pcm_hw_params *params)425{426 struct snd_pcm_runtime *runtime = substream->runtime;427 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;428 struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);429 int err;430 u16 format;431 int width;432 unsigned int bytes_per_sec;433 434 print_hwparams(substream, params);435 err = snd_card_asihpi_format_alsa2hpi(card, params_format(params), &format);436 if (err)437 return err;438 439 hpi_handle_error(hpi_format_create(&dpcm->format,440 params_channels(params),441 format, params_rate(params), 0, 0));442 443 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {444 if (hpi_instream_reset(dpcm->h_stream) != 0)445 return -EINVAL;446 447 if (hpi_instream_set_format(448 dpcm->h_stream, &dpcm->format) != 0)449 return -EINVAL;450 }451 452 dpcm->hpi_buffer_attached = 0;453 if (card->can_dma) {454 err = hpi_stream_host_buffer_attach(dpcm->h_stream,455 params_buffer_bytes(params), runtime->dma_addr);456 if (err == 0) {457 dev_dbg(card->card->dev,458 "stream_host_buffer_attach success %u %lu\n",459 params_buffer_bytes(params),460 (unsigned long)runtime->dma_addr);461 } else {462 dev_dbg(card->card->dev,463 "stream_host_buffer_attach error %d\n", err);464 return -ENOMEM;465 }466 467 err = hpi_stream_get_info_ex(dpcm->h_stream, NULL,468 &dpcm->hpi_buffer_attached, NULL, NULL, NULL);469 }470 bytes_per_sec = params_rate(params) * params_channels(params);471 width = snd_pcm_format_width(params_format(params));472 bytes_per_sec *= width;473 bytes_per_sec /= 8;474 if (width < 0 || bytes_per_sec == 0)475 return -EINVAL;476 477 dpcm->bytes_per_sec = bytes_per_sec;478 dpcm->buffer_bytes = params_buffer_bytes(params);479 dpcm->period_bytes = params_period_bytes(params);480 481 return 0;482}483 484static int485snd_card_asihpi_hw_free(struct snd_pcm_substream *substream)486{487 struct snd_pcm_runtime *runtime = substream->runtime;488 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;489 if (dpcm->hpi_buffer_attached)490 hpi_stream_host_buffer_detach(dpcm->h_stream);491 492 return 0;493}494 495static void snd_card_asihpi_runtime_free(struct snd_pcm_runtime *runtime)496{497 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;498 kfree(dpcm);499}500 501static void snd_card_asihpi_pcm_timer_start(struct snd_pcm_substream *502 substream)503{504 struct snd_pcm_runtime *runtime = substream->runtime;505 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;506 int expiry;507 508 expiry = HZ / 200;509 510 expiry = max(expiry, 1); /* don't let it be zero! */511 mod_timer(&dpcm->timer, jiffies + expiry);512 dpcm->respawn_timer = 1;513}514 515static void snd_card_asihpi_pcm_timer_stop(struct snd_pcm_substream *substream)516{517 struct snd_pcm_runtime *runtime = substream->runtime;518 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;519 520 dpcm->respawn_timer = 0;521 del_timer(&dpcm->timer);522}523 524static void snd_card_asihpi_pcm_int_start(struct snd_pcm_substream *substream)525{526 struct snd_card_asihpi_pcm *dpcm;527 struct snd_card_asihpi *card;528 529 dpcm = (struct snd_card_asihpi_pcm *)substream->runtime->private_data;530 card = snd_pcm_substream_chip(substream);531 532 WARN_ON(in_interrupt());533 card->llmode_streampriv = dpcm;534 535 hpi_handle_error(hpi_adapter_set_property(card->hpi->adapter->index,536 HPI_ADAPTER_PROPERTY_IRQ_RATE,537 card->update_interval_frames, 0));538}539 540static void snd_card_asihpi_pcm_int_stop(struct snd_pcm_substream *substream)541{542 struct snd_card_asihpi *card;543 544 card = snd_pcm_substream_chip(substream);545 546 hpi_handle_error(hpi_adapter_set_property(card->hpi->adapter->index,547 HPI_ADAPTER_PROPERTY_IRQ_RATE, 0, 0));548 549 card->llmode_streampriv = NULL;550}551 552static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,553 int cmd)554{555 struct snd_card_asihpi_pcm *dpcm = substream->runtime->private_data;556 struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);557 struct snd_pcm_substream *s;558 u16 e;559 char name[16];560 561 snd_pcm_debug_name(substream, name, sizeof(name));562 563 switch (cmd) {564 case SNDRV_PCM_TRIGGER_START:565 dev_dbg(card->card->dev, "%s trigger start\n", name);566 snd_pcm_group_for_each_entry(s, substream) {567 struct snd_pcm_runtime *runtime = s->runtime;568 struct snd_card_asihpi_pcm *ds = runtime->private_data;569 570 if (snd_pcm_substream_chip(s) != card)571 continue;572 573 /* don't link Cap and Play */574 if (substream->stream != s->stream)575 continue;576 577 ds->drained_count = 0;578 if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {579 /* How do I know how much valid data is present580 * in buffer? Must be at least one period!581 * Guessing 2 periods, but if582 * buffer is bigger it may contain even more583 * data??584 */585 unsigned int preload = ds->period_bytes * 1;586 asihpi_dbg("%d preload %d\n", s->number, preload);587 hpi_handle_error(hpi_outstream_write_buf(588 ds->h_stream,589 &runtime->dma_area[0],590 preload,591 &ds->format));592 ds->pcm_buf_host_rw_ofs = preload;593 }594 595 if (card->support_grouping) {596 dev_dbg(card->card->dev, "%d group\n", s->number);597 e = hpi_stream_group_add(598 dpcm->h_stream,599 ds->h_stream);600 if (!e) {601 snd_pcm_trigger_done(s, substream);602 } else {603 hpi_handle_error(e);604 break;605 }606 } else607 break;608 }609 /* start the master stream */610 card->pcm_start(substream);611 if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ||612 !card->can_dma)613 hpi_handle_error(hpi_stream_start(dpcm->h_stream));614 break;615 616 case SNDRV_PCM_TRIGGER_STOP:617 dev_dbg(card->card->dev, "%s trigger stop\n", name);618 card->pcm_stop(substream);619 snd_pcm_group_for_each_entry(s, substream) {620 if (snd_pcm_substream_chip(s) != card)621 continue;622 /* don't link Cap and Play */623 if (substream->stream != s->stream)624 continue;625 626 /*? workaround linked streams don't627 transition to SETUP 20070706*/628 __snd_pcm_set_state(s->runtime, SNDRV_PCM_STATE_SETUP);629 630 if (card->support_grouping) {631 dev_dbg(card->card->dev, "%d group\n", s->number);632 snd_pcm_trigger_done(s, substream);633 } else634 break;635 }636 637 /* _prepare and _hwparams reset the stream */638 hpi_handle_error(hpi_stream_stop(dpcm->h_stream));639 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)640 hpi_handle_error(641 hpi_outstream_reset(dpcm->h_stream));642 643 if (card->support_grouping)644 hpi_handle_error(hpi_stream_group_reset(dpcm->h_stream));645 break;646 647 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:648 dev_dbg(card->card->dev, "%s trigger pause release\n", name);649 card->pcm_start(substream);650 hpi_handle_error(hpi_stream_start(dpcm->h_stream));651 break;652 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:653 dev_dbg(card->card->dev, "%s trigger pause push\n", name);654 card->pcm_stop(substream);655 hpi_handle_error(hpi_stream_stop(dpcm->h_stream));656 break;657 default:658 dev_dbg(card->card->dev, "\tINVALID\n");659 return -EINVAL;660 }661 662 return 0;663}664 665/*algorithm outline666 Without linking degenerates to getting single stream pos etc667 Without mmap 2nd loop degenerates to snd_pcm_period_elapsed668*/669/*670pcm_buf_dma_ofs=get_buf_pos(s);671for_each_linked_stream(s) {672 pcm_buf_dma_ofs=get_buf_pos(s);673 min_buf_pos = modulo_min(min_buf_pos, pcm_buf_dma_ofs, buffer_bytes)674 new_data = min(new_data, calc_new_data(pcm_buf_dma_ofs,irq_pos)675}676timer.expires = jiffies + predict_next_period_ready(min_buf_pos);677for_each_linked_stream(s) {678 s->pcm_buf_dma_ofs = min_buf_pos;679 if (new_data > period_bytes) {680 if (mmap) {681 irq_pos = (irq_pos + period_bytes) % buffer_bytes;682 if (playback) {683 write(period_bytes);684 } else {685 read(period_bytes);686 }687 }688 snd_pcm_period_elapsed(s);689 }690}691*/692 693/** Minimum of 2 modulo values. Works correctly when the difference between694* the values is less than half the modulus695*/696static inline unsigned int modulo_min(unsigned int a, unsigned int b,697 unsigned long int modulus)698{699 unsigned int result;700 if (((a-b) % modulus) < (modulus/2))701 result = b;702 else703 result = a;704 705 return result;706}707 708/** Timer function, equivalent to interrupt service routine for cards709*/710static void snd_card_asihpi_timer_function(struct timer_list *t)711{712 struct snd_card_asihpi_pcm *dpcm = from_timer(dpcm, t, timer);713 struct snd_pcm_substream *substream = dpcm->substream;714 struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);715 struct snd_pcm_runtime *runtime;716 struct snd_pcm_substream *s;717 unsigned int newdata = 0;718 unsigned int pcm_buf_dma_ofs, min_buf_pos = 0;719 unsigned int remdata, xfercount, next_jiffies;720 int first = 1;721 u16 state;722 u32 buffer_size, bytes_avail, samples_played, on_card_bytes;723 char name[16];724 725 726 snd_pcm_debug_name(substream, name, sizeof(name));727 728 /* find minimum newdata and buffer pos in group */729 snd_pcm_group_for_each_entry(s, substream) {730 struct snd_card_asihpi_pcm *ds = s->runtime->private_data;731 runtime = s->runtime;732 733 if (snd_pcm_substream_chip(s) != card)734 continue;735 736 /* don't link Cap and Play */737 if (substream->stream != s->stream)738 continue;739 740 hpi_handle_error(hpi_stream_get_info_ex(741 ds->h_stream, &state,742 &buffer_size, &bytes_avail,743 &samples_played, &on_card_bytes));744 745 /* number of bytes in on-card buffer */746 runtime->delay = on_card_bytes;747 748 if (!card->can_dma)749 on_card_bytes = bytes_avail;750 751 if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {752 pcm_buf_dma_ofs = ds->pcm_buf_host_rw_ofs - bytes_avail;753 if (state == HPI_STATE_STOPPED) {754 if (bytes_avail == 0) {755 hpi_handle_error(hpi_stream_start(ds->h_stream));756 dev_dbg(card->card->dev,757 "P%d start\n", s->number);758 ds->drained_count = 0;759 }760 } else if (state == HPI_STATE_DRAINED) {761 dev_dbg(card->card->dev,762 "P%d drained\n", s->number);763 ds->drained_count++;764 if (ds->drained_count > 20) {765 snd_pcm_stop_xrun(s);766 continue;767 }768 } else {769 ds->drained_count = 0;770 }771 } else772 pcm_buf_dma_ofs = bytes_avail + ds->pcm_buf_host_rw_ofs;773 774 if (first) {775 /* can't statically init min when wrap is involved */776 min_buf_pos = pcm_buf_dma_ofs;777 newdata = (pcm_buf_dma_ofs - ds->pcm_buf_elapsed_dma_ofs) % ds->buffer_bytes;778 first = 0;779 } else {780 min_buf_pos =781 modulo_min(min_buf_pos, pcm_buf_dma_ofs, UINT_MAX+1L);782 newdata = min(783 (pcm_buf_dma_ofs - ds->pcm_buf_elapsed_dma_ofs) % ds->buffer_bytes,784 newdata);785 }786 787 asihpi_dbg(788 "timer1, %s, %d, S=%d, elap=%d, rw=%d, dsp=%d, left=%d, aux=%d, space=%d, hw_ptr=%ld, appl_ptr=%ld\n",789 name, s->number, state,790 ds->pcm_buf_elapsed_dma_ofs,791 ds->pcm_buf_host_rw_ofs,792 pcm_buf_dma_ofs,793 (int)bytes_avail,794 795 (int)on_card_bytes,796 buffer_size-bytes_avail,797 (unsigned long)frames_to_bytes(runtime,798 runtime->status->hw_ptr),799 (unsigned long)frames_to_bytes(runtime,800 runtime->control->appl_ptr)801 );802 }803 pcm_buf_dma_ofs = min_buf_pos;804 805 remdata = newdata % dpcm->period_bytes;806 xfercount = newdata - remdata; /* a multiple of period_bytes */807 /* come back when on_card_bytes has decreased enough to allow808 write to happen, or when data has been consumed to make another809 period810 */811 if (xfercount && (on_card_bytes > dpcm->period_bytes))812 next_jiffies = ((on_card_bytes - dpcm->period_bytes) * HZ / dpcm->bytes_per_sec);813 else814 next_jiffies = ((dpcm->period_bytes - remdata) * HZ / dpcm->bytes_per_sec);815 816 next_jiffies = max(next_jiffies, 1U);817 dpcm->timer.expires = jiffies + next_jiffies;818 asihpi_dbg("timer2, jif=%d, buf_pos=%d, newdata=%d, xfer=%d\n",819 next_jiffies, pcm_buf_dma_ofs, newdata, xfercount);820 821 snd_pcm_group_for_each_entry(s, substream) {822 struct snd_card_asihpi_pcm *ds = s->runtime->private_data;823 824 /* don't link Cap and Play */825 if (substream->stream != s->stream)826 continue;827 828 /* Store dma offset for use by pointer callback */829 ds->pcm_buf_dma_ofs = pcm_buf_dma_ofs;830 831 if (xfercount &&832 /* Limit use of on card fifo for playback */833 ((on_card_bytes <= ds->period_bytes) ||834 (s->stream == SNDRV_PCM_STREAM_CAPTURE)))835 836 {837 838 unsigned int buf_ofs = ds->pcm_buf_host_rw_ofs % ds->buffer_bytes;839 unsigned int xfer1, xfer2;840 char *pd = &s->runtime->dma_area[buf_ofs];841 842 if (card->can_dma) { /* buffer wrap is handled at lower level */843 xfer1 = xfercount;844 xfer2 = 0;845 } else {846 xfer1 = min(xfercount, ds->buffer_bytes - buf_ofs);847 xfer2 = xfercount - xfer1;848 }849 850 if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {851 asihpi_dbg("write1, P=%d, xfer=%d, buf_ofs=%d\n",852 s->number, xfer1, buf_ofs);853 hpi_handle_error(854 hpi_outstream_write_buf(855 ds->h_stream, pd, xfer1,856 &ds->format));857 858 if (xfer2) {859 pd = s->runtime->dma_area;860 861 asihpi_dbg("write2, P=%d, xfer=%d, buf_ofs=%d\n",862 s->number,863 xfercount - xfer1, buf_ofs);864 hpi_handle_error(865 hpi_outstream_write_buf(866 ds->h_stream, pd,867 xfercount - xfer1,868 &ds->format));869 }870 } else {871 asihpi_dbg("read1, C=%d, xfer=%d\n",872 s->number, xfer1);873 hpi_handle_error(874 hpi_instream_read_buf(875 ds->h_stream,876 pd, xfer1));877 if (xfer2) {878 pd = s->runtime->dma_area;879 asihpi_dbg("read2, C=%d, xfer=%d\n",880 s->number, xfer2);881 hpi_handle_error(882 hpi_instream_read_buf(883 ds->h_stream,884 pd, xfer2));885 }886 }887 /* ? host_rw_ofs always ahead of elapsed_dma_ofs by preload size? */888 ds->pcm_buf_host_rw_ofs += xfercount;889 ds->pcm_buf_elapsed_dma_ofs += xfercount;890 snd_pcm_period_elapsed(s);891 }892 }893 894 if (!card->hpi->interrupt_mode && dpcm->respawn_timer)895 add_timer(&dpcm->timer);896}897 898static void snd_card_asihpi_isr(struct hpi_adapter *a)899{900 struct snd_card_asihpi *asihpi;901 902 WARN_ON(!a || !a->snd_card || !a->snd_card->private_data);903 asihpi = (struct snd_card_asihpi *)a->snd_card->private_data;904 if (asihpi->llmode_streampriv)905 snd_card_asihpi_timer_function(906 &asihpi->llmode_streampriv->timer);907}908 909/***************************** PLAYBACK OPS ****************/910static int snd_card_asihpi_playback_prepare(struct snd_pcm_substream *911 substream)912{913 struct snd_pcm_runtime *runtime = substream->runtime;914 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;915 916 hpi_handle_error(hpi_outstream_reset(dpcm->h_stream));917 dpcm->pcm_buf_host_rw_ofs = 0;918 dpcm->pcm_buf_dma_ofs = 0;919 dpcm->pcm_buf_elapsed_dma_ofs = 0;920 return 0;921}922 923static snd_pcm_uframes_t924snd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream)925{926 struct snd_pcm_runtime *runtime = substream->runtime;927 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;928 snd_pcm_uframes_t ptr;929 char name[16];930 snd_pcm_debug_name(substream, name, sizeof(name));931 932 ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes);933 asihpi_dbg("%s, pointer=%ld\n", name, (unsigned long)ptr);934 return ptr;935}936 937static u64 snd_card_asihpi_playback_formats(struct snd_card_asihpi *asihpi,938 u32 h_stream)939{940 struct hpi_format hpi_format;941 u16 format;942 u16 err;943 u32 h_control;944 u32 sample_rate = 48000;945 u64 formats = 0;946 947 /* on cards without SRC, must query at valid rate,948 * maybe set by external sync949 */950 err = hpi_mixer_get_control(asihpi->h_mixer,951 HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,952 HPI_CONTROL_SAMPLECLOCK, &h_control);953 954 if (!err)955 err = hpi_sample_clock_get_sample_rate(h_control,956 &sample_rate);957 958 for (format = HPI_FORMAT_PCM8_UNSIGNED;959 format <= HPI_FORMAT_PCM24_SIGNED; format++) {960 err = hpi_format_create(&hpi_format, asihpi->out_max_chans,961 format, sample_rate, 128000, 0);962 if (!err)963 err = hpi_outstream_query_format(h_stream, &hpi_format);964 if (!err && (hpi_to_alsa_formats[format] != INVALID_FORMAT))965 formats |= pcm_format_to_bits(hpi_to_alsa_formats[format]);966 }967 return formats;968}969 970static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)971{972 struct snd_pcm_runtime *runtime = substream->runtime;973 struct snd_card_asihpi_pcm *dpcm;974 struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);975 struct snd_pcm_hardware snd_card_asihpi_playback;976 int err;977 978 dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);979 if (dpcm == NULL)980 return -ENOMEM;981 982 err = hpi_outstream_open(card->hpi->adapter->index,983 substream->number, &dpcm->h_stream);984 hpi_handle_error(err);985 if (err)986 kfree(dpcm);987 if (err == HPI_ERROR_OBJ_ALREADY_OPEN)988 return -EBUSY;989 if (err)990 return -EIO;991 992 /*? also check ASI5000 samplerate source993 If external, only support external rate.994 If internal and other stream playing, can't switch995 */996 997 timer_setup(&dpcm->timer, snd_card_asihpi_timer_function, 0);998 dpcm->substream = substream;999 runtime->private_data = dpcm;1000 runtime->private_free = snd_card_asihpi_runtime_free;1001 1002 memset(&snd_card_asihpi_playback, 0, sizeof(snd_card_asihpi_playback));1003 if (!card->hpi->interrupt_mode) {1004 snd_card_asihpi_playback.buffer_bytes_max = BUFFER_BYTES_MAX;1005 snd_card_asihpi_playback.period_bytes_min = PERIOD_BYTES_MIN;1006 snd_card_asihpi_playback.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;1007 snd_card_asihpi_playback.periods_min = PERIODS_MIN;1008 snd_card_asihpi_playback.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN;1009 } else {1010 size_t pbmin = card->update_interval_frames *1011 card->out_max_chans;1012 snd_card_asihpi_playback.buffer_bytes_max = BUFFER_BYTES_MAX;1013 snd_card_asihpi_playback.period_bytes_min = pbmin;1014 snd_card_asihpi_playback.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;1015 snd_card_asihpi_playback.periods_min = PERIODS_MIN;1016 snd_card_asihpi_playback.periods_max = BUFFER_BYTES_MAX / pbmin;1017 }1018 1019 /* snd_card_asihpi_playback.fifo_size = 0; */1020 snd_card_asihpi_playback.channels_max = card->out_max_chans;1021 snd_card_asihpi_playback.channels_min = card->out_min_chans;1022 snd_card_asihpi_playback.formats =1023 snd_card_asihpi_playback_formats(card, dpcm->h_stream);1024 1025 snd_card_asihpi_pcm_samplerates(card, &snd_card_asihpi_playback);1026 1027 snd_card_asihpi_playback.info = SNDRV_PCM_INFO_INTERLEAVED |1028 SNDRV_PCM_INFO_DOUBLE |1029 SNDRV_PCM_INFO_BATCH |1030 SNDRV_PCM_INFO_BLOCK_TRANSFER |1031 SNDRV_PCM_INFO_PAUSE |1032 SNDRV_PCM_INFO_MMAP |1033 SNDRV_PCM_INFO_MMAP_VALID;1034 1035 if (card->support_grouping) {1036 snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_SYNC_START;1037 snd_pcm_set_sync(substream);1038 }1039 1040 /* struct is copied, so can create initializer dynamically */1041 runtime->hw = snd_card_asihpi_playback;1042 1043 if (card->can_dma)1044 err = snd_pcm_hw_constraint_pow2(runtime, 0,1045 SNDRV_PCM_HW_PARAM_BUFFER_BYTES);1046 if (err < 0)1047 return err;1048 1049 snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,1050 card->update_interval_frames);1051 1052 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,1053 card->update_interval_frames, UINT_MAX);1054 1055 return 0;1056}1057 1058static int snd_card_asihpi_playback_close(struct snd_pcm_substream *substream)1059{1060 struct snd_pcm_runtime *runtime = substream->runtime;1061 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;1062 1063 hpi_handle_error(hpi_outstream_close(dpcm->h_stream));1064 return 0;1065}1066 1067static const struct snd_pcm_ops snd_card_asihpi_playback_mmap_ops = {1068 .open = snd_card_asihpi_playback_open,1069 .close = snd_card_asihpi_playback_close,1070 .hw_params = snd_card_asihpi_pcm_hw_params,1071 .hw_free = snd_card_asihpi_hw_free,1072 .prepare = snd_card_asihpi_playback_prepare,1073 .trigger = snd_card_asihpi_trigger,1074 .pointer = snd_card_asihpi_playback_pointer,1075};1076 1077/***************************** CAPTURE OPS ****************/1078static snd_pcm_uframes_t1079snd_card_asihpi_capture_pointer(struct snd_pcm_substream *substream)1080{1081 struct snd_pcm_runtime *runtime = substream->runtime;1082 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;1083 char name[16];1084 snd_pcm_debug_name(substream, name, sizeof(name));1085 1086 asihpi_dbg("%s, pointer=%d\n", name, dpcm->pcm_buf_dma_ofs);1087 /* NOTE Unlike playback can't use actual samples_played1088 for the capture position, because those samples aren't yet in1089 the local buffer available for reading.1090 */1091 return bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes);1092}1093 1094static int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream)1095{1096 struct snd_pcm_runtime *runtime = substream->runtime;1097 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;1098 1099 hpi_handle_error(hpi_instream_reset(dpcm->h_stream));1100 dpcm->pcm_buf_host_rw_ofs = 0;1101 dpcm->pcm_buf_dma_ofs = 0;1102 dpcm->pcm_buf_elapsed_dma_ofs = 0;1103 1104 return 0;1105}1106 1107static u64 snd_card_asihpi_capture_formats(struct snd_card_asihpi *asihpi,1108 u32 h_stream)1109{1110 struct hpi_format hpi_format;1111 u16 format;1112 u16 err;1113 u32 h_control;1114 u32 sample_rate = 48000;1115 u64 formats = 0;1116 1117 /* on cards without SRC, must query at valid rate,1118 maybe set by external sync */1119 err = hpi_mixer_get_control(asihpi->h_mixer,1120 HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,1121 HPI_CONTROL_SAMPLECLOCK, &h_control);1122 1123 if (!err)1124 err = hpi_sample_clock_get_sample_rate(h_control,1125 &sample_rate);1126 1127 for (format = HPI_FORMAT_PCM8_UNSIGNED;1128 format <= HPI_FORMAT_PCM24_SIGNED; format++) {1129 1130 err = hpi_format_create(&hpi_format, asihpi->in_max_chans,1131 format, sample_rate, 128000, 0);1132 if (!err)1133 err = hpi_instream_query_format(h_stream, &hpi_format);1134 if (!err && (hpi_to_alsa_formats[format] != INVALID_FORMAT))1135 formats |= pcm_format_to_bits(hpi_to_alsa_formats[format]);1136 }1137 return formats;1138}1139 1140static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)1141{1142 struct snd_pcm_runtime *runtime = substream->runtime;1143 struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);1144 struct snd_card_asihpi_pcm *dpcm;1145 struct snd_pcm_hardware snd_card_asihpi_capture;1146 int err;1147 1148 dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);1149 if (dpcm == NULL)1150 return -ENOMEM;1151 1152 1153 dev_dbg(card->card->dev, "capture open adapter %d stream %d\n",1154 card->hpi->adapter->index, substream->number);1155 1156 err = hpi_handle_error(1157 hpi_instream_open(card->hpi->adapter->index,1158 substream->number, &dpcm->h_stream));1159 if (err)1160 kfree(dpcm);1161 if (err == HPI_ERROR_OBJ_ALREADY_OPEN)1162 return -EBUSY;1163 if (err)1164 return -EIO;1165 1166 timer_setup(&dpcm->timer, snd_card_asihpi_timer_function, 0);1167 dpcm->substream = substream;1168 runtime->private_data = dpcm;1169 runtime->private_free = snd_card_asihpi_runtime_free;1170 1171 memset(&snd_card_asihpi_capture, 0, sizeof(snd_card_asihpi_capture));1172 if (!card->hpi->interrupt_mode) {1173 snd_card_asihpi_capture.buffer_bytes_max = BUFFER_BYTES_MAX;1174 snd_card_asihpi_capture.period_bytes_min = PERIOD_BYTES_MIN;1175 snd_card_asihpi_capture.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;1176 snd_card_asihpi_capture.periods_min = PERIODS_MIN;1177 snd_card_asihpi_capture.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN;1178 } else {1179 size_t pbmin = card->update_interval_frames *1180 card->out_max_chans;1181 snd_card_asihpi_capture.buffer_bytes_max = BUFFER_BYTES_MAX;1182 snd_card_asihpi_capture.period_bytes_min = pbmin;1183 snd_card_asihpi_capture.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;1184 snd_card_asihpi_capture.periods_min = PERIODS_MIN;1185 snd_card_asihpi_capture.periods_max = BUFFER_BYTES_MAX / pbmin;1186 }1187 /* snd_card_asihpi_capture.fifo_size = 0; */1188 snd_card_asihpi_capture.channels_max = card->in_max_chans;1189 snd_card_asihpi_capture.channels_min = card->in_min_chans;1190 snd_card_asihpi_capture.formats =1191 snd_card_asihpi_capture_formats(card, dpcm->h_stream);1192 snd_card_asihpi_pcm_samplerates(card, &snd_card_asihpi_capture);1193 snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED |1194 SNDRV_PCM_INFO_MMAP |1195 SNDRV_PCM_INFO_MMAP_VALID;1196 1197 if (card->support_grouping)1198 snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_SYNC_START;1199 1200 runtime->hw = snd_card_asihpi_capture;1201 1202 if (card->can_dma)1203 err = snd_pcm_hw_constraint_pow2(runtime, 0,1204 SNDRV_PCM_HW_PARAM_BUFFER_BYTES);1205 if (err < 0)1206 return err;1207 1208 snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,1209 card->update_interval_frames);1210 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,1211 card->update_interval_frames, UINT_MAX);1212 1213 snd_pcm_set_sync(substream);1214 1215 return 0;1216}1217 1218static int snd_card_asihpi_capture_close(struct snd_pcm_substream *substream)1219{1220 struct snd_card_asihpi_pcm *dpcm = substream->runtime->private_data;1221 1222 hpi_handle_error(hpi_instream_close(dpcm->h_stream));1223 return 0;1224}1225 1226static const struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = {1227 .open = snd_card_asihpi_capture_open,1228 .close = snd_card_asihpi_capture_close,1229 .hw_params = snd_card_asihpi_pcm_hw_params,1230 .hw_free = snd_card_asihpi_hw_free,1231 .prepare = snd_card_asihpi_capture_prepare,1232 .trigger = snd_card_asihpi_trigger,1233 .pointer = snd_card_asihpi_capture_pointer,1234};1235 1236static int snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi, int device)1237{1238 struct snd_pcm *pcm;1239 int err;1240 u16 num_instreams, num_outstreams, x16;1241 u32 x32;1242 1243 err = hpi_adapter_get_info(asihpi->hpi->adapter->index,1244 &num_outstreams, &num_instreams,1245 &x16, &x32, &x16);1246 1247 err = snd_pcm_new(asihpi->card, "Asihpi PCM", device,1248 num_outstreams, num_instreams, &pcm);1249 if (err < 0)1250 return err;1251 1252 /* pointer to ops struct is stored, dont change ops afterwards! */1253 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,1254 &snd_card_asihpi_playback_mmap_ops);1255 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,1256 &snd_card_asihpi_capture_mmap_ops);1257 1258 pcm->private_data = asihpi;1259 pcm->info_flags = 0;1260 strcpy(pcm->name, "Asihpi PCM");1261 1262 /*? do we want to emulate MMAP for non-BBM cards?1263 Jack doesn't work with ALSAs MMAP emulation - WHY NOT? */1264 snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,1265 &asihpi->pci->dev,1266 64*1024, BUFFER_BYTES_MAX);1267 1268 return 0;1269}1270 1271/***************************** MIXER CONTROLS ****************/1272struct hpi_control {1273 u32 h_control;1274 u16 control_type;1275 u16 src_node_type;1276 u16 src_node_index;1277 u16 dst_node_type;1278 u16 dst_node_index;1279 u16 band;1280 char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* copied to snd_ctl_elem_id.name[44]; */1281};1282 1283static const char * const asihpi_tuner_band_names[] = {1284 "invalid",1285 "AM",1286 "FM mono",1287 "TV NTSC-M",1288 "FM stereo",1289 "AUX",1290 "TV PAL BG",1291 "TV PAL I",1292 "TV PAL DK",1293 "TV SECAM",1294 "TV DAB",1295};1296/* Number of strings must match the enumerations for HPI_TUNER_BAND in hpi.h */1297compile_time_assert(1298 (ARRAY_SIZE(asihpi_tuner_band_names) ==1299 (HPI_TUNER_BAND_LAST+1)),1300 assert_tuner_band_names_size);1301 1302static const char * const asihpi_src_names[] = {1303 "no source",1304 "PCM",1305 "Line",1306 "Digital",1307 "Tuner",1308 "RF",1309 "Clock",1310 "Bitstream",1311 "Mic",1312 "Net",1313 "Analog",1314 "Adapter",1315 "RTP",1316 "Internal",1317 "AVB",1318 "BLU-Link"1319};1320/* Number of strings must match the enumerations for HPI_SOURCENODES in hpi.h */1321compile_time_assert(1322 (ARRAY_SIZE(asihpi_src_names) ==1323 (HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_NONE+1)),1324 assert_src_names_size);1325 1326static const char * const asihpi_dst_names[] = {1327 "no destination",1328 "PCM",1329 "Line",1330 "Digital",1331 "RF",1332 "Speaker",1333 "Net",1334 "Analog",1335 "RTP",1336 "AVB",1337 "Internal",1338 "BLU-Link"1339};1340/* Number of strings must match the enumerations for HPI_DESTNODES in hpi.h */1341compile_time_assert(1342 (ARRAY_SIZE(asihpi_dst_names) ==1343 (HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_NONE+1)),1344 assert_dst_names_size);1345 1346static inline int ctl_add(struct snd_card *card, struct snd_kcontrol_new *ctl,1347 struct snd_card_asihpi *asihpi)1348{1349 int err;1350 1351 err = snd_ctl_add(card, snd_ctl_new1(ctl, asihpi));1352 if (err < 0)1353 return err;1354 else if (mixer_dump)1355 dev_info(&asihpi->pci->dev, "added %s(%d)\n", ctl->name, ctl->index);1356 1357 return 0;1358}1359 1360/* Convert HPI control name and location into ALSA control name */1361static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control,1362 struct hpi_control *hpi_ctl,1363 char *name)1364{1365 char *dir;1366 memset(snd_control, 0, sizeof(*snd_control));1367 snd_control->name = hpi_ctl->name;1368 snd_control->private_value = hpi_ctl->h_control;1369 snd_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER;1370 snd_control->index = 0;1371 1372 if (hpi_ctl->src_node_type + HPI_SOURCENODE_NONE == HPI_SOURCENODE_CLOCK_SOURCE)1373 dir = ""; /* clock is neither capture nor playback */1374 else if (hpi_ctl->dst_node_type + HPI_DESTNODE_NONE == HPI_DESTNODE_ISTREAM)1375 dir = "Capture "; /* On or towards a PCM capture destination*/1376 else if ((hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) &&1377 (!hpi_ctl->dst_node_type))1378 dir = "Capture "; /* On a source node that is not PCM playback */1379 else if (hpi_ctl->src_node_type &&1380 (hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) &&1381 (hpi_ctl->dst_node_type))1382 dir = "Monitor Playback "; /* Between an input and an output */1383 else1384 dir = "Playback "; /* PCM Playback source, or output node */1385 1386 if (hpi_ctl->src_node_type && hpi_ctl->dst_node_type)1387 sprintf(hpi_ctl->name, "%s %d %s %d %s%s",1388 asihpi_src_names[hpi_ctl->src_node_type],1389 hpi_ctl->src_node_index,1390 asihpi_dst_names[hpi_ctl->dst_node_type],1391 hpi_ctl->dst_node_index,1392 dir, name);1393 else if (hpi_ctl->dst_node_type) {1394 sprintf(hpi_ctl->name, "%s %d %s%s",1395 asihpi_dst_names[hpi_ctl->dst_node_type],1396 hpi_ctl->dst_node_index,1397 dir, name);1398 } else {1399 sprintf(hpi_ctl->name, "%s %d %s%s",1400 asihpi_src_names[hpi_ctl->src_node_type],1401 hpi_ctl->src_node_index,1402 dir, name);1403 }1404}1405 1406/*------------------------------------------------------------1407 Volume controls1408 ------------------------------------------------------------*/1409#define VOL_STEP_mB 11410static int snd_asihpi_volume_info(struct snd_kcontrol *kcontrol,1411 struct snd_ctl_elem_info *uinfo)1412{1413 u32 h_control = kcontrol->private_value;1414 u32 count;1415 u16 err;1416 /* native gains are in millibels */1417 short min_gain_mB;1418 short max_gain_mB;1419 short step_gain_mB;1420 1421 err = hpi_volume_query_range(h_control,1422 &min_gain_mB, &max_gain_mB, &step_gain_mB);1423 if (err) {1424 max_gain_mB = 0;1425 min_gain_mB = -10000;1426 step_gain_mB = VOL_STEP_mB;1427 }1428 1429 err = hpi_meter_query_channels(h_control, &count);1430 if (err)1431 count = HPI_MAX_CHANNELS;1432 1433 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;1434 uinfo->count = count;1435 uinfo->value.integer.min = min_gain_mB / VOL_STEP_mB;1436 uinfo->value.integer.max = max_gain_mB / VOL_STEP_mB;1437 uinfo->value.integer.step = step_gain_mB / VOL_STEP_mB;1438 return 0;1439}1440 1441static int snd_asihpi_volume_get(struct snd_kcontrol *kcontrol,1442 struct snd_ctl_elem_value *ucontrol)1443{1444 u32 h_control = kcontrol->private_value;1445 short an_gain_mB[HPI_MAX_CHANNELS];1446 1447 hpi_handle_error(hpi_volume_get_gain(h_control, an_gain_mB));1448 ucontrol->value.integer.value[0] = an_gain_mB[0] / VOL_STEP_mB;1449 ucontrol->value.integer.value[1] = an_gain_mB[1] / VOL_STEP_mB;1450 1451 return 0;1452}1453 1454static int snd_asihpi_volume_put(struct snd_kcontrol *kcontrol,1455 struct snd_ctl_elem_value *ucontrol)1456{1457 u32 h_control = kcontrol->private_value;1458 short an_gain_mB[HPI_MAX_CHANNELS];1459 1460 an_gain_mB[0] =1461 (ucontrol->value.integer.value[0]) * VOL_STEP_mB;1462 an_gain_mB[1] =1463 (ucontrol->value.integer.value[1]) * VOL_STEP_mB;1464 /* change = asihpi->mixer_volume[addr][0] != left ||1465 asihpi->mixer_volume[addr][1] != right;1466 */1467 hpi_handle_error(hpi_volume_set_gain(h_control, an_gain_mB));1468 return 1;1469}1470 1471static const DECLARE_TLV_DB_SCALE(db_scale_100, -10000, VOL_STEP_mB, 0);1472 1473#define snd_asihpi_volume_mute_info snd_ctl_boolean_mono_info1474 1475static int snd_asihpi_volume_mute_get(struct snd_kcontrol *kcontrol,1476 struct snd_ctl_elem_value *ucontrol)1477{1478 u32 h_control = kcontrol->private_value;1479 u32 mute;1480 1481 hpi_handle_error(hpi_volume_get_mute(h_control, &mute));1482 ucontrol->value.integer.value[0] = mute ? 0 : 1;1483 1484 return 0;1485}1486 1487static int snd_asihpi_volume_mute_put(struct snd_kcontrol *kcontrol,1488 struct snd_ctl_elem_value *ucontrol)1489{1490 u32 h_control = kcontrol->private_value;1491 /* HPI currently only supports all or none muting of multichannel volume1492 ALSA Switch element has opposite sense to HPI mute: on==unmuted, off=muted1493 */1494 int mute = ucontrol->value.integer.value[0] ? 0 : HPI_BITMASK_ALL_CHANNELS;1495 hpi_handle_error(hpi_volume_set_mute(h_control, mute));1496 return 1;1497}1498 1499static int snd_asihpi_volume_add(struct snd_card_asihpi *asihpi,1500 struct hpi_control *hpi_ctl)1501{1502 struct snd_card *card = asihpi->card;1503 struct snd_kcontrol_new snd_control;1504 int err;1505 u32 mute;1506 1507 asihpi_ctl_init(&snd_control, hpi_ctl, "Volume");1508 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |1509 SNDRV_CTL_ELEM_ACCESS_TLV_READ;1510 snd_control.info = snd_asihpi_volume_info;1511 snd_control.get = snd_asihpi_volume_get;1512 snd_control.put = snd_asihpi_volume_put;1513 snd_control.tlv.p = db_scale_100;1514 1515 err = ctl_add(card, &snd_control, asihpi);1516 if (err)1517 return err;1518 1519 if (hpi_volume_get_mute(hpi_ctl->h_control, &mute) == 0) {1520 asihpi_ctl_init(&snd_control, hpi_ctl, "Switch");1521 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;1522 snd_control.info = snd_asihpi_volume_mute_info;1523 snd_control.get = snd_asihpi_volume_mute_get;1524 snd_control.put = snd_asihpi_volume_mute_put;1525 err = ctl_add(card, &snd_control, asihpi);1526 }1527 return err;1528}1529 1530/*------------------------------------------------------------1531 Level controls1532 ------------------------------------------------------------*/1533static int snd_asihpi_level_info(struct snd_kcontrol *kcontrol,1534 struct snd_ctl_elem_info *uinfo)1535{1536 u32 h_control = kcontrol->private_value;1537 u16 err;1538 short min_gain_mB;1539 short max_gain_mB;1540 short step_gain_mB;1541 1542 err =1543 hpi_level_query_range(h_control, &min_gain_mB,1544 &max_gain_mB, &step_gain_mB);1545 if (err) {1546 max_gain_mB = 2400;1547 min_gain_mB = -1000;1548 step_gain_mB = 100;1549 }1550 1551 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;1552 uinfo->count = 2;1553 uinfo->value.integer.min = min_gain_mB / HPI_UNITS_PER_dB;1554 uinfo->value.integer.max = max_gain_mB / HPI_UNITS_PER_dB;1555 uinfo->value.integer.step = step_gain_mB / HPI_UNITS_PER_dB;1556 return 0;1557}1558 1559static int snd_asihpi_level_get(struct snd_kcontrol *kcontrol,1560 struct snd_ctl_elem_value *ucontrol)1561{1562 u32 h_control = kcontrol->private_value;1563 short an_gain_mB[HPI_MAX_CHANNELS];1564 1565 hpi_handle_error(hpi_level_get_gain(h_control, an_gain_mB));1566 ucontrol->value.integer.value[0] =1567 an_gain_mB[0] / HPI_UNITS_PER_dB;1568 ucontrol->value.integer.value[1] =1569 an_gain_mB[1] / HPI_UNITS_PER_dB;1570 1571 return 0;1572}1573 1574static int snd_asihpi_level_put(struct snd_kcontrol *kcontrol,1575 struct snd_ctl_elem_value *ucontrol)1576{1577 int change;1578 u32 h_control = kcontrol->private_value;1579 short an_gain_mB[HPI_MAX_CHANNELS];1580 1581 an_gain_mB[0] =1582 (ucontrol->value.integer.value[0]) * HPI_UNITS_PER_dB;1583 an_gain_mB[1] =1584 (ucontrol->value.integer.value[1]) * HPI_UNITS_PER_dB;1585 /* change = asihpi->mixer_level[addr][0] != left ||1586 asihpi->mixer_level[addr][1] != right;1587 */1588 change = 1;1589 hpi_handle_error(hpi_level_set_gain(h_control, an_gain_mB));1590 return change;1591}1592 1593static const DECLARE_TLV_DB_SCALE(db_scale_level, -1000, 100, 0);1594 1595static int snd_asihpi_level_add(struct snd_card_asihpi *asihpi,1596 struct hpi_control *hpi_ctl)1597{1598 struct snd_card *card = asihpi->card;1599 struct snd_kcontrol_new snd_control;1600 1601 /* can't use 'volume' cos some nodes have volume as well */1602 asihpi_ctl_init(&snd_control, hpi_ctl, "Level");1603 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |1604 SNDRV_CTL_ELEM_ACCESS_TLV_READ;1605 snd_control.info = snd_asihpi_level_info;1606 snd_control.get = snd_asihpi_level_get;1607 snd_control.put = snd_asihpi_level_put;1608 snd_control.tlv.p = db_scale_level;1609 1610 return ctl_add(card, &snd_control, asihpi);1611}1612 1613/*------------------------------------------------------------1614 AESEBU controls1615 ------------------------------------------------------------*/1616 1617/* AESEBU format */1618static const char * const asihpi_aesebu_format_names[] = {1619 "N/A", "S/PDIF", "AES/EBU" };1620 1621static int snd_asihpi_aesebu_format_info(struct snd_kcontrol *kcontrol,1622 struct snd_ctl_elem_info *uinfo)1623{1624 return snd_ctl_enum_info(uinfo, 1, 3, asihpi_aesebu_format_names);1625}1626 1627static int snd_asihpi_aesebu_format_get(struct snd_kcontrol *kcontrol,1628 struct snd_ctl_elem_value *ucontrol,1629 u16 (*func)(u32, u16 *))1630{1631 u32 h_control = kcontrol->private_value;1632 u16 source, err;1633 1634 err = func(h_control, &source);1635 1636 /* default to N/A */1637 ucontrol->value.enumerated.item[0] = 0;1638 /* return success but set the control to N/A */1639 if (err)1640 return 0;1641 if (source == HPI_AESEBU_FORMAT_SPDIF)1642 ucontrol->value.enumerated.item[0] = 1;1643 if (source == HPI_AESEBU_FORMAT_AESEBU)1644 ucontrol->value.enumerated.item[0] = 2;1645 1646 return 0;1647}1648 1649static int snd_asihpi_aesebu_format_put(struct snd_kcontrol *kcontrol,1650 struct snd_ctl_elem_value *ucontrol,1651 u16 (*func)(u32, u16))1652{1653 u32 h_control = kcontrol->private_value;1654 1655 /* default to S/PDIF */1656 u16 source = HPI_AESEBU_FORMAT_SPDIF;1657 1658 if (ucontrol->value.enumerated.item[0] == 1)1659 source = HPI_AESEBU_FORMAT_SPDIF;1660 if (ucontrol->value.enumerated.item[0] == 2)1661 source = HPI_AESEBU_FORMAT_AESEBU;1662 1663 if (func(h_control, source) != 0)1664 return -EINVAL;1665 1666 return 1;1667}1668 1669static int snd_asihpi_aesebu_rx_format_get(struct snd_kcontrol *kcontrol,1670 struct snd_ctl_elem_value *ucontrol) {1671 return snd_asihpi_aesebu_format_get(kcontrol, ucontrol,1672 hpi_aesebu_receiver_get_format);1673}1674 1675static int snd_asihpi_aesebu_rx_format_put(struct snd_kcontrol *kcontrol,1676 struct snd_ctl_elem_value *ucontrol) {1677 return snd_asihpi_aesebu_format_put(kcontrol, ucontrol,1678 hpi_aesebu_receiver_set_format);1679}1680 1681static int snd_asihpi_aesebu_rxstatus_info(struct snd_kcontrol *kcontrol,1682 struct snd_ctl_elem_info *uinfo)1683{1684 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;1685 uinfo->count = 1;1686 1687 uinfo->value.integer.min = 0;1688 uinfo->value.integer.max = 0X1F;1689 uinfo->value.integer.step = 1;1690 1691 return 0;1692}1693 1694static int snd_asihpi_aesebu_rxstatus_get(struct snd_kcontrol *kcontrol,1695 struct snd_ctl_elem_value *ucontrol) {1696 1697 u32 h_control = kcontrol->private_value;1698 u16 status;1699 1700 hpi_handle_error(hpi_aesebu_receiver_get_error_status(1701 h_control, &status));1702 ucontrol->value.integer.value[0] = status;1703 return 0;1704}1705 1706static int snd_asihpi_aesebu_rx_add(struct snd_card_asihpi *asihpi,1707 struct hpi_control *hpi_ctl)1708{1709 struct snd_card *card = asihpi->card;1710 struct snd_kcontrol_new snd_control;1711 1712 asihpi_ctl_init(&snd_control, hpi_ctl, "Format");1713 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;1714 snd_control.info = snd_asihpi_aesebu_format_info;1715 snd_control.get = snd_asihpi_aesebu_rx_format_get;1716 snd_control.put = snd_asihpi_aesebu_rx_format_put;1717 1718 1719 if (ctl_add(card, &snd_control, asihpi) < 0)1720 return -EINVAL;1721 1722 asihpi_ctl_init(&snd_control, hpi_ctl, "Status");1723 snd_control.access =1724 SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;1725 snd_control.info = snd_asihpi_aesebu_rxstatus_info;1726 snd_control.get = snd_asihpi_aesebu_rxstatus_get;1727 1728 return ctl_add(card, &snd_control, asihpi);1729}1730 1731static int snd_asihpi_aesebu_tx_format_get(struct snd_kcontrol *kcontrol,1732 struct snd_ctl_elem_value *ucontrol) {1733 return snd_asihpi_aesebu_format_get(kcontrol, ucontrol,1734 hpi_aesebu_transmitter_get_format);1735}1736 1737static int snd_asihpi_aesebu_tx_format_put(struct snd_kcontrol *kcontrol,1738 struct snd_ctl_elem_value *ucontrol) {1739 return snd_asihpi_aesebu_format_put(kcontrol, ucontrol,1740 hpi_aesebu_transmitter_set_format);1741}1742 1743 1744static int snd_asihpi_aesebu_tx_add(struct snd_card_asihpi *asihpi,1745 struct hpi_control *hpi_ctl)1746{1747 struct snd_card *card = asihpi->card;1748 struct snd_kcontrol_new snd_control;1749 1750 asihpi_ctl_init(&snd_control, hpi_ctl, "Format");1751 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;1752 snd_control.info = snd_asihpi_aesebu_format_info;1753 snd_control.get = snd_asihpi_aesebu_tx_format_get;1754 snd_control.put = snd_asihpi_aesebu_tx_format_put;1755 1756 return ctl_add(card, &snd_control, asihpi);1757}1758 1759/*------------------------------------------------------------1760 Tuner controls1761 ------------------------------------------------------------*/1762 1763/* Gain */1764 1765static int snd_asihpi_tuner_gain_info(struct snd_kcontrol *kcontrol,1766 struct snd_ctl_elem_info *uinfo)1767{1768 u32 h_control = kcontrol->private_value;1769 u16 err;1770 short idx;1771 u16 gain_range[3];1772 1773 for (idx = 0; idx < 3; idx++) {1774 err = hpi_tuner_query_gain(h_control,1775 idx, &gain_range[idx]);1776 if (err != 0)1777 return err;1778 }1779 1780 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;1781 uinfo->count = 1;1782 uinfo->value.integer.min = ((int)gain_range[0]) / HPI_UNITS_PER_dB;1783 uinfo->value.integer.max = ((int)gain_range[1]) / HPI_UNITS_PER_dB;1784 uinfo->value.integer.step = ((int) gain_range[2]) / HPI_UNITS_PER_dB;1785 return 0;1786}1787 1788static int snd_asihpi_tuner_gain_get(struct snd_kcontrol *kcontrol,1789 struct snd_ctl_elem_value *ucontrol)1790{1791 /*1792 struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);1793 */1794 u32 h_control = kcontrol->private_value;1795 short gain;1796 1797 hpi_handle_error(hpi_tuner_get_gain(h_control, &gain));1798 ucontrol->value.integer.value[0] = gain / HPI_UNITS_PER_dB;1799 1800 return 0;1801}1802 1803static int snd_asihpi_tuner_gain_put(struct snd_kcontrol *kcontrol,1804 struct snd_ctl_elem_value *ucontrol)1805{1806 /*1807 struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);1808 */1809 u32 h_control = kcontrol->private_value;1810 short gain;1811 1812 gain = (ucontrol->value.integer.value[0]) * HPI_UNITS_PER_dB;1813 hpi_handle_error(hpi_tuner_set_gain(h_control, gain));1814 1815 return 1;1816}1817 1818/* Band */1819 1820static int asihpi_tuner_band_query(struct snd_kcontrol *kcontrol,1821 u16 *band_list, u32 len) {1822 u32 h_control = kcontrol->private_value;1823 u16 err = 0;1824 u32 i;1825 1826 for (i = 0; i < len; i++) {1827 err = hpi_tuner_query_band(1828 h_control, i, &band_list[i]);1829 if (err != 0)1830 break;1831 }1832 1833 if (err && (err != HPI_ERROR_INVALID_OBJ_INDEX))1834 return -EIO;1835 1836 return i;1837}1838 1839static int snd_asihpi_tuner_band_info(struct snd_kcontrol *kcontrol,1840 struct snd_ctl_elem_info *uinfo)1841{1842 u16 tuner_bands[HPI_TUNER_BAND_LAST];1843 int num_bands = 0;1844 1845 num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,1846 HPI_TUNER_BAND_LAST);1847 1848 if (num_bands < 0)1849 return num_bands;1850 1851 return snd_ctl_enum_info(uinfo, 1, num_bands, asihpi_tuner_band_names);1852}1853 1854static int snd_asihpi_tuner_band_get(struct snd_kcontrol *kcontrol,1855 struct snd_ctl_elem_value *ucontrol)1856{1857 u32 h_control = kcontrol->private_value;1858 /*1859 struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);1860 */1861 u16 band, idx;1862 u16 tuner_bands[HPI_TUNER_BAND_LAST];1863 __always_unused u32 num_bands;1864 1865 num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,1866 HPI_TUNER_BAND_LAST);1867 1868 hpi_handle_error(hpi_tuner_get_band(h_control, &band));1869 1870 ucontrol->value.enumerated.item[0] = -1;1871 for (idx = 0; idx < HPI_TUNER_BAND_LAST; idx++)1872 if (tuner_bands[idx] == band) {1873 ucontrol->value.enumerated.item[0] = idx;1874 break;1875 }1876 1877 return 0;1878}1879 1880static int snd_asihpi_tuner_band_put(struct snd_kcontrol *kcontrol,1881 struct snd_ctl_elem_value *ucontrol)1882{1883 /*1884 struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);1885 */1886 u32 h_control = kcontrol->private_value;1887 unsigned int idx;1888 u16 band;1889 u16 tuner_bands[HPI_TUNER_BAND_LAST];1890 __always_unused u32 num_bands;1891 1892 num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,1893 HPI_TUNER_BAND_LAST);1894 1895 idx = ucontrol->value.enumerated.item[0];1896 if (idx >= ARRAY_SIZE(tuner_bands))1897 idx = ARRAY_SIZE(tuner_bands) - 1;1898 band = tuner_bands[idx];1899 hpi_handle_error(hpi_tuner_set_band(h_control, band));1900 1901 return 1;1902}1903 1904/* Freq */1905 1906static int snd_asihpi_tuner_freq_info(struct snd_kcontrol *kcontrol,1907 struct snd_ctl_elem_info *uinfo)1908{1909 u32 h_control = kcontrol->private_value;1910 u16 err;1911 u16 tuner_bands[HPI_TUNER_BAND_LAST];1912 u16 num_bands = 0, band_iter, idx;1913 u32 freq_range[3], temp_freq_range[3];1914 1915 num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,1916 HPI_TUNER_BAND_LAST);1917 1918 freq_range[0] = INT_MAX;1919 freq_range[1] = 0;1920 freq_range[2] = INT_MAX;1921 1922 for (band_iter = 0; band_iter < num_bands; band_iter++) {1923 for (idx = 0; idx < 3; idx++) {1924 err = hpi_tuner_query_frequency(h_control,1925 idx, tuner_bands[band_iter],1926 &temp_freq_range[idx]);1927 if (err != 0)1928 return err;1929 }1930 1931 /* skip band with bogus stepping */1932 if (temp_freq_range[2] <= 0)1933 continue;1934 1935 if (temp_freq_range[0] < freq_range[0])1936 freq_range[0] = temp_freq_range[0];1937 if (temp_freq_range[1] > freq_range[1])1938 freq_range[1] = temp_freq_range[1];1939 if (temp_freq_range[2] < freq_range[2])1940 freq_range[2] = temp_freq_range[2];1941 }1942 1943 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;1944 uinfo->count = 1;1945 uinfo->value.integer.min = ((int)freq_range[0]);1946 uinfo->value.integer.max = ((int)freq_range[1]);1947 uinfo->value.integer.step = ((int)freq_range[2]);1948 return 0;1949}1950 1951static int snd_asihpi_tuner_freq_get(struct snd_kcontrol *kcontrol,1952 struct snd_ctl_elem_value *ucontrol)1953{1954 u32 h_control = kcontrol->private_value;1955 u32 freq;1956 1957 hpi_handle_error(hpi_tuner_get_frequency(h_control, &freq));1958 ucontrol->value.integer.value[0] = freq;1959 1960 return 0;1961}1962 1963static int snd_asihpi_tuner_freq_put(struct snd_kcontrol *kcontrol,1964 struct snd_ctl_elem_value *ucontrol)1965{1966 u32 h_control = kcontrol->private_value;1967 u32 freq;1968 1969 freq = ucontrol->value.integer.value[0];1970 hpi_handle_error(hpi_tuner_set_frequency(h_control, freq));1971 1972 return 1;1973}1974 1975/* Tuner control group initializer */1976static int snd_asihpi_tuner_add(struct snd_card_asihpi *asihpi,1977 struct hpi_control *hpi_ctl)1978{1979 struct snd_card *card = asihpi->card;1980 struct snd_kcontrol_new snd_control;1981 1982 snd_control.private_value = hpi_ctl->h_control;1983 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;1984 1985 if (!hpi_tuner_get_gain(hpi_ctl->h_control, NULL)) {1986 asihpi_ctl_init(&snd_control, hpi_ctl, "Gain");1987 snd_control.info = snd_asihpi_tuner_gain_info;1988 snd_control.get = snd_asihpi_tuner_gain_get;1989 snd_control.put = snd_asihpi_tuner_gain_put;1990 1991 if (ctl_add(card, &snd_control, asihpi) < 0)1992 return -EINVAL;1993 }1994 1995 asihpi_ctl_init(&snd_control, hpi_ctl, "Band");1996 snd_control.info = snd_asihpi_tuner_band_info;1997 snd_control.get = snd_asihpi_tuner_band_get;1998 snd_control.put = snd_asihpi_tuner_band_put;1999 2000 if (ctl_add(card, &snd_control, asihpi) < 0)2001 return -EINVAL;2002 2003 asihpi_ctl_init(&snd_control, hpi_ctl, "Freq");2004 snd_control.info = snd_asihpi_tuner_freq_info;2005 snd_control.get = snd_asihpi_tuner_freq_get;2006 snd_control.put = snd_asihpi_tuner_freq_put;2007 2008 return ctl_add(card, &snd_control, asihpi);2009}2010 2011/*------------------------------------------------------------2012 Meter controls2013 ------------------------------------------------------------*/2014static int snd_asihpi_meter_info(struct snd_kcontrol *kcontrol,2015 struct snd_ctl_elem_info *uinfo)2016{2017 u32 h_control = kcontrol->private_value;2018 u32 count;2019 u16 err;2020 err = hpi_meter_query_channels(h_control, &count);2021 if (err)2022 count = HPI_MAX_CHANNELS;2023 2024 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;2025 uinfo->count = count;2026 uinfo->value.integer.min = 0;2027 uinfo->value.integer.max = 0x7FFFFFFF;2028 return 0;2029}2030 2031/* linear values for 10dB steps */2032static const int log2lin[] = {2033 0x7FFFFFFF, /* 0dB */2034 679093956,2035 214748365,2036 67909396,2037 21474837,2038 6790940,2039 2147484, /* -60dB */2040 679094,2041 214748, /* -80 */2042 67909,2043 21475, /* -100 */2044 6791,2045 2147,2046 679,2047 214,2048 68,2049 21,2050 7,2051 22052};2053 2054static int snd_asihpi_meter_get(struct snd_kcontrol *kcontrol,2055 struct snd_ctl_elem_value *ucontrol)2056{2057 u32 h_control = kcontrol->private_value;2058 short an_gain_mB[HPI_MAX_CHANNELS], i;2059 u16 err;2060 2061 err = hpi_meter_get_peak(h_control, an_gain_mB);2062 2063 for (i = 0; i < HPI_MAX_CHANNELS; i++) {2064 if (err) {2065 ucontrol->value.integer.value[i] = 0;2066 } else if (an_gain_mB[i] >= 0) {2067 ucontrol->value.integer.value[i] =2068 an_gain_mB[i] << 16;2069 } else {2070 /* -ve is log value in millibels < -60dB,2071 * convert to (roughly!) linear,2072 */2073 ucontrol->value.integer.value[i] =2074 log2lin[an_gain_mB[i] / -1000];2075 }2076 }2077 return 0;2078}2079 2080static int snd_asihpi_meter_add(struct snd_card_asihpi *asihpi,2081 struct hpi_control *hpi_ctl, int subidx)2082{2083 struct snd_card *card = asihpi->card;2084 struct snd_kcontrol_new snd_control;2085 2086 asihpi_ctl_init(&snd_control, hpi_ctl, "Meter");2087 snd_control.access =2088 SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;2089 snd_control.info = snd_asihpi_meter_info;2090 snd_control.get = snd_asihpi_meter_get;2091 2092 snd_control.index = subidx;2093 2094 return ctl_add(card, &snd_control, asihpi);2095}2096 2097/*------------------------------------------------------------2098 Multiplexer controls2099 ------------------------------------------------------------*/2100static int snd_card_asihpi_mux_count_sources(struct snd_kcontrol *snd_control)2101{2102 u32 h_control = snd_control->private_value;2103 struct hpi_control hpi_ctl;2104 int s, err;2105 for (s = 0; s < 32; s++) {2106 err = hpi_multiplexer_query_source(h_control, s,2107 &hpi_ctl.2108 src_node_type,2109 &hpi_ctl.2110 src_node_index);2111 if (err)2112 break;2113 }2114 return s;2115}2116 2117static int snd_asihpi_mux_info(struct snd_kcontrol *kcontrol,2118 struct snd_ctl_elem_info *uinfo)2119{2120 u16 src_node_type, src_node_index;2121 u32 h_control = kcontrol->private_value;2122 2123 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;2124 uinfo->count = 1;2125 uinfo->value.enumerated.items =2126 snd_card_asihpi_mux_count_sources(kcontrol);2127 2128 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)2129 uinfo->value.enumerated.item =2130 uinfo->value.enumerated.items - 1;2131 2132 hpi_multiplexer_query_source(h_control,2133 uinfo->value.enumerated.item,2134 &src_node_type, &src_node_index);2135 2136 sprintf(uinfo->value.enumerated.name, "%s %d",2137 asihpi_src_names[src_node_type - HPI_SOURCENODE_NONE],2138 src_node_index);2139 return 0;2140}2141 2142static int snd_asihpi_mux_get(struct snd_kcontrol *kcontrol,2143 struct snd_ctl_elem_value *ucontrol)2144{2145 u32 h_control = kcontrol->private_value;2146 u16 source_type, source_index;2147 u16 src_node_type, src_node_index;2148 int s;2149 2150 hpi_handle_error(hpi_multiplexer_get_source(h_control,2151 &source_type, &source_index));2152 /* Should cache this search result! */2153 for (s = 0; s < 256; s++) {2154 if (hpi_multiplexer_query_source(h_control, s,2155 &src_node_type, &src_node_index))2156 break;2157 2158 if ((source_type == src_node_type)2159 && (source_index == src_node_index)) {2160 ucontrol->value.enumerated.item[0] = s;2161 return 0;2162 }2163 }2164 pr_warn("%s: Control %x failed to match mux source %hu %hu\n",2165 __func__, h_control, source_type, source_index);2166 ucontrol->value.enumerated.item[0] = 0;2167 return 0;2168}2169 2170static int snd_asihpi_mux_put(struct snd_kcontrol *kcontrol,2171 struct snd_ctl_elem_value *ucontrol)2172{2173 int change;2174 u32 h_control = kcontrol->private_value;2175 u16 source_type, source_index;2176 u16 e;2177 2178 change = 1;2179 2180 e = hpi_multiplexer_query_source(h_control,2181 ucontrol->value.enumerated.item[0],2182 &source_type, &source_index);2183 if (!e)2184 hpi_handle_error(2185 hpi_multiplexer_set_source(h_control,2186 source_type, source_index));2187 return change;2188}2189 2190 2191static int snd_asihpi_mux_add(struct snd_card_asihpi *asihpi,2192 struct hpi_control *hpi_ctl)2193{2194 struct snd_card *card = asihpi->card;2195 struct snd_kcontrol_new snd_control;2196 2197 asihpi_ctl_init(&snd_control, hpi_ctl, "Route");2198 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;2199 snd_control.info = snd_asihpi_mux_info;2200 snd_control.get = snd_asihpi_mux_get;2201 snd_control.put = snd_asihpi_mux_put;2202 2203 return ctl_add(card, &snd_control, asihpi);2204 2205}2206 2207/*------------------------------------------------------------2208 Channel mode controls2209 ------------------------------------------------------------*/2210static int snd_asihpi_cmode_info(struct snd_kcontrol *kcontrol,2211 struct snd_ctl_elem_info *uinfo)2212{2213 static const char * const mode_names[HPI_CHANNEL_MODE_LAST + 1] = {2214 "invalid",2215 "Normal", "Swap",2216 "From Left", "From Right",2217 "To Left", "To Right"2218 };2219 2220 u32 h_control = kcontrol->private_value;2221 u16 mode;2222 int i;2223 const char *mapped_names[6];2224 int valid_modes = 0;2225 2226 /* HPI channel mode values can be from 1 to 62227 Some adapters only support a contiguous subset2228 */2229 for (i = 0; i < HPI_CHANNEL_MODE_LAST; i++)2230 if (!hpi_channel_mode_query_mode(2231 h_control, i, &mode)) {2232 mapped_names[valid_modes] = mode_names[mode];2233 valid_modes++;2234 }2235 2236 if (!valid_modes)2237 return -EINVAL;2238 2239 return snd_ctl_enum_info(uinfo, 1, valid_modes, mapped_names);2240}2241 2242static int snd_asihpi_cmode_get(struct snd_kcontrol *kcontrol,2243 struct snd_ctl_elem_value *ucontrol)2244{2245 u32 h_control = kcontrol->private_value;2246 u16 mode;2247 2248 if (hpi_channel_mode_get(h_control, &mode))2249 mode = 1;2250 2251 ucontrol->value.enumerated.item[0] = mode - 1;2252 2253 return 0;2254}2255 2256static int snd_asihpi_cmode_put(struct snd_kcontrol *kcontrol,2257 struct snd_ctl_elem_value *ucontrol)2258{2259 int change;2260 u32 h_control = kcontrol->private_value;2261 2262 change = 1;2263 2264 hpi_handle_error(hpi_channel_mode_set(h_control,2265 ucontrol->value.enumerated.item[0] + 1));2266 return change;2267}2268 2269 2270static int snd_asihpi_cmode_add(struct snd_card_asihpi *asihpi,2271 struct hpi_control *hpi_ctl)2272{2273 struct snd_card *card = asihpi->card;2274 struct snd_kcontrol_new snd_control;2275 2276 asihpi_ctl_init(&snd_control, hpi_ctl, "Mode");2277 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;2278 snd_control.info = snd_asihpi_cmode_info;2279 snd_control.get = snd_asihpi_cmode_get;2280 snd_control.put = snd_asihpi_cmode_put;2281 2282 return ctl_add(card, &snd_control, asihpi);2283}2284 2285/*------------------------------------------------------------2286 Sampleclock source controls2287 ------------------------------------------------------------*/2288static const char * const sampleclock_sources[] = {2289 "N/A", "Local PLL", "Digital Sync", "Word External", "Word Header",2290 "SMPTE", "Digital1", "Auto", "Network", "Invalid",2291 "Prev Module", "BLU-Link",2292 "Digital2", "Digital3", "Digital4", "Digital5",2293 "Digital6", "Digital7", "Digital8"};2294 2295 /* Number of strings must match expected enumerated values */2296 compile_time_assert(2297 (ARRAY_SIZE(sampleclock_sources) == MAX_CLOCKSOURCES),2298 assert_sampleclock_sources_size);2299 2300static int snd_asihpi_clksrc_info(struct snd_kcontrol *kcontrol,2301 struct snd_ctl_elem_info *uinfo)2302{2303 struct snd_card_asihpi *asihpi =2304 (struct snd_card_asihpi *)(kcontrol->private_data);2305 struct clk_cache *clkcache = &asihpi->cc;2306 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;2307 uinfo->count = 1;2308 uinfo->value.enumerated.items = clkcache->count;2309 2310 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)2311 uinfo->value.enumerated.item =2312 uinfo->value.enumerated.items - 1;2313 2314 strcpy(uinfo->value.enumerated.name,2315 clkcache->s[uinfo->value.enumerated.item].name);2316 return 0;2317}2318 2319static int snd_asihpi_clksrc_get(struct snd_kcontrol *kcontrol,2320 struct snd_ctl_elem_value *ucontrol)2321{2322 struct snd_card_asihpi *asihpi =2323 (struct snd_card_asihpi *)(kcontrol->private_data);2324 struct clk_cache *clkcache = &asihpi->cc;2325 u32 h_control = kcontrol->private_value;2326 u16 source, srcindex = 0;2327 int i;2328 2329 ucontrol->value.enumerated.item[0] = 0;2330 if (hpi_sample_clock_get_source(h_control, &source))2331 source = 0;2332 2333 if (source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)2334 if (hpi_sample_clock_get_source_index(h_control, &srcindex))2335 srcindex = 0;2336 2337 for (i = 0; i < clkcache->count; i++)2338 if ((clkcache->s[i].source == source) &&2339 (clkcache->s[i].index == srcindex))2340 break;2341 2342 ucontrol->value.enumerated.item[0] = i;2343 2344 return 0;2345}2346 2347static int snd_asihpi_clksrc_put(struct snd_kcontrol *kcontrol,2348 struct snd_ctl_elem_value *ucontrol)2349{2350 struct snd_card_asihpi *asihpi =2351 (struct snd_card_asihpi *)(kcontrol->private_data);2352 struct clk_cache *clkcache = &asihpi->cc;2353 unsigned int item;2354 int change;2355 u32 h_control = kcontrol->private_value;2356 2357 change = 1;2358 item = ucontrol->value.enumerated.item[0];2359 if (item >= clkcache->count)2360 item = clkcache->count-1;2361 2362 hpi_handle_error(hpi_sample_clock_set_source(2363 h_control, clkcache->s[item].source));2364 2365 if (clkcache->s[item].source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)2366 hpi_handle_error(hpi_sample_clock_set_source_index(2367 h_control, clkcache->s[item].index));2368 return change;2369}2370 2371/*------------------------------------------------------------2372 Clkrate controls2373 ------------------------------------------------------------*/2374/* Need to change this to enumerated control with list of rates */2375static int snd_asihpi_clklocal_info(struct snd_kcontrol *kcontrol,2376 struct snd_ctl_elem_info *uinfo)2377{2378 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;2379 uinfo->count = 1;2380 uinfo->value.integer.min = 8000;2381 uinfo->value.integer.max = 192000;2382 uinfo->value.integer.step = 100;2383 2384 return 0;2385}2386 2387static int snd_asihpi_clklocal_get(struct snd_kcontrol *kcontrol,2388 struct snd_ctl_elem_value *ucontrol)2389{2390 u32 h_control = kcontrol->private_value;2391 u32 rate;2392 u16 e;2393 2394 e = hpi_sample_clock_get_local_rate(h_control, &rate);2395 if (!e)2396 ucontrol->value.integer.value[0] = rate;2397 else2398 ucontrol->value.integer.value[0] = 0;2399 return 0;2400}2401 2402static int snd_asihpi_clklocal_put(struct snd_kcontrol *kcontrol,2403 struct snd_ctl_elem_value *ucontrol)2404{2405 int change;2406 u32 h_control = kcontrol->private_value;2407 2408 /* change = asihpi->mixer_clkrate[addr][0] != left ||2409 asihpi->mixer_clkrate[addr][1] != right;2410 */2411 change = 1;2412 hpi_handle_error(hpi_sample_clock_set_local_rate(h_control,2413 ucontrol->value.integer.value[0]));2414 return change;2415}2416 2417static int snd_asihpi_clkrate_info(struct snd_kcontrol *kcontrol,2418 struct snd_ctl_elem_info *uinfo)2419{2420 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;2421 uinfo->count = 1;2422 uinfo->value.integer.min = 8000;2423 uinfo->value.integer.max = 192000;2424 uinfo->value.integer.step = 100;2425 2426 return 0;2427}2428 2429static int snd_asihpi_clkrate_get(struct snd_kcontrol *kcontrol,2430 struct snd_ctl_elem_value *ucontrol)2431{2432 u32 h_control = kcontrol->private_value;2433 u32 rate;2434 u16 e;2435 2436 e = hpi_sample_clock_get_sample_rate(h_control, &rate);2437 if (!e)2438 ucontrol->value.integer.value[0] = rate;2439 else2440 ucontrol->value.integer.value[0] = 0;2441 return 0;2442}2443 2444static int snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi,2445 struct hpi_control *hpi_ctl)2446{2447 struct snd_card *card;2448 struct snd_kcontrol_new snd_control;2449 2450 struct clk_cache *clkcache;2451 u32 hSC = hpi_ctl->h_control;2452 int has_aes_in = 0;2453 int i, j;2454 u16 source;2455 2456 if (snd_BUG_ON(!asihpi))2457 return -EINVAL;2458 card = asihpi->card;2459 clkcache = &asihpi->cc;2460 snd_control.private_value = hpi_ctl->h_control;2461 2462 clkcache->has_local = 0;2463 2464 for (i = 0; i <= HPI_SAMPLECLOCK_SOURCE_LAST; i++) {2465 if (hpi_sample_clock_query_source(hSC,2466 i, &source))2467 break;2468 clkcache->s[i].source = source;2469 clkcache->s[i].index = 0;2470 clkcache->s[i].name = sampleclock_sources[source];2471 if (source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)2472 has_aes_in = 1;2473 if (source == HPI_SAMPLECLOCK_SOURCE_LOCAL)2474 clkcache->has_local = 1;2475 }2476 if (has_aes_in)2477 /* already will have picked up index 0 above */2478 for (j = 1; j < 8; j++) {2479 if (hpi_sample_clock_query_source_index(hSC,2480 j, HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT,2481 &source))2482 break;2483 clkcache->s[i].source =2484 HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT;2485 clkcache->s[i].index = j;2486 clkcache->s[i].name = sampleclock_sources[2487 j+HPI_SAMPLECLOCK_SOURCE_LAST];2488 i++;2489 }2490 clkcache->count = i;2491 2492 asihpi_ctl_init(&snd_control, hpi_ctl, "Source");2493 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE ;2494 snd_control.info = snd_asihpi_clksrc_info;2495 snd_control.get = snd_asihpi_clksrc_get;2496 snd_control.put = snd_asihpi_clksrc_put;2497 if (ctl_add(card, &snd_control, asihpi) < 0)2498 return -EINVAL;2499 2500 2501 if (clkcache->has_local) {2502 asihpi_ctl_init(&snd_control, hpi_ctl, "Localrate");2503 snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE ;2504 snd_control.info = snd_asihpi_clklocal_info;2505 snd_control.get = snd_asihpi_clklocal_get;2506 snd_control.put = snd_asihpi_clklocal_put;2507 2508 2509 if (ctl_add(card, &snd_control, asihpi) < 0)2510 return -EINVAL;2511 }2512 2513 asihpi_ctl_init(&snd_control, hpi_ctl, "Rate");2514 snd_control.access =2515 SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;2516 snd_control.info = snd_asihpi_clkrate_info;2517 snd_control.get = snd_asihpi_clkrate_get;2518 2519 return ctl_add(card, &snd_control, asihpi);2520}2521/*------------------------------------------------------------2522 Mixer2523 ------------------------------------------------------------*/2524 2525static int snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)2526{2527 struct snd_card *card;2528 unsigned int idx = 0;2529 unsigned int subindex = 0;2530 int err;2531 struct hpi_control hpi_ctl, prev_ctl;2532 2533 if (snd_BUG_ON(!asihpi))2534 return -EINVAL;2535 card = asihpi->card;2536 strcpy(card->mixername, "Asihpi Mixer");2537 2538 err =2539 hpi_mixer_open(asihpi->hpi->adapter->index,2540 &asihpi->h_mixer);2541 hpi_handle_error(err);2542 if (err)2543 return -err;2544 2545 memset(&prev_ctl, 0, sizeof(prev_ctl));2546 prev_ctl.control_type = -1;2547 2548 for (idx = 0; idx < 2000; idx++) {2549 err = hpi_mixer_get_control_by_index(2550 asihpi->h_mixer,2551 idx,2552 &hpi_ctl.src_node_type,2553 &hpi_ctl.src_node_index,2554 &hpi_ctl.dst_node_type,2555 &hpi_ctl.dst_node_index,2556 &hpi_ctl.control_type,2557 &hpi_ctl.h_control);2558 if (err) {2559 if (err == HPI_ERROR_CONTROL_DISABLED) {2560 if (mixer_dump)2561 dev_info(&asihpi->pci->dev,2562 "Disabled HPI Control(%d)\n",2563 idx);2564 continue;2565 } else2566 break;2567 2568 }2569 2570 hpi_ctl.src_node_type -= HPI_SOURCENODE_NONE;2571 hpi_ctl.dst_node_type -= HPI_DESTNODE_NONE;2572 2573 /* ASI50xx in SSX mode has multiple meters on the same node.2574 Use subindex to create distinct ALSA controls2575 for any duplicated controls.2576 */2577 if ((hpi_ctl.control_type == prev_ctl.control_type) &&2578 (hpi_ctl.src_node_type == prev_ctl.src_node_type) &&2579 (hpi_ctl.src_node_index == prev_ctl.src_node_index) &&2580 (hpi_ctl.dst_node_type == prev_ctl.dst_node_type) &&2581 (hpi_ctl.dst_node_index == prev_ctl.dst_node_index))2582 subindex++;2583 else2584 subindex = 0;2585 2586 prev_ctl = hpi_ctl;2587 2588 switch (hpi_ctl.control_type) {2589 case HPI_CONTROL_VOLUME:2590 err = snd_asihpi_volume_add(asihpi, &hpi_ctl);2591 break;2592 case HPI_CONTROL_LEVEL:2593 err = snd_asihpi_level_add(asihpi, &hpi_ctl);2594 break;2595 case HPI_CONTROL_MULTIPLEXER:2596 err = snd_asihpi_mux_add(asihpi, &hpi_ctl);2597 break;2598 case HPI_CONTROL_CHANNEL_MODE:2599 err = snd_asihpi_cmode_add(asihpi, &hpi_ctl);2600 break;2601 case HPI_CONTROL_METER:2602 err = snd_asihpi_meter_add(asihpi, &hpi_ctl, subindex);2603 break;2604 case HPI_CONTROL_SAMPLECLOCK:2605 err = snd_asihpi_sampleclock_add(2606 asihpi, &hpi_ctl);2607 break;2608 case HPI_CONTROL_CONNECTION: /* ignore these */2609 continue;2610 case HPI_CONTROL_TUNER:2611 err = snd_asihpi_tuner_add(asihpi, &hpi_ctl);2612 break;2613 case HPI_CONTROL_AESEBU_TRANSMITTER:2614 err = snd_asihpi_aesebu_tx_add(asihpi, &hpi_ctl);2615 break;2616 case HPI_CONTROL_AESEBU_RECEIVER:2617 err = snd_asihpi_aesebu_rx_add(asihpi, &hpi_ctl);2618 break;2619 case HPI_CONTROL_VOX:2620 case HPI_CONTROL_BITSTREAM:2621 case HPI_CONTROL_MICROPHONE:2622 case HPI_CONTROL_PARAMETRIC_EQ:2623 case HPI_CONTROL_COMPANDER:2624 default:2625 if (mixer_dump)2626 dev_info(&asihpi->pci->dev,2627 "Untranslated HPI Control (%d) %d %d %d %d %d\n",2628 idx,2629 hpi_ctl.control_type,2630 hpi_ctl.src_node_type,2631 hpi_ctl.src_node_index,2632 hpi_ctl.dst_node_type,2633 hpi_ctl.dst_node_index);2634 continue;2635 }2636 if (err < 0)2637 return err;2638 }2639 if (HPI_ERROR_INVALID_OBJ_INDEX != err)2640 hpi_handle_error(err);2641 2642 dev_info(&asihpi->pci->dev, "%d mixer controls found\n", idx);2643 2644 return 0;2645}2646 2647/*------------------------------------------------------------2648 /proc interface2649 ------------------------------------------------------------*/2650 2651static void2652snd_asihpi_proc_read(struct snd_info_entry *entry,2653 struct snd_info_buffer *buffer)2654{2655 struct snd_card_asihpi *asihpi = entry->private_data;2656 u32 h_control;2657 u32 rate = 0;2658 u16 source = 0;2659 2660 u16 num_outstreams;2661 u16 num_instreams;2662 u16 version;2663 u32 serial_number;2664 u16 type;2665 2666 int err;2667 2668 snd_iprintf(buffer, "ASIHPI driver proc file\n");2669 2670 hpi_handle_error(hpi_adapter_get_info(asihpi->hpi->adapter->index,2671 &num_outstreams, &num_instreams,2672 &version, &serial_number, &type));2673 2674 snd_iprintf(buffer,2675 "Adapter type ASI%4X\nHardware Index %d\n"2676 "%d outstreams\n%d instreams\n",2677 type, asihpi->hpi->adapter->index,2678 num_outstreams, num_instreams);2679 2680 snd_iprintf(buffer,2681 "Serial#%d\nHardware version %c%d\nDSP code version %03d\n",2682 serial_number, ((version >> 3) & 0xf) + 'A', version & 0x7,2683 ((version >> 13) * 100) + ((version >> 7) & 0x3f));2684 2685 err = hpi_mixer_get_control(asihpi->h_mixer,2686 HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,2687 HPI_CONTROL_SAMPLECLOCK, &h_control);2688 2689 if (!err) {2690 err = hpi_sample_clock_get_sample_rate(h_control, &rate);2691 err += hpi_sample_clock_get_source(h_control, &source);2692 2693 if (!err)2694 snd_iprintf(buffer, "Sample Clock %dHz, source %s\n",2695 rate, sampleclock_sources[source]);2696 }2697}2698 2699static void snd_asihpi_proc_init(struct snd_card_asihpi *asihpi)2700{2701 snd_card_ro_proc_new(asihpi->card, "info", asihpi,2702 snd_asihpi_proc_read);2703}2704 2705/*------------------------------------------------------------2706 HWDEP2707 ------------------------------------------------------------*/2708 2709static int snd_asihpi_hpi_open(struct snd_hwdep *hw, struct file *file)2710{2711 if (enable_hpi_hwdep)2712 return 0;2713 else2714 return -ENODEV;2715 2716}2717 2718static int snd_asihpi_hpi_release(struct snd_hwdep *hw, struct file *file)2719{2720 if (enable_hpi_hwdep)2721 return asihpi_hpi_release(file);2722 else2723 return -ENODEV;2724}2725 2726static int snd_asihpi_hpi_ioctl(struct snd_hwdep *hw, struct file *file,2727 unsigned int cmd, unsigned long arg)2728{2729 if (enable_hpi_hwdep)2730 return asihpi_hpi_ioctl(file, cmd, arg);2731 else2732 return -ENODEV;2733}2734 2735 2736/* results in /dev/snd/hwC#D0 file for each card with index #2737 also /proc/asound/hwdep will contain '#-00: asihpi (HPI) for each card'2738*/2739static int snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, int device)2740{2741 struct snd_hwdep *hw;2742 int err;2743 2744 err = snd_hwdep_new(asihpi->card, "HPI", device, &hw);2745 if (err < 0)2746 return err;2747 strcpy(hw->name, "asihpi (HPI)");2748 hw->iface = SNDRV_HWDEP_IFACE_LAST;2749 hw->ops.open = snd_asihpi_hpi_open;2750 hw->ops.ioctl = snd_asihpi_hpi_ioctl;2751 hw->ops.release = snd_asihpi_hpi_release;2752 hw->private_data = asihpi;2753 return 0;2754}2755 2756/*------------------------------------------------------------2757 CARD2758 ------------------------------------------------------------*/2759static int snd_asihpi_probe(struct pci_dev *pci_dev,2760 const struct pci_device_id *pci_id)2761{2762 int err;2763 struct hpi_adapter *hpi;2764 struct snd_card *card;2765 struct snd_card_asihpi *asihpi;2766 2767 u32 h_control;2768 u32 h_stream;2769 u32 adapter_index;2770 2771 static int dev;2772 if (dev >= SNDRV_CARDS)2773 return -ENODEV;2774 2775 /* Should this be enable[hpi->index] ? */2776 if (!enable[dev]) {2777 dev++;2778 return -ENOENT;2779 }2780 2781 /* Initialise low-level HPI driver */2782 err = asihpi_adapter_probe(pci_dev, pci_id);2783 if (err < 0)2784 return err;2785 2786 hpi = pci_get_drvdata(pci_dev);2787 adapter_index = hpi->adapter->index;2788 /* first try to give the card the same index as its hardware index */2789 err = snd_card_new(&pci_dev->dev, adapter_index, id[adapter_index],2790 THIS_MODULE, sizeof(struct snd_card_asihpi), &card);2791 if (err < 0) {2792 /* if that fails, try the default index==next available */2793 err = snd_card_new(&pci_dev->dev, index[dev], id[dev],2794 THIS_MODULE, sizeof(struct snd_card_asihpi),2795 &card);2796 if (err < 0)2797 return err;2798 dev_warn(&pci_dev->dev, "Adapter index %d->ALSA index %d\n",2799 adapter_index, card->number);2800 }2801 2802 asihpi = card->private_data;2803 asihpi->card = card;2804 asihpi->pci = pci_dev;2805 asihpi->hpi = hpi;2806 hpi->snd_card = card;2807 2808 err = hpi_adapter_get_property(adapter_index,2809 HPI_ADAPTER_PROPERTY_CAPS1,2810 NULL, &asihpi->support_grouping);2811 if (err)2812 asihpi->support_grouping = 0;2813 2814 err = hpi_adapter_get_property(adapter_index,2815 HPI_ADAPTER_PROPERTY_CAPS2,2816 &asihpi->support_mrx, NULL);2817 if (err)2818 asihpi->support_mrx = 0;2819 2820 err = hpi_adapter_get_property(adapter_index,2821 HPI_ADAPTER_PROPERTY_INTERVAL,2822 NULL, &asihpi->update_interval_frames);2823 if (err)2824 asihpi->update_interval_frames = 512;2825 2826 if (hpi->interrupt_mode) {2827 asihpi->pcm_start = snd_card_asihpi_pcm_int_start;2828 asihpi->pcm_stop = snd_card_asihpi_pcm_int_stop;2829 hpi->interrupt_callback = snd_card_asihpi_isr;2830 } else {2831 asihpi->pcm_start = snd_card_asihpi_pcm_timer_start;2832 asihpi->pcm_stop = snd_card_asihpi_pcm_timer_stop;2833 }2834 2835 hpi_handle_error(hpi_instream_open(adapter_index,2836 0, &h_stream));2837 2838 err = hpi_instream_host_buffer_free(h_stream);2839 asihpi->can_dma = (!err);2840 2841 hpi_handle_error(hpi_instream_close(h_stream));2842 2843 if (!asihpi->can_dma)2844 asihpi->update_interval_frames *= 2;2845 2846 err = hpi_adapter_get_property(adapter_index,2847 HPI_ADAPTER_PROPERTY_CURCHANNELS,2848 &asihpi->in_max_chans, &asihpi->out_max_chans);2849 if (err) {2850 asihpi->in_max_chans = 2;2851 asihpi->out_max_chans = 2;2852 }2853 2854 if (asihpi->out_max_chans > 2) { /* assume LL mode */2855 asihpi->out_min_chans = asihpi->out_max_chans;2856 asihpi->in_min_chans = asihpi->in_max_chans;2857 asihpi->support_grouping = 0;2858 } else {2859 asihpi->out_min_chans = 1;2860 asihpi->in_min_chans = 1;2861 }2862 2863 dev_info(&pci_dev->dev, "Has dma:%d, grouping:%d, mrx:%d, uif:%d\n",2864 asihpi->can_dma,2865 asihpi->support_grouping,2866 asihpi->support_mrx,2867 asihpi->update_interval_frames2868 );2869 2870 err = snd_card_asihpi_pcm_new(asihpi, 0);2871 if (err < 0) {2872 dev_err(&pci_dev->dev, "pcm_new failed\n");2873 goto __nodev;2874 }2875 err = snd_card_asihpi_mixer_new(asihpi);2876 if (err < 0) {2877 dev_err(&pci_dev->dev, "mixer_new failed\n");2878 goto __nodev;2879 }2880 2881 err = hpi_mixer_get_control(asihpi->h_mixer,2882 HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,2883 HPI_CONTROL_SAMPLECLOCK, &h_control);2884 2885 if (!err)2886 err = hpi_sample_clock_set_local_rate(2887 h_control, adapter_fs);2888 2889 snd_asihpi_proc_init(asihpi);2890 2891 /* always create, can be enabled or disabled dynamically2892 by enable_hwdep module param*/2893 snd_asihpi_hpi_new(asihpi, 0);2894 2895 strcpy(card->driver, "ASIHPI");2896 2897 sprintf(card->shortname, "AudioScience ASI%4X",2898 asihpi->hpi->adapter->type);2899 sprintf(card->longname, "%s %i",2900 card->shortname, adapter_index);2901 err = snd_card_register(card);2902 2903 if (!err) {2904 dev++;2905 return 0;2906 }2907__nodev:2908 snd_card_free(card);2909 dev_err(&pci_dev->dev, "snd_asihpi_probe error %d\n", err);2910 return err;2911 2912}2913 2914static void snd_asihpi_remove(struct pci_dev *pci_dev)2915{2916 struct hpi_adapter *hpi = pci_get_drvdata(pci_dev);2917 2918 /* Stop interrupts */2919 if (hpi->interrupt_mode) {2920 hpi->interrupt_callback = NULL;2921 hpi_handle_error(hpi_adapter_set_property(hpi->adapter->index,2922 HPI_ADAPTER_PROPERTY_IRQ_RATE, 0, 0));2923 }2924 2925 snd_card_free(hpi->snd_card);2926 hpi->snd_card = NULL;2927 asihpi_adapter_remove(pci_dev);2928}2929 2930static const struct pci_device_id asihpi_pci_tbl[] = {2931 {HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_DSP6205,2932 HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,2933 (kernel_ulong_t)HPI_6205},2934 {HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_PCI2040,2935 HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,2936 (kernel_ulong_t)HPI_6000},2937 {0,}2938};2939MODULE_DEVICE_TABLE(pci, asihpi_pci_tbl);2940 2941static struct pci_driver driver = {2942 .name = KBUILD_MODNAME,2943 .id_table = asihpi_pci_tbl,2944 .probe = snd_asihpi_probe,2945 .remove = snd_asihpi_remove,2946};2947 2948static int __init snd_asihpi_init(void)2949{2950 asihpi_init();2951 return pci_register_driver(&driver);2952}2953 2954static void __exit snd_asihpi_exit(void)2955{2956 2957 pci_unregister_driver(&driver);2958 asihpi_exit();2959}2960 2961module_init(snd_asihpi_init)2962module_exit(snd_asihpi_exit)2963 2964