123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361 |
- /*
- * ALSA driver for Echoaudio soundcards.
- * Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.it>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- #include <linux/module.h>
- MODULE_AUTHOR("Giuliano Pochini <pochini@shiny.it>");
- MODULE_LICENSE("GPL v2");
- MODULE_DESCRIPTION("Echoaudio " ECHOCARD_NAME " soundcards driver");
- MODULE_SUPPORTED_DEVICE("{{Echoaudio," ECHOCARD_NAME "}}");
- MODULE_DEVICE_TABLE(pci, snd_echo_ids);
- static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
- static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
- static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
- module_param_array(index, int, NULL, 0444);
- MODULE_PARM_DESC(index, "Index value for " ECHOCARD_NAME " soundcard.");
- module_param_array(id, charp, NULL, 0444);
- MODULE_PARM_DESC(id, "ID string for " ECHOCARD_NAME " soundcard.");
- module_param_array(enable, bool, NULL, 0444);
- MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard.");
- static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999};
- static const DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1);
- static int get_firmware(const struct firmware **fw_entry,
- struct echoaudio *chip, const short fw_index)
- {
- int err;
- char name[30];
- #ifdef CONFIG_PM
- if (chip->fw_cache[fw_index]) {
- DE_ACT(("firmware requested: %s is cached\n", card_fw[fw_index].data));
- *fw_entry = chip->fw_cache[fw_index];
- return 0;
- }
- #endif
- DE_ACT(("firmware requested: %s\n", card_fw[fw_index].data));
- snprintf(name, sizeof(name), "ea/%s", card_fw[fw_index].data);
- err = request_firmware(fw_entry, name, pci_device(chip));
- if (err < 0)
- snd_printk(KERN_ERR "get_firmware(): Firmware not available (%d)\n", err);
- #ifdef CONFIG_PM
- else
- chip->fw_cache[fw_index] = *fw_entry;
- #endif
- return err;
- }
- static void free_firmware(const struct firmware *fw_entry)
- {
- #ifdef CONFIG_PM
- DE_ACT(("firmware not released (kept in cache)\n"));
- #else
- release_firmware(fw_entry);
- DE_ACT(("firmware released\n"));
- #endif
- }
- static void free_firmware_cache(struct echoaudio *chip)
- {
- #ifdef CONFIG_PM
- int i;
- for (i = 0; i < 8 ; i++)
- if (chip->fw_cache[i]) {
- release_firmware(chip->fw_cache[i]);
- DE_ACT(("release_firmware(%d)\n", i));
- }
- DE_ACT(("firmware_cache released\n"));
- #endif
- }
- /******************************************************************************
- PCM interface
- ******************************************************************************/
- static void audiopipe_free(struct snd_pcm_runtime *runtime)
- {
- struct audiopipe *pipe = runtime->private_data;
- if (pipe->sgpage.area)
- snd_dma_free_pages(&pipe->sgpage);
- kfree(pipe);
- }
- static int hw_rule_capture_format_by_channels(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
- {
- struct snd_interval *c = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
- struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- struct snd_mask fmt;
- snd_mask_any(&fmt);
- #ifndef ECHOCARD_HAS_STEREO_BIG_ENDIAN32
- /* >=2 channels cannot be S32_BE */
- if (c->min == 2) {
- fmt.bits[0] &= ~SNDRV_PCM_FMTBIT_S32_BE;
- return snd_mask_refine(f, &fmt);
- }
- #endif
- /* > 2 channels cannot be U8 and S32_BE */
- if (c->min > 2) {
- fmt.bits[0] &= ~(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_BE);
- return snd_mask_refine(f, &fmt);
- }
- /* Mono is ok with any format */
- return 0;
- }
- static int hw_rule_capture_channels_by_format(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
- {
- struct snd_interval *c = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
- struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- struct snd_interval ch;
- snd_interval_any(&ch);
- /* S32_BE is mono (and stereo) only */
- if (f->bits[0] == SNDRV_PCM_FMTBIT_S32_BE) {
- ch.min = 1;
- #ifdef ECHOCARD_HAS_STEREO_BIG_ENDIAN32
- ch.max = 2;
- #else
- ch.max = 1;
- #endif
- ch.integer = 1;
- return snd_interval_refine(c, &ch);
- }
- /* U8 can be only mono or stereo */
- if (f->bits[0] == SNDRV_PCM_FMTBIT_U8) {
- ch.min = 1;
- ch.max = 2;
- ch.integer = 1;
- return snd_interval_refine(c, &ch);
- }
- /* S16_LE, S24_3LE and S32_LE support any number of channels. */
- return 0;
- }
- static int hw_rule_playback_format_by_channels(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
- {
- struct snd_interval *c = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
- struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- struct snd_mask fmt;
- u64 fmask;
- snd_mask_any(&fmt);
- fmask = fmt.bits[0] + ((u64)fmt.bits[1] << 32);
- /* >2 channels must be S16_LE, S24_3LE or S32_LE */
- if (c->min > 2) {
- fmask &= SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_3LE |
- SNDRV_PCM_FMTBIT_S32_LE;
- /* 1 channel must be S32_BE or S32_LE */
- } else if (c->max == 1)
- fmask &= SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE;
- #ifndef ECHOCARD_HAS_STEREO_BIG_ENDIAN32
- /* 2 channels cannot be S32_BE */
- else if (c->min == 2 && c->max == 2)
- fmask &= ~SNDRV_PCM_FMTBIT_S32_BE;
- #endif
- else
- return 0;
- fmt.bits[0] &= (u32)fmask;
- fmt.bits[1] &= (u32)(fmask >> 32);
- return snd_mask_refine(f, &fmt);
- }
- static int hw_rule_playback_channels_by_format(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
- {
- struct snd_interval *c = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
- struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- struct snd_interval ch;
- u64 fmask;
- snd_interval_any(&ch);
- ch.integer = 1;
- fmask = f->bits[0] + ((u64)f->bits[1] << 32);
- /* S32_BE is mono (and stereo) only */
- if (fmask == SNDRV_PCM_FMTBIT_S32_BE) {
- ch.min = 1;
- #ifdef ECHOCARD_HAS_STEREO_BIG_ENDIAN32
- ch.max = 2;
- #else
- ch.max = 1;
- #endif
- /* U8 is stereo only */
- } else if (fmask == SNDRV_PCM_FMTBIT_U8)
- ch.min = ch.max = 2;
- /* S16_LE and S24_3LE must be at least stereo */
- else if (!(fmask & ~(SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_3LE)))
- ch.min = 2;
- else
- return 0;
- return snd_interval_refine(c, &ch);
- }
- /* Since the sample rate is a global setting, do allow the user to change the
- sample rate only if there is only one pcm device open. */
- static int hw_rule_sample_rate(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
- {
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct echoaudio *chip = rule->private;
- struct snd_interval fixed;
- if (!chip->can_set_rate) {
- snd_interval_any(&fixed);
- fixed.min = fixed.max = chip->sample_rate;
- return snd_interval_refine(rate, &fixed);
- }
- return 0;
- }
- static int pcm_open(struct snd_pcm_substream *substream,
- signed char max_channels)
- {
- struct echoaudio *chip;
- struct snd_pcm_runtime *runtime;
- struct audiopipe *pipe;
- int err, i;
- if (max_channels <= 0)
- return -EAGAIN;
- chip = snd_pcm_substream_chip(substream);
- runtime = substream->runtime;
- pipe = kzalloc(sizeof(struct audiopipe), GFP_KERNEL);
- if (!pipe)
- return -ENOMEM;
- pipe->index = -1; /* Not configured yet */
- /* Set up hw capabilities and contraints */
- memcpy(&pipe->hw, &pcm_hardware_skel, sizeof(struct snd_pcm_hardware));
- DE_HWP(("max_channels=%d\n", max_channels));
- pipe->constr.list = channels_list;
- pipe->constr.mask = 0;
- for (i = 0; channels_list[i] <= max_channels; i++);
- pipe->constr.count = i;
- if (pipe->hw.channels_max > max_channels)
- pipe->hw.channels_max = max_channels;
- if (chip->digital_mode == DIGITAL_MODE_ADAT) {
- pipe->hw.rate_max = 48000;
- pipe->hw.rates &= SNDRV_PCM_RATE_8000_48000;
- }
- runtime->hw = pipe->hw;
- runtime->private_data = pipe;
- runtime->private_free = audiopipe_free;
- snd_pcm_set_sync(substream);
- /* Only mono and any even number of channels are allowed */
- if ((err = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- &pipe->constr)) < 0)
- return err;
- /* All periods should have the same size */
- if ((err = snd_pcm_hw_constraint_integer(runtime,
- SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
- return err;
- /* The hw accesses memory in chunks 32 frames long and they should be
- 32-bytes-aligned. It's not a requirement, but it seems that IRQs are
- generated with a resolution of 32 frames. Thus we need the following */
- if ((err = snd_pcm_hw_constraint_step(runtime, 0,
- SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
- 32)) < 0)
- return err;
- if ((err = snd_pcm_hw_constraint_step(runtime, 0,
- SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
- 32)) < 0)
- return err;
- if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- hw_rule_sample_rate, chip,
- SNDRV_PCM_HW_PARAM_RATE, -1)) < 0)
- return err;
- /* Finally allocate a page for the scatter-gather list */
- if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
- snd_dma_pci_data(chip->pci),
- PAGE_SIZE, &pipe->sgpage)) < 0) {
- DE_HWP(("s-g list allocation failed\n"));
- return err;
- }
- return 0;
- }
- static int pcm_analog_in_open(struct snd_pcm_substream *substream)
- {
- struct echoaudio *chip = snd_pcm_substream_chip(substream);
- int err;
- DE_ACT(("pcm_analog_in_open\n"));
- if ((err = pcm_open(substream, num_analog_busses_in(chip) -
- substream->number)) < 0)
- return err;
- if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- hw_rule_capture_channels_by_format, NULL,
- SNDRV_PCM_HW_PARAM_FORMAT, -1)) < 0)
- return err;
- if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_FORMAT,
- hw_rule_capture_format_by_channels, NULL,
- SNDRV_PCM_HW_PARAM_CHANNELS, -1)) < 0)
- return err;
- atomic_inc(&chip->opencount);
- if (atomic_read(&chip->opencount) > 1 && chip->rate_set)
- chip->can_set_rate=0;
- DE_HWP(("pcm_analog_in_open cs=%d oc=%d r=%d\n",
- chip->can_set_rate, atomic_read(&chip->opencount),
- chip->sample_rate));
- return 0;
- }
- static int pcm_analog_out_open(struct snd_pcm_substream *substream)
- {
- struct echoaudio *chip = snd_pcm_substream_chip(substream);
- int max_channels, err;
- #ifdef ECHOCARD_HAS_VMIXER
- max_channels = num_pipes_out(chip);
- #else
- max_channels = num_analog_busses_out(chip);
- #endif
- DE_ACT(("pcm_analog_out_open\n"));
- if ((err = pcm_open(substream, max_channels - substream->number)) < 0)
- return err;
- if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- hw_rule_playback_channels_by_format,
- NULL,
- SNDRV_PCM_HW_PARAM_FORMAT, -1)) < 0)
- return err;
- if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_FORMAT,
- hw_rule_playback_format_by_channels,
- NULL,
- SNDRV_PCM_HW_PARAM_CHANNELS, -1)) < 0)
- return err;
- atomic_inc(&chip->opencount);
- if (atomic_read(&chip->opencount) > 1 && chip->rate_set)
- chip->can_set_rate=0;
- DE_HWP(("pcm_analog_out_open cs=%d oc=%d r=%d\n",
- chip->can_set_rate, atomic_read(&chip->opencount),
- chip->sample_rate));
- return 0;
- }
- #ifdef ECHOCARD_HAS_DIGITAL_IO
- static int pcm_digital_in_open(struct snd_pcm_substream *substream)
- {
- struct echoaudio *chip = snd_pcm_substream_chip(substream);
- int err, max_channels;
- DE_ACT(("pcm_digital_in_open\n"));
- max_channels = num_digital_busses_in(chip) - substream->number;
- mutex_lock(&chip->mode_mutex);
- if (chip->digital_mode == DIGITAL_MODE_ADAT)
- err = pcm_open(substream, max_channels);
- else /* If the card has ADAT, subtract the 6 channels
- * that S/PDIF doesn't have
- */
- err = pcm_open(substream, max_channels - ECHOCARD_HAS_ADAT);
- if (err < 0)
- goto din_exit;
- if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- hw_rule_capture_channels_by_format, NULL,
- SNDRV_PCM_HW_PARAM_FORMAT, -1)) < 0)
- goto din_exit;
- if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_FORMAT,
- hw_rule_capture_format_by_channels, NULL,
- SNDRV_PCM_HW_PARAM_CHANNELS, -1)) < 0)
- goto din_exit;
- atomic_inc(&chip->opencount);
- if (atomic_read(&chip->opencount) > 1 && chip->rate_set)
- chip->can_set_rate=0;
- din_exit:
- mutex_unlock(&chip->mode_mutex);
- return err;
- }
- #ifndef ECHOCARD_HAS_VMIXER /* See the note in snd_echo_new_pcm() */
- static int pcm_digital_out_open(struct snd_pcm_substream *substream)
- {
- struct echoaudio *chip = snd_pcm_substream_chip(substream);
- int err, max_channels;
- DE_ACT(("pcm_digital_out_open\n"));
- max_channels = num_digital_busses_out(chip) - substream->number;
- mutex_lock(&chip->mode_mutex);
- if (chip->digital_mode == DIGITAL_MODE_ADAT)
- err = pcm_open(substream, max_channels);
- else /* If the card has ADAT, subtract the 6 channels
- * that S/PDIF doesn't have
- */
- err = pcm_open(substream, max_channels - ECHOCARD_HAS_ADAT);
- if (err < 0)
- goto dout_exit;
- if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- hw_rule_playback_channels_by_format,
- NULL, SNDRV_PCM_HW_PARAM_FORMAT,
- -1)) < 0)
- goto dout_exit;
- if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_FORMAT,
- hw_rule_playback_format_by_channels,
- NULL, SNDRV_PCM_HW_PARAM_CHANNELS,
- -1)) < 0)
- goto dout_exit;
- atomic_inc(&chip->opencount);
- if (atomic_read(&chip->opencount) > 1 && chip->rate_set)
- chip->can_set_rate=0;
- dout_exit:
- mutex_unlock(&chip->mode_mutex);
- return err;
- }
- #endif /* !ECHOCARD_HAS_VMIXER */
- #endif /* ECHOCARD_HAS_DIGITAL_IO */
- static int pcm_close(struct snd_pcm_substream *substream)
- {
- struct echoaudio *chip = snd_pcm_substream_chip(substream);
- int oc;
- /* Nothing to do here. Audio is already off and pipe will be
- * freed by its callback
- */
- DE_ACT(("pcm_close\n"));
- atomic_dec(&chip->opencount);
- oc = atomic_read(&chip->opencount);
- DE_ACT(("pcm_close oc=%d cs=%d rs=%d\n", oc,
- chip->can_set_rate, chip->rate_set));
- if (oc < 2)
- chip->can_set_rate = 1;
- if (oc == 0)
- chip->rate_set = 0;
- DE_ACT(("pcm_close2 oc=%d cs=%d rs=%d\n", oc,
- chip->can_set_rate,chip->rate_set));
- return 0;
- }
- /* Channel allocation and scatter-gather list setup */
- static int init_engine(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params,
- int pipe_index, int interleave)
- {
- struct echoaudio *chip;
- int err, per, rest, page, edge, offs;
- struct audiopipe *pipe;
- chip = snd_pcm_substream_chip(substream);
- pipe = (struct audiopipe *) substream->runtime->private_data;
- /* Sets up che hardware. If it's already initialized, reset and
- * redo with the new parameters
- */
- spin_lock_irq(&chip->lock);
- if (pipe->index >= 0) {
- DE_HWP(("hwp_ie free(%d)\n", pipe->index));
- err = free_pipes(chip, pipe);
- snd_BUG_ON(err);
- chip->substream[pipe->index] = NULL;
- }
- err = allocate_pipes(chip, pipe, pipe_index, interleave);
- if (err < 0) {
- spin_unlock_irq(&chip->lock);
- DE_ACT((KERN_NOTICE "allocate_pipes(%d) err=%d\n",
- pipe_index, err));
- return err;
- }
- spin_unlock_irq(&chip->lock);
- DE_ACT((KERN_NOTICE "allocate_pipes()=%d\n", pipe_index));
- DE_HWP(("pcm_hw_params (bufsize=%dB periods=%d persize=%dB)\n",
- params_buffer_bytes(hw_params), params_periods(hw_params),
- params_period_bytes(hw_params)));
- err = snd_pcm_lib_malloc_pages(substream,
- params_buffer_bytes(hw_params));
- if (err < 0) {
- snd_printk(KERN_ERR "malloc_pages err=%d\n", err);
- spin_lock_irq(&chip->lock);
- free_pipes(chip, pipe);
- spin_unlock_irq(&chip->lock);
- pipe->index = -1;
- return err;
- }
- sglist_init(chip, pipe);
- edge = PAGE_SIZE;
- for (offs = page = per = 0; offs < params_buffer_bytes(hw_params);
- per++) {
- rest = params_period_bytes(hw_params);
- if (offs + rest > params_buffer_bytes(hw_params))
- rest = params_buffer_bytes(hw_params) - offs;
- while (rest) {
- dma_addr_t addr;
- addr = snd_pcm_sgbuf_get_addr(substream, offs);
- if (rest <= edge - offs) {
- sglist_add_mapping(chip, pipe, addr, rest);
- sglist_add_irq(chip, pipe);
- offs += rest;
- rest = 0;
- } else {
- sglist_add_mapping(chip, pipe, addr,
- edge - offs);
- rest -= edge - offs;
- offs = edge;
- }
- if (offs == edge) {
- edge += PAGE_SIZE;
- page++;
- }
- }
- }
- /* Close the ring buffer */
- sglist_wrap(chip, pipe);
- /* This stuff is used by the irq handler, so it must be
- * initialized before chip->substream
- */
- chip->last_period[pipe_index] = 0;
- pipe->last_counter = 0;
- pipe->position = 0;
- smp_wmb();
- chip->substream[pipe_index] = substream;
- chip->rate_set = 1;
- spin_lock_irq(&chip->lock);
- set_sample_rate(chip, hw_params->rate_num / hw_params->rate_den);
- spin_unlock_irq(&chip->lock);
- DE_HWP(("pcm_hw_params ok\n"));
- return 0;
- }
- static int pcm_analog_in_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
- {
- struct echoaudio *chip = snd_pcm_substream_chip(substream);
- return init_engine(substream, hw_params, px_analog_in(chip) +
- substream->number, params_channels(hw_params));
- }
- static int pcm_analog_out_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
- {
- return init_engine(substream, hw_params, substream->number,
- params_channels(hw_params));
- }
- #ifdef ECHOCARD_HAS_DIGITAL_IO
- static int pcm_digital_in_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
- {
- struct echoaudio *chip = snd_pcm_substream_chip(substream);
- return init_engine(substream, hw_params, px_digital_in(chip) +
- substream->number, params_channels(hw_params));
- }
- #ifndef ECHOCARD_HAS_VMIXER /* See the note in snd_echo_new_pcm() */
- static int pcm_digital_out_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
- {
- struct echoaudio *chip = snd_pcm_substream_chip(substream);
- return init_engine(substream, hw_params, px_digital_out(chip) +
- substream->number, params_channels(hw_params));
- }
- #endif /* !ECHOCARD_HAS_VMIXER */
- #endif /* ECHOCARD_HAS_DIGITAL_IO */
- static int pcm_hw_free(struct snd_pcm_substream *substream)
- {
- struct echoaudio *chip;
- struct audiopipe *pipe;
- chip = snd_pcm_substream_chip(substream);
- pipe = (struct audiopipe *) substream->runtime->private_data;
- spin_lock_irq(&chip->lock);
- if (pipe->index >= 0) {
- DE_HWP(("pcm_hw_free(%d)\n", pipe->index));
- free_pipes(chip, pipe);
- chip->substream[pipe->index] = NULL;
- pipe->index = -1;
- }
- spin_unlock_irq(&chip->lock);
- DE_HWP(("pcm_hw_freed\n"));
- snd_pcm_lib_free_pages(substream);
- return 0;
- }
- static int pcm_prepare(struct snd_pcm_substream *substream)
- {
- struct echoaudio *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct audioformat format;
- int pipe_index = ((struct audiopipe *)runtime->private_data)->index;
- DE_HWP(("Prepare rate=%d format=%d channels=%d\n",
- runtime->rate, runtime->format, runtime->channels));
- format.interleave = runtime->channels;
- format.data_are_bigendian = 0;
- format.mono_to_stereo = 0;
- switch (runtime->format) {
- case SNDRV_PCM_FORMAT_U8:
- format.bits_per_sample = 8;
- break;
- case SNDRV_PCM_FORMAT_S16_LE:
- format.bits_per_sample = 16;
- break;
- case SNDRV_PCM_FORMAT_S24_3LE:
- format.bits_per_sample = 24;
- break;
- case SNDRV_PCM_FORMAT_S32_BE:
- format.data_are_bigendian = 1;
- case SNDRV_PCM_FORMAT_S32_LE:
- format.bits_per_sample = 32;
- break;
- default:
- DE_HWP(("Prepare error: unsupported format %d\n",
- runtime->format));
- return -EINVAL;
- }
- if (snd_BUG_ON(pipe_index >= px_num(chip)))
- return -EINVAL;
- if (snd_BUG_ON(!is_pipe_allocated(chip, pipe_index)))
- return -EINVAL;
- set_audio_format(chip, pipe_index, &format);
- return 0;
- }
- static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
- {
- struct echoaudio *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct audiopipe *pipe = runtime->private_data;
- int i, err;
- u32 channelmask = 0;
- struct snd_pcm_substream *s;
- snd_pcm_group_for_each_entry(s, substream) {
- for (i = 0; i < DSP_MAXPIPES; i++) {
- if (s == chip->substream[i]) {
- channelmask |= 1 << i;
- snd_pcm_trigger_done(s, substream);
- }
- }
- }
- spin_lock(&chip->lock);
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_RESUME:
- DE_ACT(("pcm_trigger resume\n"));
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- DE_ACT(("pcm_trigger start\n"));
- for (i = 0; i < DSP_MAXPIPES; i++) {
- if (channelmask & (1 << i)) {
- pipe = chip->substream[i]->runtime->private_data;
- switch (pipe->state) {
- case PIPE_STATE_STOPPED:
- chip->last_period[i] = 0;
- pipe->last_counter = 0;
- pipe->position = 0;
- *pipe->dma_counter = 0;
- case PIPE_STATE_PAUSED:
- pipe->state = PIPE_STATE_STARTED;
- break;
- case PIPE_STATE_STARTED:
- break;
- }
- }
- }
- err = start_transport(chip, channelmask,
- chip->pipe_cyclic_mask);
- break;
- case SNDRV_PCM_TRIGGER_SUSPEND:
- DE_ACT(("pcm_trigger suspend\n"));
- case SNDRV_PCM_TRIGGER_STOP:
- DE_ACT(("pcm_trigger stop\n"));
- for (i = 0; i < DSP_MAXPIPES; i++) {
- if (channelmask & (1 << i)) {
- pipe = chip->substream[i]->runtime->private_data;
- pipe->state = PIPE_STATE_STOPPED;
- }
- }
- err = stop_transport(chip, channelmask);
- break;
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- DE_ACT(("pcm_trigger pause\n"));
- for (i = 0; i < DSP_MAXPIPES; i++) {
- if (channelmask & (1 << i)) {
- pipe = chip->substream[i]->runtime->private_data;
- pipe->state = PIPE_STATE_PAUSED;
- }
- }
- err = pause_transport(chip, channelmask);
- break;
- default:
- err = -EINVAL;
- }
- spin_unlock(&chip->lock);
- return err;
- }
- static snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream)
- {
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct audiopipe *pipe = runtime->private_data;
- size_t cnt, bufsize, pos;
- cnt = le32_to_cpu(*pipe->dma_counter);
- pipe->position += cnt - pipe->last_counter;
- pipe->last_counter = cnt;
- bufsize = substream->runtime->buffer_size;
- pos = bytes_to_frames(substream->runtime, pipe->position);
- while (pos >= bufsize) {
- pipe->position -= frames_to_bytes(substream->runtime, bufsize);
- pos -= bufsize;
- }
- return pos;
- }
- /* pcm *_ops structures */
- static struct snd_pcm_ops analog_playback_ops = {
- .open = pcm_analog_out_open,
- .close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_analog_out_hw_params,
- .hw_free = pcm_hw_free,
- .prepare = pcm_prepare,
- .trigger = pcm_trigger,
- .pointer = pcm_pointer,
- .page = snd_pcm_sgbuf_ops_page,
- };
- static struct snd_pcm_ops analog_capture_ops = {
- .open = pcm_analog_in_open,
- .close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_analog_in_hw_params,
- .hw_free = pcm_hw_free,
- .prepare = pcm_prepare,
- .trigger = pcm_trigger,
- .pointer = pcm_pointer,
- .page = snd_pcm_sgbuf_ops_page,
- };
- #ifdef ECHOCARD_HAS_DIGITAL_IO
- #ifndef ECHOCARD_HAS_VMIXER
- static struct snd_pcm_ops digital_playback_ops = {
- .open = pcm_digital_out_open,
- .close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_digital_out_hw_params,
- .hw_free = pcm_hw_free,
- .prepare = pcm_prepare,
- .trigger = pcm_trigger,
- .pointer = pcm_pointer,
- .page = snd_pcm_sgbuf_ops_page,
- };
- #endif /* !ECHOCARD_HAS_VMIXER */
- static struct snd_pcm_ops digital_capture_ops = {
- .open = pcm_digital_in_open,
- .close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_digital_in_hw_params,
- .hw_free = pcm_hw_free,
- .prepare = pcm_prepare,
- .trigger = pcm_trigger,
- .pointer = pcm_pointer,
- .page = snd_pcm_sgbuf_ops_page,
- };
- #endif /* ECHOCARD_HAS_DIGITAL_IO */
- /* Preallocate memory only for the first substream because it's the most
- * used one
- */
- static int snd_echo_preallocate_pages(struct snd_pcm *pcm, struct device *dev)
- {
- struct snd_pcm_substream *ss;
- int stream, err;
- for (stream = 0; stream < 2; stream++)
- for (ss = pcm->streams[stream].substream; ss; ss = ss->next) {
- err = snd_pcm_lib_preallocate_pages(ss, SNDRV_DMA_TYPE_DEV_SG,
- dev,
- ss->number ? 0 : 128<<10,
- 256<<10);
- if (err < 0)
- return err;
- }
- return 0;
- }
- /*<--snd_echo_probe() */
- static int __devinit snd_echo_new_pcm(struct echoaudio *chip)
- {
- struct snd_pcm *pcm;
- int err;
- #ifdef ECHOCARD_HAS_VMIXER
- /* This card has a Vmixer, that is there is no direct mapping from PCM
- streams to physical outputs. The user can mix the streams as he wishes
- via control interface and it's possible to send any stream to any
- output, thus it makes no sense to keep analog and digital outputs
- separated */
- /* PCM#0 Virtual outputs and analog inputs */
- if ((err = snd_pcm_new(chip->card, "PCM", 0, num_pipes_out(chip),
- num_analog_busses_in(chip), &pcm)) < 0)
- return err;
- pcm->private_data = chip;
- chip->analog_pcm = pcm;
- strcpy(pcm->name, chip->card->shortname);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &analog_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops);
- if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
- return err;
- DE_INIT(("Analog PCM ok\n"));
- #ifdef ECHOCARD_HAS_DIGITAL_IO
- /* PCM#1 Digital inputs, no outputs */
- if ((err = snd_pcm_new(chip->card, "Digital PCM", 1, 0,
- num_digital_busses_in(chip), &pcm)) < 0)
- return err;
- pcm->private_data = chip;
- chip->digital_pcm = pcm;
- strcpy(pcm->name, chip->card->shortname);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops);
- if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
- return err;
- DE_INIT(("Digital PCM ok\n"));
- #endif /* ECHOCARD_HAS_DIGITAL_IO */
- #else /* ECHOCARD_HAS_VMIXER */
- /* The card can manage substreams formed by analog and digital channels
- at the same time, but I prefer to keep analog and digital channels
- separated, because that mixed thing is confusing and useless. So we
- register two PCM devices: */
- /* PCM#0 Analog i/o */
- if ((err = snd_pcm_new(chip->card, "Analog PCM", 0,
- num_analog_busses_out(chip),
- num_analog_busses_in(chip), &pcm)) < 0)
- return err;
- pcm->private_data = chip;
- chip->analog_pcm = pcm;
- strcpy(pcm->name, chip->card->shortname);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &analog_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops);
- if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
- return err;
- DE_INIT(("Analog PCM ok\n"));
- #ifdef ECHOCARD_HAS_DIGITAL_IO
- /* PCM#1 Digital i/o */
- if ((err = snd_pcm_new(chip->card, "Digital PCM", 1,
- num_digital_busses_out(chip),
- num_digital_busses_in(chip), &pcm)) < 0)
- return err;
- pcm->private_data = chip;
- chip->digital_pcm = pcm;
- strcpy(pcm->name, chip->card->shortname);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &digital_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops);
- if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
- return err;
- DE_INIT(("Digital PCM ok\n"));
- #endif /* ECHOCARD_HAS_DIGITAL_IO */
- #endif /* ECHOCARD_HAS_VMIXER */
- return 0;
- }
- /******************************************************************************
- Control interface
- ******************************************************************************/
- #if !defined(ECHOCARD_HAS_VMIXER) || defined(ECHOCARD_HAS_LINE_OUT_GAIN)
- /******************* PCM output volume *******************/
- static int snd_echo_output_gain_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
- {
- struct echoaudio *chip;
- chip = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = num_busses_out(chip);
- uinfo->value.integer.min = ECHOGAIN_MINOUT;
- uinfo->value.integer.max = ECHOGAIN_MAXOUT;
- return 0;
- }
- static int snd_echo_output_gain_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip;
- int c;
- chip = snd_kcontrol_chip(kcontrol);
- for (c = 0; c < num_busses_out(chip); c++)
- ucontrol->value.integer.value[c] = chip->output_gain[c];
- return 0;
- }
- static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip;
- int c, changed, gain;
- changed = 0;
- chip = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&chip->lock);
- for (c = 0; c < num_busses_out(chip); c++) {
- gain = ucontrol->value.integer.value[c];
- /* Ignore out of range values */
- if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT)
- continue;
- if (chip->output_gain[c] != gain) {
- set_output_gain(chip, c, gain);
- changed = 1;
- }
- }
- if (changed)
- update_output_line_level(chip);
- spin_unlock_irq(&chip->lock);
- return changed;
- }
- #ifdef ECHOCARD_HAS_LINE_OUT_GAIN
- /* On the Mia this one controls the line-out volume */
- static struct snd_kcontrol_new snd_echo_line_output_gain __devinitdata = {
- .name = "Line Playback Volume",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
- SNDRV_CTL_ELEM_ACCESS_TLV_READ,
- .info = snd_echo_output_gain_info,
- .get = snd_echo_output_gain_get,
- .put = snd_echo_output_gain_put,
- .tlv = {.p = db_scale_output_gain},
- };
- #else
- static struct snd_kcontrol_new snd_echo_pcm_output_gain __devinitdata = {
- .name = "PCM Playback Volume",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
- .info = snd_echo_output_gain_info,
- .get = snd_echo_output_gain_get,
- .put = snd_echo_output_gain_put,
- .tlv = {.p = db_scale_output_gain},
- };
- #endif
- #endif /* !ECHOCARD_HAS_VMIXER || ECHOCARD_HAS_LINE_OUT_GAIN */
- #ifdef ECHOCARD_HAS_INPUT_GAIN
- /******************* Analog input volume *******************/
- static int snd_echo_input_gain_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
- {
- struct echoaudio *chip;
- chip = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = num_analog_busses_in(chip);
- uinfo->value.integer.min = ECHOGAIN_MININP;
- uinfo->value.integer.max = ECHOGAIN_MAXINP;
- return 0;
- }
- static int snd_echo_input_gain_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip;
- int c;
- chip = snd_kcontrol_chip(kcontrol);
- for (c = 0; c < num_analog_busses_in(chip); c++)
- ucontrol->value.integer.value[c] = chip->input_gain[c];
- return 0;
- }
- static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip;
- int c, gain, changed;
- changed = 0;
- chip = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&chip->lock);
- for (c = 0; c < num_analog_busses_in(chip); c++) {
- gain = ucontrol->value.integer.value[c];
- /* Ignore out of range values */
- if (gain < ECHOGAIN_MININP || gain > ECHOGAIN_MAXINP)
- continue;
- if (chip->input_gain[c] != gain) {
- set_input_gain(chip, c, gain);
- changed = 1;
- }
- }
- if (changed)
- update_input_line_level(chip);
- spin_unlock_irq(&chip->lock);
- return changed;
- }
- static const DECLARE_TLV_DB_SCALE(db_scale_input_gain, -2500, 50, 0);
- static struct snd_kcontrol_new snd_echo_line_input_gain __devinitdata = {
- .name = "Line Capture Volume",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
- .info = snd_echo_input_gain_info,
- .get = snd_echo_input_gain_get,
- .put = snd_echo_input_gain_put,
- .tlv = {.p = db_scale_input_gain},
- };
- #endif /* ECHOCARD_HAS_INPUT_GAIN */
- #ifdef ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL
- /************ Analog output nominal level (+4dBu / -10dBV) ***************/
- static int snd_echo_output_nominal_info (struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
- {
- struct echoaudio *chip;
- chip = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = num_analog_busses_out(chip);
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
- }
- static int snd_echo_output_nominal_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip;
- int c;
- chip = snd_kcontrol_chip(kcontrol);
- for (c = 0; c < num_analog_busses_out(chip); c++)
- ucontrol->value.integer.value[c] = chip->nominal_level[c];
- return 0;
- }
- static int snd_echo_output_nominal_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip;
- int c, changed;
- changed = 0;
- chip = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&chip->lock);
- for (c = 0; c < num_analog_busses_out(chip); c++) {
- if (chip->nominal_level[c] != ucontrol->value.integer.value[c]) {
- set_nominal_level(chip, c,
- ucontrol->value.integer.value[c]);
- changed = 1;
- }
- }
- if (changed)
- update_output_line_level(chip);
- spin_unlock_irq(&chip->lock);
- return changed;
- }
- static struct snd_kcontrol_new snd_echo_output_nominal_level __devinitdata = {
- .name = "Line Playback Switch (-10dBV)",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .info = snd_echo_output_nominal_info,
- .get = snd_echo_output_nominal_get,
- .put = snd_echo_output_nominal_put,
- };
- #endif /* ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL */
- #ifdef ECHOCARD_HAS_INPUT_NOMINAL_LEVEL
- /*************** Analog input nominal level (+4dBu / -10dBV) ***************/
- static int snd_echo_input_nominal_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
- {
- struct echoaudio *chip;
- chip = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = num_analog_busses_in(chip);
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
- }
- static int snd_echo_input_nominal_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip;
- int c;
- chip = snd_kcontrol_chip(kcontrol);
- for (c = 0; c < num_analog_busses_in(chip); c++)
- ucontrol->value.integer.value[c] =
- chip->nominal_level[bx_analog_in(chip) + c];
- return 0;
- }
- static int snd_echo_input_nominal_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip;
- int c, changed;
- changed = 0;
- chip = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&chip->lock);
- for (c = 0; c < num_analog_busses_in(chip); c++) {
- if (chip->nominal_level[bx_analog_in(chip) + c] !=
- ucontrol->value.integer.value[c]) {
- set_nominal_level(chip, bx_analog_in(chip) + c,
- ucontrol->value.integer.value[c]);
- changed = 1;
- }
- }
- if (changed)
- update_output_line_level(chip); /* "Output" is not a mistake
- * here.
- */
- spin_unlock_irq(&chip->lock);
- return changed;
- }
- static struct snd_kcontrol_new snd_echo_intput_nominal_level __devinitdata = {
- .name = "Line Capture Switch (-10dBV)",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .info = snd_echo_input_nominal_info,
- .get = snd_echo_input_nominal_get,
- .put = snd_echo_input_nominal_put,
- };
- #endif /* ECHOCARD_HAS_INPUT_NOMINAL_LEVEL */
- #ifdef ECHOCARD_HAS_MONITOR
- /******************* Monitor mixer *******************/
- static int snd_echo_mixer_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
- {
- struct echoaudio *chip;
- chip = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = ECHOGAIN_MINOUT;
- uinfo->value.integer.max = ECHOGAIN_MAXOUT;
- uinfo->dimen.d[0] = num_busses_out(chip);
- uinfo->dimen.d[1] = num_busses_in(chip);
- return 0;
- }
- static int snd_echo_mixer_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip;
- chip = snd_kcontrol_chip(kcontrol);
- ucontrol->value.integer.value[0] =
- chip->monitor_gain[ucontrol->id.index / num_busses_in(chip)]
- [ucontrol->id.index % num_busses_in(chip)];
- return 0;
- }
- static int snd_echo_mixer_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip;
- int changed, gain;
- short out, in;
- changed = 0;
- chip = snd_kcontrol_chip(kcontrol);
- out = ucontrol->id.index / num_busses_in(chip);
- in = ucontrol->id.index % num_busses_in(chip);
- gain = ucontrol->value.integer.value[0];
- if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT)
- return -EINVAL;
- if (chip->monitor_gain[out][in] != gain) {
- spin_lock_irq(&chip->lock);
- set_monitor_gain(chip, out, in, gain);
- update_output_line_level(chip);
- spin_unlock_irq(&chip->lock);
- changed = 1;
- }
- return changed;
- }
- static struct snd_kcontrol_new snd_echo_monitor_mixer __devinitdata = {
- .name = "Monitor Mixer Volume",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
- .info = snd_echo_mixer_info,
- .get = snd_echo_mixer_get,
- .put = snd_echo_mixer_put,
- .tlv = {.p = db_scale_output_gain},
- };
- #endif /* ECHOCARD_HAS_MONITOR */
- #ifdef ECHOCARD_HAS_VMIXER
- /******************* Vmixer *******************/
- static int snd_echo_vmixer_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
- {
- struct echoaudio *chip;
- chip = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = ECHOGAIN_MINOUT;
- uinfo->value.integer.max = ECHOGAIN_MAXOUT;
- uinfo->dimen.d[0] = num_busses_out(chip);
- uinfo->dimen.d[1] = num_pipes_out(chip);
- return 0;
- }
- static int snd_echo_vmixer_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip;
- chip = snd_kcontrol_chip(kcontrol);
- ucontrol->value.integer.value[0] =
- chip->vmixer_gain[ucontrol->id.index / num_pipes_out(chip)]
- [ucontrol->id.index % num_pipes_out(chip)];
- return 0;
- }
- static int snd_echo_vmixer_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip;
- int gain, changed;
- short vch, out;
- changed = 0;
- chip = snd_kcontrol_chip(kcontrol);
- out = ucontrol->id.index / num_pipes_out(chip);
- vch = ucontrol->id.index % num_pipes_out(chip);
- gain = ucontrol->value.integer.value[0];
- if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT)
- return -EINVAL;
- if (chip->vmixer_gain[out][vch] != ucontrol->value.integer.value[0]) {
- spin_lock_irq(&chip->lock);
- set_vmixer_gain(chip, out, vch, ucontrol->value.integer.value[0]);
- update_vmixer_level(chip);
- spin_unlock_irq(&chip->lock);
- changed = 1;
- }
- return changed;
- }
- static struct snd_kcontrol_new snd_echo_vmixer __devinitdata = {
- .name = "VMixer Volume",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
- .info = snd_echo_vmixer_info,
- .get = snd_echo_vmixer_get,
- .put = snd_echo_vmixer_put,
- .tlv = {.p = db_scale_output_gain},
- };
- #endif /* ECHOCARD_HAS_VMIXER */
- #ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH
- /******************* Digital mode switch *******************/
- static int snd_echo_digital_mode_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
- {
- static char *names[4] = {
- "S/PDIF Coaxial", "S/PDIF Optical", "ADAT Optical",
- "S/PDIF Cdrom"
- };
- struct echoaudio *chip;
- chip = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->value.enumerated.items = chip->num_digital_modes;
- uinfo->count = 1;
- if (uinfo->value.enumerated.item >= chip->num_digital_modes)
- uinfo->value.enumerated.item = chip->num_digital_modes - 1;
- strcpy(uinfo->value.enumerated.name, names[
- chip->digital_mode_list[uinfo->value.enumerated.item]]);
- return 0;
- }
- static int snd_echo_digital_mode_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip;
- int i, mode;
- chip = snd_kcontrol_chip(kcontrol);
- mode = chip->digital_mode;
- for (i = chip->num_digital_modes - 1; i >= 0; i--)
- if (mode == chip->digital_mode_list[i]) {
- ucontrol->value.enumerated.item[0] = i;
- break;
- }
- return 0;
- }
- static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip;
- int changed;
- unsigned short emode, dmode;
- changed = 0;
- chip = snd_kcontrol_chip(kcontrol);
- emode = ucontrol->value.enumerated.item[0];
- if (emode >= chip->num_digital_modes)
- return -EINVAL;
- dmode = chip->digital_mode_list[emode];
- if (dmode != chip->digital_mode) {
- /* mode_mutex is required to make this operation atomic wrt
- pcm_digital_*_open() and set_input_clock() functions. */
- mutex_lock(&chip->mode_mutex);
- /* Do not allow the user to change the digital mode when a pcm
- device is open because it also changes the number of channels
- and the allowed sample rates */
- if (atomic_read(&chip->opencount)) {
- changed = -EAGAIN;
- } else {
- changed = set_digital_mode(chip, dmode);
- /* If we had to change the clock source, report it */
- if (changed > 0 && chip->clock_src_ctl) {
- snd_ctl_notify(chip->card,
- SNDRV_CTL_EVENT_MASK_VALUE,
- &chip->clock_src_ctl->id);
- DE_ACT(("SDM() =%d\n", changed));
- }
- if (changed >= 0)
- changed = 1; /* No errors */
- }
- mutex_unlock(&chip->mode_mutex);
- }
- return changed;
- }
- static struct snd_kcontrol_new snd_echo_digital_mode_switch __devinitdata = {
- .name = "Digital mode Switch",
- .iface = SNDRV_CTL_ELEM_IFACE_CARD,
- .info = snd_echo_digital_mode_info,
- .get = snd_echo_digital_mode_get,
- .put = snd_echo_digital_mode_put,
- };
- #endif /* ECHOCARD_HAS_DIGITAL_MODE_SWITCH */
- #ifdef ECHOCARD_HAS_DIGITAL_IO
- /******************* S/PDIF mode switch *******************/
- static int snd_echo_spdif_mode_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
- {
- static char *names[2] = {"Consumer", "Professional"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->value.enumerated.items = 2;
- uinfo->count = 1;
- if (uinfo->value.enumerated.item)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name,
- names[uinfo->value.enumerated.item]);
- return 0;
- }
- static int snd_echo_spdif_mode_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip;
- chip = snd_kcontrol_chip(kcontrol);
- ucontrol->value.enumerated.item[0] = !!chip->professional_spdif;
- return 0;
- }
- static int snd_echo_spdif_mode_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip;
- int mode;
- chip = snd_kcontrol_chip(kcontrol);
- mode = !!ucontrol->value.enumerated.item[0];
- if (mode != chip->professional_spdif) {
- spin_lock_irq(&chip->lock);
- set_professional_spdif(chip, mode);
- spin_unlock_irq(&chip->lock);
- return 1;
- }
- return 0;
- }
- static struct snd_kcontrol_new snd_echo_spdif_mode_switch __devinitdata = {
- .name = "S/PDIF mode Switch",
- .iface = SNDRV_CTL_ELEM_IFACE_CARD,
- .info = snd_echo_spdif_mode_info,
- .get = snd_echo_spdif_mode_get,
- .put = snd_echo_spdif_mode_put,
- };
- #endif /* ECHOCARD_HAS_DIGITAL_IO */
- #ifdef ECHOCARD_HAS_EXTERNAL_CLOCK
- /******************* Select input clock source *******************/
- static int snd_echo_clock_source_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
- {
- static char *names[8] = {
- "Internal", "Word", "Super", "S/PDIF", "ADAT", "ESync",
- "ESync96", "MTC"
- };
- struct echoaudio *chip;
- chip = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->value.enumerated.items = chip->num_clock_sources;
- uinfo->count = 1;
- if (uinfo->value.enumerated.item >= chip->num_clock_sources)
- uinfo->value.enumerated.item = chip->num_clock_sources - 1;
- strcpy(uinfo->value.enumerated.name, names[
- chip->clock_source_list[uinfo->value.enumerated.item]]);
- return 0;
- }
- static int snd_echo_clock_source_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip;
- int i, clock;
- chip = snd_kcontrol_chip(kcontrol);
- clock = chip->input_clock;
- for (i = 0; i < chip->num_clock_sources; i++)
- if (clock == chip->clock_source_list[i])
- ucontrol->value.enumerated.item[0] = i;
- return 0;
- }
- static int snd_echo_clock_source_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip;
- int changed;
- unsigned int eclock, dclock;
- changed = 0;
- chip = snd_kcontrol_chip(kcontrol);
- eclock = ucontrol->value.enumerated.item[0];
- if (eclock >= chip->input_clock_types)
- return -EINVAL;
- dclock = chip->clock_source_list[eclock];
- if (chip->input_clock != dclock) {
- mutex_lock(&chip->mode_mutex);
- spin_lock_irq(&chip->lock);
- if ((changed = set_input_clock(chip, dclock)) == 0)
- changed = 1; /* no errors */
- spin_unlock_irq(&chip->lock);
- mutex_unlock(&chip->mode_mutex);
- }
- if (changed < 0)
- DE_ACT(("seticlk val%d err 0x%x\n", dclock, changed));
- return changed;
- }
- static struct snd_kcontrol_new snd_echo_clock_source_switch __devinitdata = {
- .name = "Sample Clock Source",
- .iface = SNDRV_CTL_ELEM_IFACE_PCM,
- .info = snd_echo_clock_source_info,
- .get = snd_echo_clock_source_get,
- .put = snd_echo_clock_source_put,
- };
- #endif /* ECHOCARD_HAS_EXTERNAL_CLOCK */
- #ifdef ECHOCARD_HAS_PHANTOM_POWER
- /******************* Phantom power switch *******************/
- #define snd_echo_phantom_power_info snd_ctl_boolean_mono_info
- static int snd_echo_phantom_power_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip = snd_kcontrol_chip(kcontrol);
- ucontrol->value.integer.value[0] = chip->phantom_power;
- return 0;
- }
- static int snd_echo_phantom_power_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip = snd_kcontrol_chip(kcontrol);
- int power, changed = 0;
- power = !!ucontrol->value.integer.value[0];
- if (chip->phantom_power != power) {
- spin_lock_irq(&chip->lock);
- changed = set_phantom_power(chip, power);
- spin_unlock_irq(&chip->lock);
- if (changed == 0)
- changed = 1; /* no errors */
- }
- return changed;
- }
- static struct snd_kcontrol_new snd_echo_phantom_power_switch __devinitdata = {
- .name = "Phantom power Switch",
- .iface = SNDRV_CTL_ELEM_IFACE_CARD,
- .info = snd_echo_phantom_power_info,
- .get = snd_echo_phantom_power_get,
- .put = snd_echo_phantom_power_put,
- };
- #endif /* ECHOCARD_HAS_PHANTOM_POWER */
- #ifdef ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE
- /******************* Digital input automute switch *******************/
- #define snd_echo_automute_info snd_ctl_boolean_mono_info
- static int snd_echo_automute_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip = snd_kcontrol_chip(kcontrol);
- ucontrol->value.integer.value[0] = chip->digital_in_automute;
- return 0;
- }
- static int snd_echo_automute_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip = snd_kcontrol_chip(kcontrol);
- int automute, changed = 0;
- automute = !!ucontrol->value.integer.value[0];
- if (chip->digital_in_automute != automute) {
- spin_lock_irq(&chip->lock);
- changed = set_input_auto_mute(chip, automute);
- spin_unlock_irq(&chip->lock);
- if (changed == 0)
- changed = 1; /* no errors */
- }
- return changed;
- }
- static struct snd_kcontrol_new snd_echo_automute_switch __devinitdata = {
- .name = "Digital Capture Switch (automute)",
- .iface = SNDRV_CTL_ELEM_IFACE_CARD,
- .info = snd_echo_automute_info,
- .get = snd_echo_automute_get,
- .put = snd_echo_automute_put,
- };
- #endif /* ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE */
- /******************* VU-meters switch *******************/
- #define snd_echo_vumeters_switch_info snd_ctl_boolean_mono_info
- static int snd_echo_vumeters_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip;
- chip = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&chip->lock);
- set_meters_on(chip, ucontrol->value.integer.value[0]);
- spin_unlock_irq(&chip->lock);
- return 1;
- }
- static struct snd_kcontrol_new snd_echo_vumeters_switch __devinitdata = {
- .name = "VU-meters Switch",
- .iface = SNDRV_CTL_ELEM_IFACE_CARD,
- .access = SNDRV_CTL_ELEM_ACCESS_WRITE,
- .info = snd_echo_vumeters_switch_info,
- .put = snd_echo_vumeters_switch_put,
- };
- /***** Read VU-meters (input, output, analog and digital together) *****/
- static int snd_echo_vumeters_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
- {
- struct echoaudio *chip;
- chip = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 96;
- uinfo->value.integer.min = ECHOGAIN_MINOUT;
- uinfo->value.integer.max = 0;
- #ifdef ECHOCARD_HAS_VMIXER
- uinfo->dimen.d[0] = 3; /* Out, In, Virt */
- #else
- uinfo->dimen.d[0] = 2; /* Out, In */
- #endif
- uinfo->dimen.d[1] = 16; /* 16 channels */
- uinfo->dimen.d[2] = 2; /* 0=level, 1=peak */
- return 0;
- }
- static int snd_echo_vumeters_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip;
- chip = snd_kcontrol_chip(kcontrol);
- get_audio_meters(chip, ucontrol->value.integer.value);
- return 0;
- }
- static struct snd_kcontrol_new snd_echo_vumeters __devinitdata = {
- .name = "VU-meters",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .access = SNDRV_CTL_ELEM_ACCESS_READ |
- SNDRV_CTL_ELEM_ACCESS_VOLATILE |
- SNDRV_CTL_ELEM_ACCESS_TLV_READ,
- .info = snd_echo_vumeters_info,
- .get = snd_echo_vumeters_get,
- .tlv = {.p = db_scale_output_gain},
- };
- /*** Channels info - it exports informations about the number of channels ***/
- static int snd_echo_channels_info_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
- {
- struct echoaudio *chip;
- chip = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 6;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1 << ECHO_CLOCK_NUMBER;
- return 0;
- }
- static int snd_echo_channels_info_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- struct echoaudio *chip;
- int detected, clocks, bit, src;
- chip = snd_kcontrol_chip(kcontrol);
- ucontrol->value.integer.value[0] = num_busses_in(chip);
- ucontrol->value.integer.value[1] = num_analog_busses_in(chip);
- ucontrol->value.integer.value[2] = num_busses_out(chip);
- ucontrol->value.integer.value[3] = num_analog_busses_out(chip);
- ucontrol->value.integer.value[4] = num_pipes_out(chip);
- /* Compute the bitmask of the currently valid input clocks */
- detected = detect_input_clocks(chip);
- clocks = 0;
- src = chip->num_clock_sources - 1;
- for (bit = ECHO_CLOCK_NUMBER - 1; bit >= 0; bit--)
- if (detected & (1 << bit))
- for (; src >= 0; src--)
- if (bit == chip->clock_source_list[src]) {
- clocks |= 1 << src;
- break;
- }
- ucontrol->value.integer.value[5] = clocks;
- return 0;
- }
- static struct snd_kcontrol_new snd_echo_channels_info __devinitdata = {
- .name = "Channels info",
- .iface = SNDRV_CTL_ELEM_IFACE_HWDEP,
- .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
- .info = snd_echo_channels_info_info,
- .get = snd_echo_channels_info_get,
- };
- /******************************************************************************
- IRQ Handler
- ******************************************************************************/
- static irqreturn_t snd_echo_interrupt(int irq, void *dev_id)
- {
- struct echoaudio *chip = dev_id;
- struct snd_pcm_substream *substream;
- int period, ss, st;
- spin_lock(&chip->lock);
- st = service_irq(chip);
- if (st < 0) {
- spin_unlock(&chip->lock);
- return IRQ_NONE;
- }
- /* The hardware doesn't tell us which substream caused the irq,
- thus we have to check all running substreams. */
- for (ss = 0; ss < DSP_MAXPIPES; ss++) {
- substream = chip->substream[ss];
- if (substream && ((struct audiopipe *)substream->runtime->
- private_data)->state == PIPE_STATE_STARTED) {
- period = pcm_pointer(substream) /
- substream->runtime->period_size;
- if (period != chip->last_period[ss]) {
- chip->last_period[ss] = period;
- spin_unlock(&chip->lock);
- snd_pcm_period_elapsed(substream);
- spin_lock(&chip->lock);
- }
- }
- }
- spin_unlock(&chip->lock);
- #ifdef ECHOCARD_HAS_MIDI
- if (st > 0 && chip->midi_in) {
- snd_rawmidi_receive(chip->midi_in, chip->midi_buffer, st);
- DE_MID(("rawmidi_iread=%d\n", st));
- }
- #endif
- return IRQ_HANDLED;
- }
- /******************************************************************************
- Module construction / destruction
- ******************************************************************************/
- static int snd_echo_free(struct echoaudio *chip)
- {
- DE_INIT(("Stop DSP...\n"));
- if (chip->comm_page)
- rest_in_peace(chip);
- DE_INIT(("Stopped.\n"));
- if (chip->irq >= 0)
- free_irq(chip->irq, chip);
- if (chip->comm_page)
- snd_dma_free_pages(&chip->commpage_dma_buf);
- if (chip->dsp_registers)
- iounmap(chip->dsp_registers);
- if (chip->iores)
- release_and_free_resource(chip->iores);
- DE_INIT(("MMIO freed.\n"));
- pci_disable_device(chip->pci);
- /* release chip data */
- free_firmware_cache(chip);
- kfree(chip);
- DE_INIT(("Chip freed.\n"));
- return 0;
- }
- static int snd_echo_dev_free(struct snd_device *device)
- {
- struct echoaudio *chip = device->device_data;
- DE_INIT(("snd_echo_dev_free()...\n"));
- return snd_echo_free(chip);
- }
- /* <--snd_echo_probe() */
- static __devinit int snd_echo_create(struct snd_card *card,
- struct pci_dev *pci,
- struct echoaudio **rchip)
- {
- struct echoaudio *chip;
- int err;
- size_t sz;
- static struct snd_device_ops ops = {
- .dev_free = snd_echo_dev_free,
- };
- *rchip = NULL;
- pci_write_config_byte(pci, PCI_LATENCY_TIMER, 0xC0);
- if ((err = pci_enable_device(pci)) < 0)
- return err;
- pci_set_master(pci);
- /* Allocate chip if needed */
- if (!*rchip) {
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
- if (!chip) {
- pci_disable_device(pci);
- return -ENOMEM;
- }
- DE_INIT(("chip=%p\n", chip));
- spin_lock_init(&chip->lock);
- chip->card = card;
- chip->pci = pci;
- chip->irq = -1;
- atomic_set(&chip->opencount, 0);
- mutex_init(&chip->mode_mutex);
- chip->can_set_rate = 1;
- } else {
- /* If this was called from the resume function, chip is
- * already allocated and it contains current card settings.
- */
- chip = *rchip;
- }
- /* PCI resource allocation */
- chip->dsp_registers_phys = pci_resource_start(pci, 0);
- sz = pci_resource_len(pci, 0);
- if (sz > PAGE_SIZE)
- sz = PAGE_SIZE; /* We map only the required part */
- if ((chip->iores = request_mem_region(chip->dsp_registers_phys, sz,
- ECHOCARD_NAME)) == NULL) {
- snd_echo_free(chip);
- snd_printk(KERN_ERR "cannot get memory region\n");
- return -EBUSY;
- }
- chip->dsp_registers = (volatile u32 __iomem *)
- ioremap_nocache(chip->dsp_registers_phys, sz);
- if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED,
- KBUILD_MODNAME, chip)) {
- snd_echo_free(chip);
- snd_printk(KERN_ERR "cannot grab irq\n");
- return -EBUSY;
- }
- chip->irq = pci->irq;
- DE_INIT(("pci=%p irq=%d subdev=%04x Init hardware...\n",
- chip->pci, chip->irq, chip->pci->subsystem_device));
- /* Create the DSP comm page - this is the area of memory used for most
- of the communication with the DSP, which accesses it via bus mastering */
- if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
- sizeof(struct comm_page),
- &chip->commpage_dma_buf) < 0) {
- snd_echo_free(chip);
- snd_printk(KERN_ERR "cannot allocate the comm page\n");
- return -ENOMEM;
- }
- chip->comm_page_phys = chip->commpage_dma_buf.addr;
- chip->comm_page = (struct comm_page *)chip->commpage_dma_buf.area;
- err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device);
- if (err >= 0)
- err = set_mixer_defaults(chip);
- if (err < 0) {
- DE_INIT(("init_hw err=%d\n", err));
- snd_echo_free(chip);
- return err;
- }
- DE_INIT(("Card init OK\n"));
- if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
- snd_echo_free(chip);
- return err;
- }
- *rchip = chip;
- /* Init done ! */
- return 0;
- }
- /* constructor */
- static int __devinit snd_echo_probe(struct pci_dev *pci,
- const struct pci_device_id *pci_id)
- {
- static int dev;
- struct snd_card *card;
- struct echoaudio *chip;
- char *dsp;
- int i, err;
- if (dev >= SNDRV_CARDS)
- return -ENODEV;
- if (!enable[dev]) {
- dev++;
- return -ENOENT;
- }
- DE_INIT(("Echoaudio driver starting...\n"));
- i = 0;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
- if (err < 0)
- return err;
- snd_card_set_dev(card, &pci->dev);
- chip = NULL; /* Tells snd_echo_create to allocate chip */
- if ((err = snd_echo_create(card, pci, &chip)) < 0) {
- snd_card_free(card);
- return err;
- }
- strcpy(card->driver, "Echo_" ECHOCARD_NAME);
- strcpy(card->shortname, chip->card_name);
- dsp = "56301";
- if (pci_id->device == 0x3410)
- dsp = "56361";
- sprintf(card->longname, "%s rev.%d (DSP%s) at 0x%lx irq %i",
- card->shortname, pci_id->subdevice & 0x000f, dsp,
- chip->dsp_registers_phys, chip->irq);
- if ((err = snd_echo_new_pcm(chip)) < 0) {
- snd_printk(KERN_ERR "new pcm error %d\n", err);
- snd_card_free(card);
- return err;
- }
- #ifdef ECHOCARD_HAS_MIDI
- if (chip->has_midi) { /* Some Mia's do not have midi */
- if ((err = snd_echo_midi_create(card, chip)) < 0) {
- snd_printk(KERN_ERR "new midi error %d\n", err);
- snd_card_free(card);
- return err;
- }
- }
- #endif
- #ifdef ECHOCARD_HAS_VMIXER
- snd_echo_vmixer.count = num_pipes_out(chip) * num_busses_out(chip);
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vmixer, chip))) < 0)
- goto ctl_error;
- #ifdef ECHOCARD_HAS_LINE_OUT_GAIN
- err = snd_ctl_add(chip->card,
- snd_ctl_new1(&snd_echo_line_output_gain, chip));
- if (err < 0)
- goto ctl_error;
- #endif
- #else /* ECHOCARD_HAS_VMIXER */
- err = snd_ctl_add(chip->card,
- snd_ctl_new1(&snd_echo_pcm_output_gain, chip));
- if (err < 0)
- goto ctl_error;
- #endif /* ECHOCARD_HAS_VMIXER */
- #ifdef ECHOCARD_HAS_INPUT_GAIN
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_line_input_gain, chip))) < 0)
- goto ctl_error;
- #endif
- #ifdef ECHOCARD_HAS_INPUT_NOMINAL_LEVEL
- if (!chip->hasnt_input_nominal_level)
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_intput_nominal_level, chip))) < 0)
- goto ctl_error;
- #endif
- #ifdef ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_output_nominal_level, chip))) < 0)
- goto ctl_error;
- #endif
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vumeters_switch, chip))) < 0)
- goto ctl_error;
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vumeters, chip))) < 0)
- goto ctl_error;
- #ifdef ECHOCARD_HAS_MONITOR
- snd_echo_monitor_mixer.count = num_busses_in(chip) * num_busses_out(chip);
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_monitor_mixer, chip))) < 0)
- goto ctl_error;
- #endif
- #ifdef ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_automute_switch, chip))) < 0)
- goto ctl_error;
- #endif
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_channels_info, chip))) < 0)
- goto ctl_error;
- #ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH
- /* Creates a list of available digital modes */
- chip->num_digital_modes = 0;
- for (i = 0; i < 6; i++)
- if (chip->digital_modes & (1 << i))
- chip->digital_mode_list[chip->num_digital_modes++] = i;
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_digital_mode_switch, chip))) < 0)
- goto ctl_error;
- #endif /* ECHOCARD_HAS_DIGITAL_MODE_SWITCH */
- #ifdef ECHOCARD_HAS_EXTERNAL_CLOCK
- /* Creates a list of available clock sources */
- chip->num_clock_sources = 0;
- for (i = 0; i < 10; i++)
- if (chip->input_clock_types & (1 << i))
- chip->clock_source_list[chip->num_clock_sources++] = i;
- if (chip->num_clock_sources > 1) {
- chip->clock_src_ctl = snd_ctl_new1(&snd_echo_clock_source_switch, chip);
- if ((err = snd_ctl_add(chip->card, chip->clock_src_ctl)) < 0)
- goto ctl_error;
- }
- #endif /* ECHOCARD_HAS_EXTERNAL_CLOCK */
- #ifdef ECHOCARD_HAS_DIGITAL_IO
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_spdif_mode_switch, chip))) < 0)
- goto ctl_error;
- #endif
- #ifdef ECHOCARD_HAS_PHANTOM_POWER
- if (chip->has_phantom_power)
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_phantom_power_switch, chip))) < 0)
- goto ctl_error;
- #endif
- err = snd_card_register(card);
- if (err < 0)
- goto ctl_error;
- snd_printk(KERN_INFO "Card registered: %s\n", card->longname);
- pci_set_drvdata(pci, chip);
- dev++;
- return 0;
- ctl_error:
- snd_printk(KERN_ERR "new control error %d\n", err);
- snd_card_free(card);
- return err;
- }
- #if defined(CONFIG_PM)
- static int snd_echo_suspend(struct pci_dev *pci, pm_message_t state)
- {
- struct echoaudio *chip = pci_get_drvdata(pci);
- DE_INIT(("suspend start\n"));
- snd_pcm_suspend_all(chip->analog_pcm);
- snd_pcm_suspend_all(chip->digital_pcm);
- #ifdef ECHOCARD_HAS_MIDI
- /* This call can sleep */
- if (chip->midi_out)
- snd_echo_midi_output_trigger(chip->midi_out, 0);
- #endif
- spin_lock_irq(&chip->lock);
- if (wait_handshake(chip)) {
- spin_unlock_irq(&chip->lock);
- return -EIO;
- }
- clear_handshake(chip);
- if (send_vector(chip, DSP_VC_GO_COMATOSE) < 0) {
- spin_unlock_irq(&chip->lock);
- return -EIO;
- }
- spin_unlock_irq(&chip->lock);
- chip->dsp_code = NULL;
- free_irq(chip->irq, chip);
- chip->irq = -1;
- pci_save_state(pci);
- pci_disable_device(pci);
- DE_INIT(("suspend done\n"));
- return 0;
- }
- static int snd_echo_resume(struct pci_dev *pci)
- {
- struct echoaudio *chip = pci_get_drvdata(pci);
- struct comm_page *commpage, *commpage_bak;
- u32 pipe_alloc_mask;
- int err;
- DE_INIT(("resume start\n"));
- pci_restore_state(pci);
- commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL);
- if (commpage_bak == NULL)
- return -ENOMEM;
- commpage = chip->comm_page;
- memcpy(commpage_bak, commpage, sizeof(struct comm_page));
- err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device);
- if (err < 0) {
- kfree(commpage_bak);
- DE_INIT(("resume init_hw err=%d\n", err));
- snd_echo_free(chip);
- return err;
- }
- DE_INIT(("resume init OK\n"));
- /* Temporarily set chip->pipe_alloc_mask=0 otherwise
- * restore_dsp_settings() fails.
- */
- pipe_alloc_mask = chip->pipe_alloc_mask;
- chip->pipe_alloc_mask = 0;
- err = restore_dsp_rettings(chip);
- chip->pipe_alloc_mask = pipe_alloc_mask;
- if (err < 0) {
- kfree(commpage_bak);
- return err;
- }
- DE_INIT(("resume restore OK\n"));
- memcpy(&commpage->audio_format, &commpage_bak->audio_format,
- sizeof(commpage->audio_format));
- memcpy(&commpage->sglist_addr, &commpage_bak->sglist_addr,
- sizeof(commpage->sglist_addr));
- memcpy(&commpage->midi_output, &commpage_bak->midi_output,
- sizeof(commpage->midi_output));
- kfree(commpage_bak);
- if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED,
- KBUILD_MODNAME, chip)) {
- snd_echo_free(chip);
- snd_printk(KERN_ERR "cannot grab irq\n");
- return -EBUSY;
- }
- chip->irq = pci->irq;
- DE_INIT(("resume irq=%d\n", chip->irq));
- #ifdef ECHOCARD_HAS_MIDI
- if (chip->midi_input_enabled)
- enable_midi_input(chip, TRUE);
- if (chip->midi_out)
- snd_echo_midi_output_trigger(chip->midi_out, 1);
- #endif
- DE_INIT(("resume done\n"));
- return 0;
- }
- #endif /* CONFIG_PM */
- static void __devexit snd_echo_remove(struct pci_dev *pci)
- {
- struct echoaudio *chip;
- chip = pci_get_drvdata(pci);
- if (chip)
- snd_card_free(chip->card);
- pci_set_drvdata(pci, NULL);
- }
- /******************************************************************************
- Everything starts and ends here
- ******************************************************************************/
- /* pci_driver definition */
- static struct pci_driver driver = {
- .name = KBUILD_MODNAME,
- .id_table = snd_echo_ids,
- .probe = snd_echo_probe,
- .remove = __devexit_p(snd_echo_remove),
- #ifdef CONFIG_PM
- .suspend = snd_echo_suspend,
- .resume = snd_echo_resume,
- #endif /* CONFIG_PM */
- };
- /* initialization of the module */
- static int __init alsa_card_echo_init(void)
- {
- return pci_register_driver(&driver);
- }
- /* clean up the module */
- static void __exit alsa_card_echo_exit(void)
- {
- pci_unregister_driver(&driver);
- }
- module_init(alsa_card_echo_init)
- module_exit(alsa_card_echo_exit)
|