123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561 |
- /* $OpenBSD: gus.c,v 1.43 2015/06/25 20:05:11 ratchov Exp $ */
- /* $NetBSD: gus.c,v 1.51 1998/01/25 23:48:06 mycroft Exp $ */
- /*-
- * Copyright (c) 1996 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Ken Hornstein and John Kohl.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
- /*
- *
- * TODO:
- * . figure out why mixer activity while sound is playing causes problems
- * (phantom interrupts?)
- * . figure out a better deinterleave strategy that avoids sucking up
- * CPU, memory and cache bandwidth. (Maybe a special encoding?
- * Maybe use the double-speed sampling/hardware deinterleave trick
- * from the GUS SDK?) A 486/33 isn't quite fast enough to keep
- * up with 44.1kHz 16-bit stereo output without some drop-outs.
- * . use CS4231 for 16-bit sampling, for a-law and mu-law playback.
- * . actually test full-duplex sampling(recording) and playback.
- */
- /*
- * Gravis UltraSound driver
- *
- * For more detailed information, see the GUS developers' kit
- * available on the net at:
- *
- * http://www.gravis.com/Public/sdk/GUSDK222.ZIP
- *
- * See ultrawrd.doc inside--it's MS Word (ick), but it's the bible
- *
- */
- /*
- * The GUS Max has a slightly strange set of connections between the CS4231
- * and the GF1 and the DMA interconnects. It's set up so that the CS4231 can
- * be playing while the GF1 is loading patches from the system.
- *
- * Here's a recreation of the DMA interconnect diagram:
- *
- * GF1
- * +---------+ digital
- * | | record ASIC
- * | |--------------+
- * | | | +--------+
- * | | play (dram) | +----+ | |
- * | |--------------(------|-\ | | +-+ |
- * +---------+ | | >-|----|---|C|--|------ dma chan 1
- * | +---|-/ | | +-+ |
- * | | +----+ | | |
- * | | +----+ | | |
- * +---------+ +-+ +--(---|-\ | | | |
- * | | play |8| | | >-|----|----+---|------ dma chan 2
- * | ---C----|--------|/|------(---|-/ | | |
- * | ^ |record |1| | +----+ | |
- * | | | /----|6|------+ +--------+
- * | ---+----|--/ +-+
- * +---------+
- * CS4231 8-to-16 bit bus conversion, if needed
- *
- *
- * "C" is an optional combiner.
- *
- */
- #include <sys/param.h>
- #include <sys/systm.h>
- #include <sys/errno.h>
- #include <sys/ioctl.h>
- #include <sys/syslog.h>
- #include <sys/device.h>
- #include <sys/buf.h>
- #include <sys/fcntl.h>
- #include <sys/malloc.h>
- #include <sys/kernel.h>
- #include <sys/timeout.h>
- #include <machine/cpu.h>
- #include <machine/intr.h>
- #include <machine/bus.h>
- #include <machine/cpufunc.h>
- #include <sys/audioio.h>
- #include <dev/audio_if.h>
- #include <dev/isa/isavar.h>
- #include <dev/isa/isadmavar.h>
- #include <dev/ic/ics2101reg.h>
- #include <dev/ic/cs4231reg.h>
- #include <dev/ic/ad1848reg.h>
- #include <dev/isa/ics2101var.h>
- #include <dev/isa/ad1848var.h>
- #include <dev/isa/cs4231var.h>
- #include "gusreg.h"
- #include "gusvar.h"
- #ifdef AUDIO_DEBUG
- #define GUSPLAYDEBUG /*XXX*/
- #define DPRINTF(x) if (gusdebug) printf x
- #define DMAPRINTF(x) if (gusdmadebug) printf x
- int gusdebug = 0;
- int gusdmadebug = 0;
- #else
- #define DPRINTF(x)
- #define DMAPRINTF(x)
- #endif
- int gus_dostereo = 1;
- #define NDMARECS 2048
- #ifdef GUSPLAYDEBUG
- int gusstats = 0;
- struct dma_record dmarecords[NDMARECS];
- int dmarecord_index = 0;
- #endif
- struct cfdriver gus_cd = {
- NULL, "gus", DV_DULL
- };
- /*
- * A mapping from IRQ/DRQ values to the values used in the GUS's internal
- * registers. A zero means that the referenced IRQ/DRQ is invalid
- */
- const int gus_irq_map[] = {
- IRQUNK, IRQUNK, 1, 3, IRQUNK, 2, IRQUNK, 4, IRQUNK, 1, IRQUNK, 5, 6,
- IRQUNK, IRQUNK, 7
- };
- const int gus_drq_map[] = {
- DRQUNK, 1, DRQUNK, 2, DRQUNK, 3, 4, 5
- };
- /*
- * A list of valid base addresses for the GUS
- */
- const int gus_base_addrs[] = {
- 0x210, 0x220, 0x230, 0x240, 0x250, 0x260
- };
- const int gus_addrs = sizeof(gus_base_addrs) / sizeof(gus_base_addrs[0]);
- /*
- * Maximum frequency values of the GUS based on the number of currently active
- * voices. Since the GUS samples a voice every 1.6 us, the maximum frequency
- * is dependent on the number of active voices. Yes, it is pretty weird.
- */
- static const int gus_max_frequency[] = {
- 44100, /* 14 voices */
- 41160, /* 15 voices */
- 38587, /* 16 voices */
- 36317, /* 17 voices */
- 34300, /* 18 voices */
- 32494, /* 19 voices */
- 30870, /* 20 voices */
- 29400, /* 21 voices */
- 28063, /* 22 voices */
- 26843, /* 23 voices */
- 25725, /* 24 voices */
- 24696, /* 25 voices */
- 23746, /* 26 voices */
- 22866, /* 27 voices */
- 22050, /* 28 voices */
- 21289, /* 29 voices */
- 20580, /* 30 voices */
- 19916, /* 31 voices */
- 19293 /* 32 voices */
- };
- /*
- * A mapping of linear volume levels to the logarithmic volume values used
- * by the GF1 chip on the GUS. From GUS SDK vol1.c.
- */
- static const unsigned short gus_log_volumes[512] = {
- 0x0000,
- 0x0700, 0x07ff, 0x0880, 0x08ff, 0x0940, 0x0980, 0x09c0, 0x09ff, 0x0a20,
- 0x0a40, 0x0a60, 0x0a80, 0x0aa0, 0x0ac0, 0x0ae0, 0x0aff, 0x0b10, 0x0b20,
- 0x0b30, 0x0b40, 0x0b50, 0x0b60, 0x0b70, 0x0b80, 0x0b90, 0x0ba0, 0x0bb0,
- 0x0bc0, 0x0bd0, 0x0be0, 0x0bf0, 0x0bff, 0x0c08, 0x0c10, 0x0c18, 0x0c20,
- 0x0c28, 0x0c30, 0x0c38, 0x0c40, 0x0c48, 0x0c50, 0x0c58, 0x0c60, 0x0c68,
- 0x0c70, 0x0c78, 0x0c80, 0x0c88, 0x0c90, 0x0c98, 0x0ca0, 0x0ca8, 0x0cb0,
- 0x0cb8, 0x0cc0, 0x0cc8, 0x0cd0, 0x0cd8, 0x0ce0, 0x0ce8, 0x0cf0, 0x0cf8,
- 0x0cff, 0x0d04, 0x0d08, 0x0d0c, 0x0d10, 0x0d14, 0x0d18, 0x0d1c, 0x0d20,
- 0x0d24, 0x0d28, 0x0d2c, 0x0d30, 0x0d34, 0x0d38, 0x0d3c, 0x0d40, 0x0d44,
- 0x0d48, 0x0d4c, 0x0d50, 0x0d54, 0x0d58, 0x0d5c, 0x0d60, 0x0d64, 0x0d68,
- 0x0d6c, 0x0d70, 0x0d74, 0x0d78, 0x0d7c, 0x0d80, 0x0d84, 0x0d88, 0x0d8c,
- 0x0d90, 0x0d94, 0x0d98, 0x0d9c, 0x0da0, 0x0da4, 0x0da8, 0x0dac, 0x0db0,
- 0x0db4, 0x0db8, 0x0dbc, 0x0dc0, 0x0dc4, 0x0dc8, 0x0dcc, 0x0dd0, 0x0dd4,
- 0x0dd8, 0x0ddc, 0x0de0, 0x0de4, 0x0de8, 0x0dec, 0x0df0, 0x0df4, 0x0df8,
- 0x0dfc, 0x0dff, 0x0e02, 0x0e04, 0x0e06, 0x0e08, 0x0e0a, 0x0e0c, 0x0e0e,
- 0x0e10, 0x0e12, 0x0e14, 0x0e16, 0x0e18, 0x0e1a, 0x0e1c, 0x0e1e, 0x0e20,
- 0x0e22, 0x0e24, 0x0e26, 0x0e28, 0x0e2a, 0x0e2c, 0x0e2e, 0x0e30, 0x0e32,
- 0x0e34, 0x0e36, 0x0e38, 0x0e3a, 0x0e3c, 0x0e3e, 0x0e40, 0x0e42, 0x0e44,
- 0x0e46, 0x0e48, 0x0e4a, 0x0e4c, 0x0e4e, 0x0e50, 0x0e52, 0x0e54, 0x0e56,
- 0x0e58, 0x0e5a, 0x0e5c, 0x0e5e, 0x0e60, 0x0e62, 0x0e64, 0x0e66, 0x0e68,
- 0x0e6a, 0x0e6c, 0x0e6e, 0x0e70, 0x0e72, 0x0e74, 0x0e76, 0x0e78, 0x0e7a,
- 0x0e7c, 0x0e7e, 0x0e80, 0x0e82, 0x0e84, 0x0e86, 0x0e88, 0x0e8a, 0x0e8c,
- 0x0e8e, 0x0e90, 0x0e92, 0x0e94, 0x0e96, 0x0e98, 0x0e9a, 0x0e9c, 0x0e9e,
- 0x0ea0, 0x0ea2, 0x0ea4, 0x0ea6, 0x0ea8, 0x0eaa, 0x0eac, 0x0eae, 0x0eb0,
- 0x0eb2, 0x0eb4, 0x0eb6, 0x0eb8, 0x0eba, 0x0ebc, 0x0ebe, 0x0ec0, 0x0ec2,
- 0x0ec4, 0x0ec6, 0x0ec8, 0x0eca, 0x0ecc, 0x0ece, 0x0ed0, 0x0ed2, 0x0ed4,
- 0x0ed6, 0x0ed8, 0x0eda, 0x0edc, 0x0ede, 0x0ee0, 0x0ee2, 0x0ee4, 0x0ee6,
- 0x0ee8, 0x0eea, 0x0eec, 0x0eee, 0x0ef0, 0x0ef2, 0x0ef4, 0x0ef6, 0x0ef8,
- 0x0efa, 0x0efc, 0x0efe, 0x0eff, 0x0f01, 0x0f02, 0x0f03, 0x0f04, 0x0f05,
- 0x0f06, 0x0f07, 0x0f08, 0x0f09, 0x0f0a, 0x0f0b, 0x0f0c, 0x0f0d, 0x0f0e,
- 0x0f0f, 0x0f10, 0x0f11, 0x0f12, 0x0f13, 0x0f14, 0x0f15, 0x0f16, 0x0f17,
- 0x0f18, 0x0f19, 0x0f1a, 0x0f1b, 0x0f1c, 0x0f1d, 0x0f1e, 0x0f1f, 0x0f20,
- 0x0f21, 0x0f22, 0x0f23, 0x0f24, 0x0f25, 0x0f26, 0x0f27, 0x0f28, 0x0f29,
- 0x0f2a, 0x0f2b, 0x0f2c, 0x0f2d, 0x0f2e, 0x0f2f, 0x0f30, 0x0f31, 0x0f32,
- 0x0f33, 0x0f34, 0x0f35, 0x0f36, 0x0f37, 0x0f38, 0x0f39, 0x0f3a, 0x0f3b,
- 0x0f3c, 0x0f3d, 0x0f3e, 0x0f3f, 0x0f40, 0x0f41, 0x0f42, 0x0f43, 0x0f44,
- 0x0f45, 0x0f46, 0x0f47, 0x0f48, 0x0f49, 0x0f4a, 0x0f4b, 0x0f4c, 0x0f4d,
- 0x0f4e, 0x0f4f, 0x0f50, 0x0f51, 0x0f52, 0x0f53, 0x0f54, 0x0f55, 0x0f56,
- 0x0f57, 0x0f58, 0x0f59, 0x0f5a, 0x0f5b, 0x0f5c, 0x0f5d, 0x0f5e, 0x0f5f,
- 0x0f60, 0x0f61, 0x0f62, 0x0f63, 0x0f64, 0x0f65, 0x0f66, 0x0f67, 0x0f68,
- 0x0f69, 0x0f6a, 0x0f6b, 0x0f6c, 0x0f6d, 0x0f6e, 0x0f6f, 0x0f70, 0x0f71,
- 0x0f72, 0x0f73, 0x0f74, 0x0f75, 0x0f76, 0x0f77, 0x0f78, 0x0f79, 0x0f7a,
- 0x0f7b, 0x0f7c, 0x0f7d, 0x0f7e, 0x0f7f, 0x0f80, 0x0f81, 0x0f82, 0x0f83,
- 0x0f84, 0x0f85, 0x0f86, 0x0f87, 0x0f88, 0x0f89, 0x0f8a, 0x0f8b, 0x0f8c,
- 0x0f8d, 0x0f8e, 0x0f8f, 0x0f90, 0x0f91, 0x0f92, 0x0f93, 0x0f94, 0x0f95,
- 0x0f96, 0x0f97, 0x0f98, 0x0f99, 0x0f9a, 0x0f9b, 0x0f9c, 0x0f9d, 0x0f9e,
- 0x0f9f, 0x0fa0, 0x0fa1, 0x0fa2, 0x0fa3, 0x0fa4, 0x0fa5, 0x0fa6, 0x0fa7,
- 0x0fa8, 0x0fa9, 0x0faa, 0x0fab, 0x0fac, 0x0fad, 0x0fae, 0x0faf, 0x0fb0,
- 0x0fb1, 0x0fb2, 0x0fb3, 0x0fb4, 0x0fb5, 0x0fb6, 0x0fb7, 0x0fb8, 0x0fb9,
- 0x0fba, 0x0fbb, 0x0fbc, 0x0fbd, 0x0fbe, 0x0fbf, 0x0fc0, 0x0fc1, 0x0fc2,
- 0x0fc3, 0x0fc4, 0x0fc5, 0x0fc6, 0x0fc7, 0x0fc8, 0x0fc9, 0x0fca, 0x0fcb,
- 0x0fcc, 0x0fcd, 0x0fce, 0x0fcf, 0x0fd0, 0x0fd1, 0x0fd2, 0x0fd3, 0x0fd4,
- 0x0fd5, 0x0fd6, 0x0fd7, 0x0fd8, 0x0fd9, 0x0fda, 0x0fdb, 0x0fdc, 0x0fdd,
- 0x0fde, 0x0fdf, 0x0fe0, 0x0fe1, 0x0fe2, 0x0fe3, 0x0fe4, 0x0fe5, 0x0fe6,
- 0x0fe7, 0x0fe8, 0x0fe9, 0x0fea, 0x0feb, 0x0fec, 0x0fed, 0x0fee, 0x0fef,
- 0x0ff0, 0x0ff1, 0x0ff2, 0x0ff3, 0x0ff4, 0x0ff5, 0x0ff6, 0x0ff7, 0x0ff8,
- 0x0ff9, 0x0ffa, 0x0ffb, 0x0ffc, 0x0ffd, 0x0ffe, 0x0fff};
- /*
- * Interface to higher level audio driver
- */
- struct audio_hw_if gus_hw_if = {
- gusopen,
- gusclose,
- NULL, /* drain */
- gus_query_encoding,
- gus_set_params,
- gus_round_blocksize,
- gus_commit_settings,
- NULL,
- NULL,
- gus_dma_output,
- gus_dma_input,
- gus_halt_out_dma,
- gus_halt_in_dma,
- gus_speaker_ctl,
- gus_getdev,
- NULL,
- gus_mixer_set_port,
- gus_mixer_get_port,
- gus_mixer_query_devinfo,
- gus_malloc,
- gus_free,
- gus_round,
- gus_mappage,
- gus_get_props,
- NULL,
- NULL,
- NULL
- };
- static struct audio_hw_if gusmax_hw_if = {
- gusmaxopen,
- gusmax_close,
- NULL, /* drain */
- gus_query_encoding, /* query encoding */
- gusmax_set_params,
- gusmax_round_blocksize,
- gusmax_commit_settings,
- NULL,
- NULL,
- gusmax_dma_output,
- gusmax_dma_input,
- gusmax_halt_out_dma,
- gusmax_halt_in_dma,
- gusmax_speaker_ctl,
- gus_getdev,
- NULL,
- gusmax_mixer_set_port,
- gusmax_mixer_get_port,
- gusmax_mixer_query_devinfo,
- ad1848_malloc,
- ad1848_free,
- ad1848_round,
- ad1848_mappage,
- gusmax_get_props,
- NULL,
- NULL,
- NULL
- };
- /*
- * Some info about the current audio device
- */
- struct audio_device gus_device = {
- "UltraSound",
- "",
- "gus",
- };
- int
- gusopen(void *addr, int flags)
- {
- struct gus_softc *sc = addr;
- DPRINTF(("gusopen() called\n"));
- if (sc->sc_flags & GUS_OPEN)
- return EBUSY;
- /*
- * Some initialization
- */
- sc->sc_flags |= GUS_OPEN;
- sc->sc_dmabuf = 0;
- sc->sc_playbuf = -1;
- sc->sc_bufcnt = 0;
- sc->sc_voc[GUS_VOICE_LEFT].start_addr = GUS_MEM_OFFSET - 1;
- sc->sc_voc[GUS_VOICE_LEFT].current_addr = GUS_MEM_OFFSET;
- if (HAS_CODEC(sc)) {
- ad1848_open(&sc->sc_codec, flags);
- sc->sc_codec.mute[AD1848_AUX1_CHANNEL] = 0;
- ad1848_mute_channel(&sc->sc_codec, AD1848_AUX1_CHANNEL, 0); /* turn on DAC output */
- if (flags & FREAD) {
- sc->sc_codec.mute[AD1848_MONO_CHANNEL] = 0;
- ad1848_mute_channel(&sc->sc_codec, AD1848_MONO_CHANNEL, 0);
- }
- } else if (flags & FREAD) {
- /* enable/unmute the microphone */
- if (HAS_MIXER(sc)) {
- gusics_mic_mute(&sc->sc_mixer, 0);
- } else
- gus_mic_ctl(sc, SPKR_ON);
- }
- if (sc->sc_nbufs == 0)
- gus_round_blocksize(sc, GUS_BUFFER_MULTIPLE); /* default blksiz */
- return 0;
- }
- int
- gusmaxopen(void *addr, int flags)
- {
- struct ad1848_softc *ac = addr;
- return gusopen(ac->parent, flags);
- }
- void
- gus_deinterleave(struct gus_softc *sc, void *buf, int size)
- {
- /* deinterleave the stereo data. We can use sc->sc_deintr_buf
- for scratch space. */
- int i;
- if (size > sc->sc_blocksize) {
- printf("gus: deinterleave %d > %d\n", size, sc->sc_blocksize);
- return;
- } else if (size < sc->sc_blocksize) {
- DPRINTF(("gus: deinterleave %d < %d\n", size, sc->sc_blocksize));
- }
- /*
- * size is in bytes.
- */
- if (sc->sc_precision == 16) {
- u_short *dei = sc->sc_deintr_buf;
- u_short *sbuf = buf;
- size >>= 1; /* bytecnt to shortcnt */
- /* copy 2nd of each pair of samples to the staging area, while
- compacting the 1st of each pair into the original area. */
- for (i = 0; i < size/2-1; i++) {
- dei[i] = sbuf[i*2+1];
- sbuf[i+1] = sbuf[i*2+2];
- }
- /*
- * this has copied one less sample than half of the
- * buffer. The first sample of the 1st stream was
- * already in place and didn't need copying.
- * Therefore, we've moved all of the 1st stream's
- * samples into place. We have one sample from 2nd
- * stream in the last slot of original area, not
- * copied to the staging area (But we don't need to!).
- * Copy the remainder of the original stream into place.
- */
- bcopy(dei, &sbuf[size/2], i * sizeof(short));
- } else {
- u_char *dei = sc->sc_deintr_buf;
- u_char *sbuf = buf;
- for (i = 0; i < size/2-1; i++) {
- dei[i] = sbuf[i*2+1];
- sbuf[i+1] = sbuf[i*2+2];
- }
- bcopy(dei, &sbuf[size/2], i);
- }
- }
- /*
- * Actually output a buffer to the DSP chip
- */
- int
- gusmax_dma_output(void *addr, void *buf, int size, void (*intr)(void *),
- void *arg)
- {
- struct ad1848_softc *ac = addr;
- return gus_dma_output(ac->parent, buf, size, intr, arg);
- }
- /*
- * called at splaudio() from interrupt handler.
- */
- void
- stereo_dmaintr(void *arg)
- {
- struct gus_softc *sc = arg;
- struct stereo_dma_intr *sa = &sc->sc_stereo;
- DMAPRINTF(("stereo_dmaintr"));
- /*
- * Put other half in its place, then call the real interrupt routine :)
- */
- sc->sc_dmaoutintr = sa->intr;
- sc->sc_outarg = sa->arg;
- #ifdef GUSPLAYDEBUG
- if (gusstats) {
- microtime(&dmarecords[dmarecord_index].tv);
- dmarecords[dmarecord_index].gusaddr = sa->dmabuf;
- dmarecords[dmarecord_index].bsdaddr = sa->buffer;
- dmarecords[dmarecord_index].count = sa->size;
- dmarecords[dmarecord_index].channel = 1;
- dmarecords[dmarecord_index++].direction = 1;
- dmarecord_index = dmarecord_index % NDMARECS;
- }
- #endif
- gusdmaout(sc, sa->flags, sa->dmabuf, (caddr_t) sa->buffer, sa->size);
- sa->flags = 0;
- sa->dmabuf = 0;
- sa->buffer = 0;
- sa->size = 0;
- sa->intr = 0;
- sa->arg = 0;
- }
- /*
- * Start up DMA output to the card.
- * Called at splaudio(), either from intr handler or from
- * generic audio code.
- */
- int
- gus_dma_output(void *addr, void *buf, int size, void (*intr)(void *), void *arg)
- {
- struct gus_softc *sc = addr;
- u_char *buffer = buf;
- u_long boarddma;
- int flags;
- DMAPRINTF(("gus_dma_output %d @ %p\n", size, buf));
- if (size != sc->sc_blocksize) {
- DPRINTF(("gus_dma_output reqsize %d not sc_blocksize %d\n",
- size, sc->sc_blocksize));
- return EINVAL;
- }
- flags = GUSMASK_DMA_WRITE;
- if (sc->sc_precision == 16)
- flags |= GUSMASK_DMA_DATA_SIZE;
- if (sc->sc_encoding == AUDIO_ENCODING_ULAW ||
- sc->sc_encoding == AUDIO_ENCODING_ALAW ||
- sc->sc_encoding == AUDIO_ENCODING_ULINEAR_BE ||
- sc->sc_encoding == AUDIO_ENCODING_ULINEAR_LE)
- flags |= GUSMASK_DMA_INVBIT;
- if (sc->sc_channels == 2) {
- if (sc->sc_precision == 16) {
- if (size & 3) {
- DPRINTF(("gus_dma_output: unpaired 16bit samples"));
- size &= 3;
- }
- } else if (size & 1) {
- DPRINTF(("gus_dma_output: unpaired samples"));
- size &= 1;
- }
- if (size == 0) {
- return 0;
- }
- gus_deinterleave(sc, (void *)buffer, size);
- size >>= 1;
- boarddma = size * sc->sc_dmabuf + GUS_MEM_OFFSET;
- sc->sc_stereo.intr = intr;
- sc->sc_stereo.arg = arg;
- sc->sc_stereo.size = size;
- sc->sc_stereo.dmabuf = boarddma + GUS_LEFT_RIGHT_OFFSET;
- sc->sc_stereo.buffer = buffer + size;
- sc->sc_stereo.flags = flags;
- if (gus_dostereo) {
- intr = stereo_dmaintr;
- arg = sc;
- }
- } else
- boarddma = size * sc->sc_dmabuf + GUS_MEM_OFFSET;
- sc->sc_flags |= GUS_LOCKED;
- sc->sc_dmaoutintr = intr;
- sc->sc_outarg = arg;
- #ifdef GUSPLAYDEBUG
- if (gusstats) {
- microtime(&dmarecords[dmarecord_index].tv);
- dmarecords[dmarecord_index].gusaddr = boarddma;
- dmarecords[dmarecord_index].bsdaddr = buffer;
- dmarecords[dmarecord_index].count = size;
- dmarecords[dmarecord_index].channel = 0;
- dmarecords[dmarecord_index++].direction = 1;
- dmarecord_index = dmarecord_index % NDMARECS;
- }
- #endif
- gusdmaout(sc, flags, boarddma, (caddr_t) buffer, size);
- return 0;
- }
- void
- gusmax_close(void *addr)
- {
- struct ad1848_softc *ac = addr;
- struct gus_softc *sc = ac->parent;
- #if 0
- ac->mute[AD1848_AUX1_CHANNEL] = MUTE_ALL;
- ad1848_mute_channel(ac, MUTE_ALL); /* turn off DAC output */
- #endif
- ad1848_close(ac);
- gusclose(sc);
- }
- /*
- * Close out device stuff. Called at splaudio() from generic audio layer.
- */
- void
- gusclose(void *addr)
- {
- struct gus_softc *sc = addr;
- DPRINTF(("gus_close: sc=%p\n", sc));
- /* if (sc->sc_flags & GUS_DMAOUT_ACTIVE) */ {
- gus_halt_out_dma(sc);
- }
- /* if (sc->sc_flags & GUS_DMAIN_ACTIVE) */ {
- gus_halt_in_dma(sc);
- }
- sc->sc_flags &= ~(GUS_OPEN|GUS_LOCKED|GUS_DMAOUT_ACTIVE|GUS_DMAIN_ACTIVE);
- if (sc->sc_deintr_buf) {
- free(sc->sc_deintr_buf, M_DEVBUF, 0);
- sc->sc_deintr_buf = NULL;
- }
- /* turn off speaker, etc. */
- /* make sure the voices shut up: */
- gus_stop_voice(sc, GUS_VOICE_LEFT, 1);
- gus_stop_voice(sc, GUS_VOICE_RIGHT, 0);
- }
- /*
- * Service interrupts. Farm them off to helper routines if we are using the
- * GUS for simple playback/record
- */
- #ifdef AUDIO_DEBUG
- int gusintrcnt;
- int gusdmaintrcnt;
- int gusvocintrcnt;
- #endif
- int
- gusintr(void *arg)
- {
- struct gus_softc *sc = arg;
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh1 = sc->sc_ioh1;
- bus_space_handle_t ioh2 = sc->sc_ioh2;
- unsigned char intr;
- int retval = 0;
- DPRINTF(("gusintr\n"));
- #ifdef AUDIO_DEBUG
- gusintrcnt++;
- #endif
- if (HAS_CODEC(sc))
- retval = ad1848_intr(&sc->sc_codec);
- mtx_enter(&audio_lock);
- if ((intr = bus_space_read_1(iot, ioh1, GUS_IRQ_STATUS)) & GUSMASK_IRQ_DMATC) {
- DMAPRINTF(("gusintr dma flags=%x\n", sc->sc_flags));
- #ifdef AUDIO_DEBUG
- gusdmaintrcnt++;
- #endif
- retval += gus_dmaout_intr(sc);
- if (sc->sc_flags & GUS_DMAIN_ACTIVE) {
- SELECT_GUS_REG(iot, ioh2, GUSREG_SAMPLE_CONTROL);
- intr = bus_space_read_1(iot, ioh2, GUS_DATA_HIGH);
- if (intr & GUSMASK_SAMPLE_DMATC) {
- retval += gus_dmain_intr(sc);
- }
- }
- }
- if (intr & (GUSMASK_IRQ_VOICE | GUSMASK_IRQ_VOLUME)) {
- DMAPRINTF(("gusintr voice flags=%x\n", sc->sc_flags));
- #ifdef AUDIO_DEBUG
- gusvocintrcnt++;
- #endif
- retval += gus_voice_intr(sc);
- }
- if (retval) {
- mtx_leave(&audio_lock);
- return 1;
- }
- mtx_leave(&audio_lock);
- return retval;
- }
- int gus_bufcnt[GUS_MEM_FOR_BUFFERS / GUS_BUFFER_MULTIPLE];
- int gus_restart; /* how many restarts? */
- int gus_stops; /* how many times did voice stop? */
- int gus_falsestops; /* stopped but not done? */
- int gus_continues;
- struct playcont {
- struct timeval tv;
- u_int playbuf;
- u_int dmabuf;
- u_char bufcnt;
- u_char vaction;
- u_char voccntl;
- u_char volcntl;
- u_long curaddr;
- u_long endaddr;
- } playstats[NDMARECS];
- int playcntr;
- void
- gus_dmaout_timeout(void *arg)
- {
- struct gus_softc *sc = arg;
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh2 = sc->sc_ioh2;
- printf("%s: dmaout timeout\n", sc->sc_dev.dv_xname);
- /*
- * Stop any DMA.
- */
- mtx_enter(&audio_lock);
- SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0);
-
- #if 0
- /* XXX we will dmadone below? */
- isa_dmaabort(sc->sc_dev.dv_parent, sc->sc_drq);
- #endif
-
- gus_dmaout_dointr(sc);
- mtx_leave(&audio_lock);
- }
- /*
- * Service DMA interrupts. This routine will only get called if we're doing
- * a DMA transfer for playback/record requests from the audio layer.
- */
- int
- gus_dmaout_intr(struct gus_softc *sc)
- {
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh2 = sc->sc_ioh2;
- /*
- * If we got a DMA transfer complete from the GUS DRAM, then deal
- * with it.
- */
- SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL);
- if (bus_space_read_1(iot, ioh2, GUS_DATA_HIGH) & GUSMASK_DMA_IRQPEND) {
- timeout_del(&sc->sc_dma_tmo);
- gus_dmaout_dointr(sc);
- return 1;
- }
- return 0;
- }
- void
- gus_dmaout_dointr(struct gus_softc *sc)
- {
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh2 = sc->sc_ioh2;
- /* sc->sc_dmaoutcnt - 1 because DMA controller counts from zero?. */
- isa_dmadone(sc->sc_dev.dv_parent, sc->sc_drq);
- sc->sc_flags &= ~GUS_DMAOUT_ACTIVE; /* pending DMA is done */
- DMAPRINTF(("gus_dmaout_dointr %d @ %p\n", sc->sc_dmaoutcnt,
- sc->sc_dmaoutaddr));
- /*
- * to prevent clicking, we need to copy last sample
- * from last buffer to scratch area just before beginning of
- * buffer. However, if we're doing formats that are converted by
- * the card during the DMA process, we need to pick up the converted
- * byte rather than the one we have in memory.
- */
- if (sc->sc_dmabuf == sc->sc_nbufs - 1) {
- int i;
- switch (sc->sc_encoding) {
- case AUDIO_ENCODING_SLINEAR_LE:
- case AUDIO_ENCODING_SLINEAR_BE:
- if (sc->sc_precision == 8)
- goto byte;
- /* we have the native format */
- for (i = 1; i <= 2; i++)
- guspoke(iot, ioh2, sc->sc_gusaddr -
- (sc->sc_nbufs - 1) * sc->sc_chanblocksize - i,
- sc->sc_dmaoutaddr[sc->sc_dmaoutcnt-i]);
- break;
- case AUDIO_ENCODING_ULINEAR_LE:
- case AUDIO_ENCODING_ULINEAR_BE:
- guspoke(iot, ioh2, sc->sc_gusaddr -
- (sc->sc_nbufs - 1) * sc->sc_chanblocksize - 2,
- guspeek(iot, ioh2,
- sc->sc_gusaddr + sc->sc_chanblocksize - 2));
- case AUDIO_ENCODING_ALAW:
- case AUDIO_ENCODING_ULAW:
- byte:
- /* we need to fetch the translated byte, then stuff it. */
- guspoke(iot, ioh2, sc->sc_gusaddr -
- (sc->sc_nbufs - 1) * sc->sc_chanblocksize - 1,
- guspeek(iot, ioh2,
- sc->sc_gusaddr + sc->sc_chanblocksize - 1));
- break;
- }
- }
- /*
- * If this is the first half of stereo, "ignore" this one
- * and copy out the second half.
- */
- if (sc->sc_dmaoutintr == stereo_dmaintr) {
- (*sc->sc_dmaoutintr)(sc->sc_outarg);
- return;
- }
- /*
- * If the voice is stopped, then start it. Reset the loop
- * and roll bits. Call the audio layer routine, since if
- * we're starting a stopped voice, that means that the next
- * buffer can be filled
- */
- sc->sc_flags &= ~GUS_LOCKED;
- if (sc->sc_voc[GUS_VOICE_LEFT].voccntl &
- GUSMASK_VOICE_STOPPED) {
- if (sc->sc_flags & GUS_PLAYING) {
- printf("%s: playing yet stopped?\n", sc->sc_dev.dv_xname);
- }
- sc->sc_bufcnt++; /* another yet to be played */
- gus_start_playing(sc, sc->sc_dmabuf);
- gus_restart++;
- } else {
- /*
- * set the sound action based on which buffer we
- * just transferred. If we just transferred buffer 0
- * we want the sound to loop when it gets to the nth
- * buffer; if we just transferred
- * any other buffer, we want the sound to roll over
- * at least one more time. The voice interrupt
- * handlers will take care of accounting &
- * setting control bits if it's not caught up to us
- * yet.
- */
- if (++sc->sc_bufcnt == 2) {
- /*
- * XXX
- * If we're too slow in reaction here,
- * the voice could be just approaching the
- * end of its run. It should be set to stop,
- * so these adjustments might not DTRT.
- */
- if (sc->sc_dmabuf == 0 &&
- sc->sc_playbuf == sc->sc_nbufs - 1) {
- /* player is just at the last buf, we're at the
- first. Turn on looping, turn off rolling. */
- sc->sc_voc[GUS_VOICE_LEFT].voccntl |= GUSMASK_LOOP_ENABLE;
- sc->sc_voc[GUS_VOICE_LEFT].volcntl &= ~GUSMASK_VOICE_ROLL;
- playstats[playcntr].vaction = 3;
- } else {
- /* player is at previous buf:
- turn on rolling, turn off looping */
- sc->sc_voc[GUS_VOICE_LEFT].voccntl &= ~GUSMASK_LOOP_ENABLE;
- sc->sc_voc[GUS_VOICE_LEFT].volcntl |= GUSMASK_VOICE_ROLL;
- playstats[playcntr].vaction = 4;
- }
- #ifdef GUSPLAYDEBUG
- if (gusstats) {
- microtime(&playstats[playcntr].tv);
- playstats[playcntr].endaddr = sc->sc_voc[GUS_VOICE_LEFT].end_addr;
- playstats[playcntr].voccntl = sc->sc_voc[GUS_VOICE_LEFT].voccntl;
- playstats[playcntr].volcntl = sc->sc_voc[GUS_VOICE_LEFT].volcntl;
- playstats[playcntr].playbuf = sc->sc_playbuf;
- playstats[playcntr].dmabuf = sc->sc_dmabuf;
- playstats[playcntr].bufcnt = sc->sc_bufcnt;
- playstats[playcntr++].curaddr = gus_get_curaddr(sc, GUS_VOICE_LEFT);
- playcntr = playcntr % NDMARECS;
- }
- #endif
- bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, GUS_VOICE_LEFT);
- SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_LEFT].voccntl);
- SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_CONTROL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_LEFT].volcntl);
- }
- }
- gus_bufcnt[sc->sc_bufcnt-1]++;
- /*
- * flip to the next DMA buffer
- */
- sc->sc_dmabuf = ++sc->sc_dmabuf % sc->sc_nbufs;
- /*
- * See comments below about DMA admission control strategy.
- * We can call the upper level here if we have an
- * idle buffer (not currently playing) to DMA into.
- */
- if (sc->sc_dmaoutintr && sc->sc_bufcnt < sc->sc_nbufs) {
- /* clean out to prevent double calls */
- void (*pfunc)(void *) = sc->sc_dmaoutintr;
- void *arg = sc->sc_outarg;
- sc->sc_outarg = 0;
- sc->sc_dmaoutintr = 0;
- (*pfunc)(arg);
- }
- }
- /*
- * Service voice interrupts
- */
- int
- gus_voice_intr(struct gus_softc *sc)
- {
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh2 = sc->sc_ioh2;
- int ignore = 0, voice, rval = 0;
- unsigned char intr, status;
- /*
- * The point of this may not be obvious at first. A voice can
- * interrupt more than once; according to the GUS SDK we are supposed
- * to ignore multiple interrupts for the same voice.
- */
- while(1) {
- SELECT_GUS_REG(iot, ioh2, GUSREG_IRQ_STATUS);
- intr = bus_space_read_1(iot, ioh2, GUS_DATA_HIGH);
- if ((intr & (GUSMASK_WIRQ_VOLUME | GUSMASK_WIRQ_VOICE))
- == (GUSMASK_WIRQ_VOLUME | GUSMASK_WIRQ_VOICE))
- /*
- * No more interrupts, time to return
- */
- return rval;
- if ((intr & GUSMASK_WIRQ_VOICE) == 0) {
- /*
- * We've got a voice interrupt. Ignore previous
- * interrupts by the same voice.
- */
- rval = 1;
- voice = intr & GUSMASK_WIRQ_VOICEMASK;
- if ((1 << voice) & ignore)
- break;
- ignore |= 1 << voice;
- /*
- * If the voice is stopped, then force it to stop
- * (this stops it from continuously generating IRQs)
- */
- SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL+0x80);
- status = bus_space_read_1(iot, ioh2, GUS_DATA_HIGH);
- if (status & GUSMASK_VOICE_STOPPED) {
- if (voice != GUS_VOICE_LEFT) {
- DMAPRINTF(("%s: spurious voice %d stop?\n",
- sc->sc_dev.dv_xname, voice));
- gus_stop_voice(sc, voice, 0);
- continue;
- }
- gus_stop_voice(sc, voice, 1);
- /* also kill right voice */
- gus_stop_voice(sc, GUS_VOICE_RIGHT, 0);
- sc->sc_bufcnt--; /* it finished a buffer */
- if (sc->sc_bufcnt > 0) {
- /*
- * probably a race to get here: the voice
- * stopped while the DMA code was just trying to
- * get the next buffer in place.
- * Start the voice again.
- */
- printf("%s: stopped voice not drained? (%x)\n",
- sc->sc_dev.dv_xname, sc->sc_bufcnt);
- gus_falsestops++;
- sc->sc_playbuf = ++sc->sc_playbuf % sc->sc_nbufs;
- gus_start_playing(sc, sc->sc_playbuf);
- } else if (sc->sc_bufcnt < 0) {
- panic("%s: negative bufcnt in stopped voice",
- sc->sc_dev.dv_xname);
- } else {
- sc->sc_playbuf = -1; /* none are active */
- gus_stops++;
- }
- /* fall through to callback and admit another
- buffer.... */
- } else if (sc->sc_bufcnt != 0) {
- /*
- * This should always be taken if the voice
- * is not stopped.
- */
- gus_continues++;
- if (gus_continue_playing(sc, voice)) {
- /*
- * we shouldn't have continued--active DMA
- * is in the way in the ring, for
- * some as-yet undebugged reason.
- */
- gus_stop_voice(sc, GUS_VOICE_LEFT, 1);
- /* also kill right voice */
- gus_stop_voice(sc, GUS_VOICE_RIGHT, 0);
- sc->sc_playbuf = -1;
- gus_stops++;
- }
- }
- /*
- * call the upper level to send on down another
- * block. We do admission rate control as follows:
- *
- * When starting up output (in the first N
- * blocks), call the upper layer after the DMA is
- * complete (see above in gus_dmaout_intr()).
- *
- * When output is already in progress and we have
- * no more GUS buffers to use for DMA, the DMA
- * output routines do not call the upper layer.
- * Instead, we call the DMA completion routine
- * here, after the voice interrupts indicating
- * that it's finished with a buffer.
- *
- * However, don't call anything here if the DMA
- * output flag is set, (which shouldn't happen)
- * because we'll squish somebody else's DMA if
- * that's the case. When DMA is done, it will
- * call back if there is a spare buffer.
- */
- if (sc->sc_dmaoutintr && !(sc->sc_flags & GUS_LOCKED)) {
- if (sc->sc_dmaoutintr == stereo_dmaintr)
- printf("gusdmaout botch?\n");
- else {
- /* clean out to avoid double calls */
- void (*pfunc)(void *) = sc->sc_dmaoutintr;
- void *arg = sc->sc_outarg;
- sc->sc_outarg = 0;
- sc->sc_dmaoutintr = 0;
- (*pfunc)(arg);
- }
- }
- }
- /*
- * Ignore other interrupts for now
- */
- }
- return 0;
- }
- void
- gus_start_playing(struct gus_softc *sc, int bufno)
- {
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh2 = sc->sc_ioh2;
- /*
- * Start the voices playing, with buffer BUFNO.
- */
- /*
- * Loop or roll if we have buffers ready.
- */
- if (sc->sc_bufcnt == 1) {
- sc->sc_voc[GUS_VOICE_LEFT].voccntl &= ~(GUSMASK_LOOP_ENABLE);
- sc->sc_voc[GUS_VOICE_LEFT].volcntl &= ~(GUSMASK_VOICE_ROLL);
- } else {
- if (bufno == sc->sc_nbufs - 1) {
- sc->sc_voc[GUS_VOICE_LEFT].voccntl |= GUSMASK_LOOP_ENABLE;
- sc->sc_voc[GUS_VOICE_LEFT].volcntl &= ~(GUSMASK_VOICE_ROLL);
- } else {
- sc->sc_voc[GUS_VOICE_LEFT].voccntl &= ~GUSMASK_LOOP_ENABLE;
- sc->sc_voc[GUS_VOICE_LEFT].volcntl |= GUSMASK_VOICE_ROLL;
- }
- }
- bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, GUS_VOICE_LEFT);
- SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_LEFT].voccntl);
- SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_CONTROL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_LEFT].volcntl);
- sc->sc_voc[GUS_VOICE_LEFT].current_addr =
- GUS_MEM_OFFSET + sc->sc_chanblocksize * bufno;
- sc->sc_voc[GUS_VOICE_LEFT].end_addr =
- sc->sc_voc[GUS_VOICE_LEFT].current_addr + sc->sc_chanblocksize - 1;
- sc->sc_voc[GUS_VOICE_RIGHT].current_addr =
- sc->sc_voc[GUS_VOICE_LEFT].current_addr +
- (gus_dostereo && sc->sc_channels == 2 ? GUS_LEFT_RIGHT_OFFSET : 0);
- /*
- * set up right channel to just loop forever, no interrupts,
- * starting at the buffer we just filled. We'll feed it data
- * at the same time as left channel.
- */
- sc->sc_voc[GUS_VOICE_RIGHT].voccntl |= GUSMASK_LOOP_ENABLE;
- sc->sc_voc[GUS_VOICE_RIGHT].volcntl &= ~(GUSMASK_VOICE_ROLL);
- #ifdef GUSPLAYDEBUG
- if (gusstats) {
- microtime(&playstats[playcntr].tv);
- playstats[playcntr].curaddr = sc->sc_voc[GUS_VOICE_LEFT].current_addr;
- playstats[playcntr].voccntl = sc->sc_voc[GUS_VOICE_LEFT].voccntl;
- playstats[playcntr].volcntl = sc->sc_voc[GUS_VOICE_LEFT].volcntl;
- playstats[playcntr].endaddr = sc->sc_voc[GUS_VOICE_LEFT].end_addr;
- playstats[playcntr].playbuf = bufno;
- playstats[playcntr].dmabuf = sc->sc_dmabuf;
- playstats[playcntr].bufcnt = sc->sc_bufcnt;
- playstats[playcntr++].vaction = 5;
- playcntr = playcntr % NDMARECS;
- }
- #endif
- bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, GUS_VOICE_RIGHT);
- SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_RIGHT].voccntl);
- SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_CONTROL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[GUS_VOICE_RIGHT].volcntl);
- gus_start_voice(sc, GUS_VOICE_RIGHT, 0);
- gus_start_voice(sc, GUS_VOICE_LEFT, 1);
- if (sc->sc_playbuf == -1)
- /* mark start of playing */
- sc->sc_playbuf = bufno;
- }
- int
- gus_continue_playing(struct gus_softc *sc, int voice)
- {
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh2 = sc->sc_ioh2;
- /*
- * stop this voice from interrupting while we work.
- */
- SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].voccntl & ~(GUSMASK_VOICE_IRQ));
- /*
- * update playbuf to point to the buffer the hardware just started
- * playing
- */
- sc->sc_playbuf = ++sc->sc_playbuf % sc->sc_nbufs;
- /*
- * account for buffer just finished
- */
- if (--sc->sc_bufcnt == 0) {
- DPRINTF(("gus: bufcnt 0 on continuing voice?\n"));
- }
- if (sc->sc_playbuf == sc->sc_dmabuf && (sc->sc_flags & GUS_LOCKED)) {
- printf("%s: continue into active dmabuf?\n", sc->sc_dev.dv_xname);
- return 1;
- }
- /*
- * Select the end of the buffer based on the currently active
- * buffer, [plus extra contiguous buffers (if ready)].
- */
- /*
- * set endpoint at end of buffer we just started playing.
- *
- * The total gets -1 because end addrs are one less than you might
- * think (the end_addr is the address of the last sample to play)
- */
- gus_set_endaddr(sc, voice, GUS_MEM_OFFSET +
- sc->sc_chanblocksize * (sc->sc_playbuf + 1) - 1);
- if (sc->sc_bufcnt < 2) {
- /*
- * Clear out the loop and roll flags, and rotate the currently
- * playing buffer. That way, if we don't manage to get more
- * data before this buffer finishes, we'll just stop.
- */
- sc->sc_voc[voice].voccntl &= ~GUSMASK_LOOP_ENABLE;
- sc->sc_voc[voice].volcntl &= ~GUSMASK_VOICE_ROLL;
- playstats[playcntr].vaction = 0;
- } else {
- /*
- * We have some buffers to play. set LOOP if we're on the
- * last buffer in the ring, otherwise set ROLL.
- */
- if (sc->sc_playbuf == sc->sc_nbufs - 1) {
- sc->sc_voc[voice].voccntl |= GUSMASK_LOOP_ENABLE;
- sc->sc_voc[voice].volcntl &= ~GUSMASK_VOICE_ROLL;
- playstats[playcntr].vaction = 1;
- } else {
- sc->sc_voc[voice].voccntl &= ~GUSMASK_LOOP_ENABLE;
- sc->sc_voc[voice].volcntl |= GUSMASK_VOICE_ROLL;
- playstats[playcntr].vaction = 2;
- }
- }
- #ifdef GUSPLAYDEBUG
- if (gusstats) {
- microtime(&playstats[playcntr].tv);
- playstats[playcntr].curaddr = gus_get_curaddr(sc, voice);
- playstats[playcntr].voccntl = sc->sc_voc[voice].voccntl;
- playstats[playcntr].volcntl = sc->sc_voc[voice].volcntl;
- playstats[playcntr].endaddr = sc->sc_voc[voice].end_addr;
- playstats[playcntr].playbuf = sc->sc_playbuf;
- playstats[playcntr].dmabuf = sc->sc_dmabuf;
- playstats[playcntr++].bufcnt = sc->sc_bufcnt;
- playcntr = playcntr % NDMARECS;
- }
- #endif
- /*
- * (re-)set voice parameters. This will reenable interrupts from this
- * voice.
- */
- SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].voccntl);
- SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_CONTROL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].volcntl);
- return 0;
- }
- /*
- * Send/receive data into GUS's DRAM using DMA. Called at splaudio()
- */
- void
- gusdmaout(struct gus_softc *sc, int flags, u_long gusaddr, caddr_t buffaddr,
- int length)
- {
- unsigned char c = (unsigned char) flags;
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh2 = sc->sc_ioh2;
- DMAPRINTF(("gusdmaout flags=%x scflags=%x\n", flags, sc->sc_flags));
- sc->sc_gusaddr = gusaddr;
- /*
- * If we're using a 16 bit DMA channel, we have to jump through some
- * extra hoops; this includes translating the DRAM address a bit
- */
- if (sc->sc_drq >= 4) {
- c |= GUSMASK_DMA_WIDTH;
- gusaddr = convert_to_16bit(gusaddr);
- }
- /*
- * Add flag bits that we always set - fast DMA, enable IRQ
- */
- c |= GUSMASK_DMA_ENABLE | GUSMASK_DMA_R0 | GUSMASK_DMA_IRQ;
- /*
- * Make sure the GUS _isn't_ setup for DMA
- */
- SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0);
- /*
- * Tell the PC DMA controller to start doing DMA
- */
- sc->sc_dmaoutaddr = (u_char *) buffaddr;
- sc->sc_dmaoutcnt = length;
- isa_dmastart(sc->sc_dev.dv_parent, sc->sc_drq, buffaddr, length,
- NULL, DMAMODE_WRITE, BUS_DMA_NOWAIT);
- /*
- * Set up DMA address - use the upper 16 bits ONLY
- */
- sc->sc_flags |= GUS_DMAOUT_ACTIVE;
- SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_START);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, (int) (gusaddr >> 4));
- /*
- * Tell the GUS to start doing DMA
- */
- SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, c);
- /*
- * XXX If we don't finish in one second, give up...
- */
- timeout_add_sec(&sc->sc_dma_tmo, 1);
- }
- /*
- * Start a voice playing on the GUS. Called from interrupt handler at
- * splaudio().
- */
- void
- gus_start_voice(struct gus_softc *sc, int voice, int intrs)
- {
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh2 = sc->sc_ioh2;
- u_long start;
- u_long current;
- u_long end;
- /*
- * Pick all the values for the voice out of the gus_voice struct
- * and use those to program the voice
- */
- start = sc->sc_voc[voice].start_addr;
- current = sc->sc_voc[voice].current_addr;
- end = sc->sc_voc[voice].end_addr;
- /*
- * If we're using 16 bit data, mangle the addresses a bit
- */
- if (sc->sc_voc[voice].voccntl & GUSMASK_DATA_SIZE16) {
- /* -1 on start so that we get onto sample boundary--other
- code always sets it for 1-byte rollover protection */
- start = convert_to_16bit(start-1);
- current = convert_to_16bit(current);
- end = convert_to_16bit(end);
- }
- /*
- * Select the voice we want to use, and program the data addresses
- */
- bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) voice);
- SELECT_GUS_REG(iot, ioh2, GUSREG_START_ADDR_HIGH);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_HIGH(start));
- SELECT_GUS_REG(iot, ioh2, GUSREG_START_ADDR_LOW);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_LOW(start));
- SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_HIGH);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_HIGH(current));
- SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_LOW);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_LOW(current));
- SELECT_GUS_REG(iot, ioh2, GUSREG_END_ADDR_HIGH);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_HIGH(end));
- SELECT_GUS_REG(iot, ioh2, GUSREG_END_ADDR_LOW);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_LOW(end));
- /*
- * (maybe) enable interrupts, disable voice stopping
- */
- if (intrs) {
- sc->sc_flags |= GUS_PLAYING; /* playing is about to start */
- sc->sc_voc[voice].voccntl |= GUSMASK_VOICE_IRQ;
- DMAPRINTF(("gus voice playing=%x\n", sc->sc_flags));
- } else
- sc->sc_voc[voice].voccntl &= ~GUSMASK_VOICE_IRQ;
- sc->sc_voc[voice].voccntl &= ~(GUSMASK_VOICE_STOPPED |
- GUSMASK_STOP_VOICE);
- /*
- * Tell the GUS about it. Note that we're doing volume ramping here
- * from 0 up to the set volume to help reduce clicks.
- */
- SELECT_GUS_REG(iot, ioh2, GUSREG_START_VOLUME);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00);
- SELECT_GUS_REG(iot, ioh2, GUSREG_END_VOLUME);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].current_volume >> 4);
- SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_VOLUME);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x00);
- SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_RATE);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 63);
- SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].voccntl);
- SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_CONTROL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00);
- delay(50);
- SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].voccntl);
- SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_CONTROL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00);
- }
- /*
- * Stop a given voice. Called at splaudio().
- */
- void
- gus_stop_voice(struct gus_softc *sc, int voice, int intrs_too)
- {
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh2 = sc->sc_ioh2;
- sc->sc_voc[voice].voccntl |= GUSMASK_VOICE_STOPPED |
- GUSMASK_STOP_VOICE;
- if (intrs_too) {
- sc->sc_voc[voice].voccntl &= ~(GUSMASK_VOICE_IRQ);
- /* no more DMA to do */
- sc->sc_flags &= ~GUS_PLAYING;
- }
- DMAPRINTF(("gusintr voice notplaying=%x\n", sc->sc_flags));
- guspoke(iot, ioh2, 0L, 0);
- bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) voice);
- SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_VOLUME);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
- SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].voccntl);
- delay(100);
- SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_VOLUME);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
- SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[voice].voccntl);
- SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_HIGH);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
- SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_LOW);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
- }
- /*
- * Set the volume of a given voice. Called at splaudio().
- */
- void
- gus_set_volume(struct gus_softc *sc, int voice, int volume)
- {
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh2 = sc->sc_ioh2;
- unsigned int gusvol;
- gusvol = gus_log_volumes[volume < 512 ? volume : 511];
- sc->sc_voc[voice].current_volume = gusvol;
- bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) voice);
- SELECT_GUS_REG(iot, ioh2, GUSREG_START_VOLUME);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, (unsigned char) (gusvol >> 4));
- SELECT_GUS_REG(iot, ioh2, GUSREG_END_VOLUME);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, (unsigned char) (gusvol >> 4));
- SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_VOLUME);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, gusvol << 4);
- delay(500);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, gusvol << 4);
- }
- /*
- * Interface to the audio layer.
- */
- int
- gusmax_set_params(void *addr, int setmode, int usemode, struct audio_params *p,
- struct audio_params *r)
- {
- struct ad1848_softc *ac = addr;
- struct gus_softc *sc = ac->parent;
- int error;
- error = ad1848_set_params(ac, setmode, usemode, p, r);
- if (error)
- return error;
- error = gus_set_params(sc, setmode, usemode, p, r);
- return error;
- }
- int
- gus_set_params(void *addr, int setmode, int usemode, struct audio_params *p,
- struct audio_params *r)
- {
- struct gus_softc *sc = addr;
- switch (p->encoding) {
- case AUDIO_ENCODING_SLINEAR_LE:
- case AUDIO_ENCODING_ULINEAR_LE:
- break;
- default:
- return (EINVAL);
- }
- /* XXX: why?! this is called with interrupts disabled */
- mtx_enter(&audio_lock);
- if (p->precision == 8) {
- sc->sc_voc[GUS_VOICE_LEFT].voccntl &= ~GUSMASK_DATA_SIZE16;
- sc->sc_voc[GUS_VOICE_RIGHT].voccntl &= ~GUSMASK_DATA_SIZE16;
- } else {
- sc->sc_voc[GUS_VOICE_LEFT].voccntl |= GUSMASK_DATA_SIZE16;
- sc->sc_voc[GUS_VOICE_RIGHT].voccntl |= GUSMASK_DATA_SIZE16;
- }
- sc->sc_encoding = p->encoding;
- sc->sc_precision = p->precision;
- sc->sc_channels = p->channels;
- mtx_leave(&audio_lock);
- if (p->sample_rate > gus_max_frequency[sc->sc_voices - GUS_MIN_VOICES])
- p->sample_rate = gus_max_frequency[sc->sc_voices - GUS_MIN_VOICES];
- if (setmode & AUMODE_RECORD)
- sc->sc_irate = p->sample_rate;
- if (setmode & AUMODE_PLAY)
- sc->sc_orate = p->sample_rate;
- p->bps = AUDIO_BPS(p->precision);
- r->bps = AUDIO_BPS(r->precision);
- p->msb = r->msb = 1;
- return 0;
- }
- /*
- * Interface to the audio layer - set the blocksize to the correct number
- * of units
- */
- int
- gusmax_round_blocksize(void *addr, int blocksize)
- {
- struct ad1848_softc *ac = addr;
- struct gus_softc *sc = ac->parent;
- /* blocksize = ad1848_round_blocksize(ac, blocksize);*/
- return gus_round_blocksize(sc, blocksize);
- }
- int
- gus_round_blocksize(addr, blocksize)
- void * addr;
- int blocksize;
- {
- struct gus_softc *sc = addr;
- DPRINTF(("gus_round_blocksize called\n"));
- if ((sc->sc_encoding == AUDIO_ENCODING_ULAW ||
- sc->sc_encoding == AUDIO_ENCODING_ALAW) && blocksize > 32768)
- blocksize = 32768;
- else if (blocksize > 65536)
- blocksize = 65536;
- if ((blocksize % GUS_BUFFER_MULTIPLE) != 0)
- blocksize = (blocksize / GUS_BUFFER_MULTIPLE + 1) *
- GUS_BUFFER_MULTIPLE;
- /* set up temporary buffer to hold the deinterleave, if necessary
- for stereo output */
- if (sc->sc_deintr_buf) {
- free(sc->sc_deintr_buf, M_DEVBUF, 0);
- sc->sc_deintr_buf = NULL;
- }
- sc->sc_deintr_buf = malloc(blocksize/2, M_DEVBUF, M_WAITOK);
- sc->sc_blocksize = blocksize;
- /* multi-buffering not quite working yet. */
- sc->sc_nbufs = /*GUS_MEM_FOR_BUFFERS / blocksize*/ 2;
- gus_set_chan_addrs(sc);
- return blocksize;
- }
- int
- gus_get_out_gain(caddr_t addr)
- {
- struct gus_softc *sc = (struct gus_softc *) addr;
- DPRINTF(("gus_get_out_gain called\n"));
- return sc->sc_ogain / 2;
- }
- inline void
- gus_set_voices(struct gus_softc *sc, int voices)
- {
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh2 = sc->sc_ioh2;
- /*
- * Select the active number of voices
- */
- SELECT_GUS_REG(iot, ioh2, GUSREG_ACTIVE_VOICES);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, (voices-1) | 0xc0);
- sc->sc_voices = voices;
- }
- /*
- * Actually set the settings of various values on the card
- */
- int
- gusmax_commit_settings(void *addr)
- {
- struct ad1848_softc *ac = addr;
- struct gus_softc *sc = ac->parent;
- int error;
- error = ad1848_commit_settings(ac);
- if (error)
- return error;
- return gus_commit_settings(sc);
- }
- /*
- * Commit the settings. Called at normal IPL.
- */
- int
- gus_commit_settings(void *addr)
- {
- struct gus_softc *sc = addr;
- DPRINTF(("gus_commit_settings called (gain = %d)\n",sc->sc_ogain));
- /* XXX: why?! this is called with interrupts disabled */
- mtx_enter(&audio_lock);
- gus_set_recrate(sc, sc->sc_irate);
- gus_set_volume(sc, GUS_VOICE_LEFT, sc->sc_ogain);
- gus_set_volume(sc, GUS_VOICE_RIGHT, sc->sc_ogain);
- gus_set_samprate(sc, GUS_VOICE_LEFT, sc->sc_orate);
- gus_set_samprate(sc, GUS_VOICE_RIGHT, sc->sc_orate);
- mtx_leave(&audio_lock);
- gus_set_chan_addrs(sc);
- return 0;
- }
- void
- gus_set_chan_addrs(struct gus_softc *sc)
- {
- /*
- * We use sc_nbufs * blocksize bytes of storage in the on-board GUS
- * ram.
- * For mono, each of the sc_nbufs buffers is DMA'd to in one chunk,
- * and both left & right channels play the same buffer.
- *
- * For stereo, each channel gets a contiguous half of the memory,
- * and each has sc_nbufs buffers of size blocksize/2.
- * Stereo data are deinterleaved in main memory before the DMA out
- * routines are called to queue the output.
- *
- * The blocksize per channel is kept in sc_chanblocksize.
- */
- if (sc->sc_channels == 2)
- sc->sc_chanblocksize = sc->sc_blocksize/2;
- else
- sc->sc_chanblocksize = sc->sc_blocksize;
- sc->sc_voc[GUS_VOICE_LEFT].start_addr = GUS_MEM_OFFSET - 1;
- sc->sc_voc[GUS_VOICE_RIGHT].start_addr =
- (gus_dostereo && sc->sc_channels == 2 ? GUS_LEFT_RIGHT_OFFSET : 0)
- + GUS_MEM_OFFSET - 1;
- sc->sc_voc[GUS_VOICE_RIGHT].current_addr =
- sc->sc_voc[GUS_VOICE_RIGHT].start_addr + 1;
- sc->sc_voc[GUS_VOICE_RIGHT].end_addr =
- sc->sc_voc[GUS_VOICE_RIGHT].start_addr +
- sc->sc_nbufs * sc->sc_chanblocksize;
- }
- /*
- * Set the sample rate of the given voice. Called at splaudio().
- */
- void
- gus_set_samprate(struct gus_softc *sc, int voice, int freq)
- {
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh2 = sc->sc_ioh2;
- unsigned int fc;
- u_long temp, f = (u_long) freq;
- /*
- * calculate fc based on the number of active voices;
- * we need to use longs to preserve enough bits
- */
- temp = (u_long) gus_max_frequency[sc->sc_voices-GUS_MIN_VOICES];
- fc = (unsigned int)(((f << 9L) + (temp >> 1L)) / temp);
- fc <<= 1;
- /*
- * Program the voice frequency, and set it in the voice data record
- */
- bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) voice);
- SELECT_GUS_REG(iot, ioh2, GUSREG_FREQ_CONTROL);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, fc);
- sc->sc_voc[voice].rate = freq;
- }
- /*
- * Set the sample rate of the recording frequency. Formula is from the GUS
- * SDK. Called at splaudio().
- */
- void
- gus_set_recrate(struct gus_softc *sc, u_long rate)
- {
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh2 = sc->sc_ioh2;
- u_char realrate;
- DPRINTF(("gus_set_recrate %lu\n", rate));
- #if 0
- realrate = 9878400/(16*(rate+2)); /* formula from GUS docs */
- #endif
- realrate = (9878400 >> 4)/rate - 2; /* formula from code, sigh. */
- SELECT_GUS_REG(iot, ioh2, GUSREG_SAMPLE_FREQ);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, realrate);
- }
- /*
- * Interface to the audio layer - turn the output on or off. Note that some
- * of these bits are flipped in the register
- */
- int
- gusmax_speaker_ctl(void *addr, int newstate)
- {
- struct ad1848_softc *sc = addr;
- return gus_speaker_ctl(sc->parent, newstate);
- }
- int
- gus_speaker_ctl(void *addr, int newstate)
- {
- struct gus_softc *sc = (struct gus_softc *) addr;
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh1 = sc->sc_ioh1;
- /* Line out bit is flipped: 0 enables, 1 disables */
- if ((newstate == SPKR_ON) &&
- (sc->sc_mixcontrol & GUSMASK_LINE_OUT)) {
- sc->sc_mixcontrol &= ~GUSMASK_LINE_OUT;
- bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, sc->sc_mixcontrol);
- }
- if ((newstate == SPKR_OFF) &&
- (sc->sc_mixcontrol & GUSMASK_LINE_OUT) == 0) {
- sc->sc_mixcontrol |= GUSMASK_LINE_OUT;
- bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, sc->sc_mixcontrol);
- }
- return 0;
- }
- int
- gus_linein_ctl(void *addr, int newstate)
- {
- struct gus_softc *sc = (struct gus_softc *) addr;
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh1 = sc->sc_ioh1;
- /* Line in bit is flipped: 0 enables, 1 disables */
- if ((newstate == SPKR_ON) &&
- (sc->sc_mixcontrol & GUSMASK_LINE_IN)) {
- sc->sc_mixcontrol &= ~GUSMASK_LINE_IN;
- bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, sc->sc_mixcontrol);
- }
- if ((newstate == SPKR_OFF) &&
- (sc->sc_mixcontrol & GUSMASK_LINE_IN) == 0) {
- sc->sc_mixcontrol |= GUSMASK_LINE_IN;
- bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, sc->sc_mixcontrol);
- }
- return 0;
- }
- int
- gus_mic_ctl(void *addr, int newstate)
- {
- struct gus_softc *sc = (struct gus_softc *) addr;
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh1 = sc->sc_ioh1;
- /* Mic bit is normal: 1 enables, 0 disables */
- if ((newstate == SPKR_ON) &&
- (sc->sc_mixcontrol & GUSMASK_MIC_IN) == 0) {
- sc->sc_mixcontrol |= GUSMASK_MIC_IN;
- bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, sc->sc_mixcontrol);
- }
- if ((newstate == SPKR_OFF) &&
- (sc->sc_mixcontrol & GUSMASK_MIC_IN)) {
- sc->sc_mixcontrol &= ~GUSMASK_MIC_IN;
- bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, sc->sc_mixcontrol);
- }
- return 0;
- }
- /*
- * Set the end address of a give voice. Called at splaudio().
- */
- void
- gus_set_endaddr(struct gus_softc *sc, int voice, u_long addr)
- {
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh2 = sc->sc_ioh2;
- sc->sc_voc[voice].end_addr = addr;
- if (sc->sc_voc[voice].voccntl & GUSMASK_DATA_SIZE16)
- addr = convert_to_16bit(addr);
- SELECT_GUS_REG(iot, ioh2, GUSREG_END_ADDR_HIGH);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_HIGH(addr));
- SELECT_GUS_REG(iot, ioh2, GUSREG_END_ADDR_LOW);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_LOW(addr));
- }
- #ifdef GUSPLAYDEBUG
- /*
- * Set current address. Called at splaudio().
- */
- void
- gus_set_curaddr(struct gus_softc *sc, int voice, u_long addr)
- {
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh2 = sc->sc_ioh2;
- sc->sc_voc[voice].current_addr = addr;
- if (sc->sc_voc[voice].voccntl & GUSMASK_DATA_SIZE16)
- addr = convert_to_16bit(addr);
- bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) voice);
- SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_HIGH);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_HIGH(addr));
- SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_LOW);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, ADDR_LOW(addr));
- }
- /*
- * Get current GUS playback address. Called at splaudio().
- */
- u_long
- gus_get_curaddr(struct gus_softc *sc, int voice)
- {
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh2 = sc->sc_ioh2;
- u_long addr;
- bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) voice);
- SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_HIGH|GUSREG_READ);
- addr = (bus_space_read_2(iot, ioh2, GUS_DATA_LOW) & 0x1fff) << 7;
- SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_LOW|GUSREG_READ);
- addr |= (bus_space_read_2(iot, ioh2, GUS_DATA_LOW) >> 9L) & 0x7f;
- if (sc->sc_voc[voice].voccntl & GUSMASK_DATA_SIZE16)
- addr = (addr & 0xc0000) | ((addr & 0x1ffff) << 1); /* undo 16-bit change */
- DPRINTF(("gus voice %d curaddr %ld end_addr %ld\n",
- voice, addr, sc->sc_voc[voice].end_addr));
- /* XXX sanity check the address? */
- return(addr);
- }
- #endif
- /*
- * Convert an address value to a "16 bit" value - why this is necessary I
- * have NO idea
- */
- u_long
- convert_to_16bit(u_long address)
- {
- u_long old_address;
- old_address = address;
- address >>= 1;
- address &= 0x0001ffffL;
- address |= (old_address & 0x000c0000L);
- return (address);
- }
- /*
- * Write a value into the GUS's DRAM
- */
- void
- guspoke(bus_space_tag_t iot, bus_space_handle_t ioh2, long address,
- unsigned char value)
- {
- /*
- * Select the DRAM address
- */
- SELECT_GUS_REG(iot, ioh2, GUSREG_DRAM_ADDR_LOW);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, (unsigned int) (address & 0xffff));
- SELECT_GUS_REG(iot, ioh2, GUSREG_DRAM_ADDR_HIGH);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, (unsigned char) ((address >> 16) & 0xff));
- /*
- * Actually write the data
- */
- bus_space_write_1(iot, ioh2, GUS_DRAM_DATA, value);
- }
- /*
- * Read a value from the GUS's DRAM
- */
- unsigned char
- guspeek(bus_space_tag_t iot, bus_space_handle_t ioh2, u_long address)
- {
- /*
- * Select the DRAM address
- */
- SELECT_GUS_REG(iot, ioh2, GUSREG_DRAM_ADDR_LOW);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, (unsigned int) (address & 0xffff));
- SELECT_GUS_REG(iot, ioh2, GUSREG_DRAM_ADDR_HIGH);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, (unsigned char) ((address >> 16) & 0xff));
- /*
- * Read in the data from the board
- */
- return (unsigned char) bus_space_read_1(iot, ioh2, GUS_DRAM_DATA);
- }
- /*
- * Reset the Gravis UltraSound card, completely
- */
- void
- gusreset(struct gus_softc *sc, int voices)
- {
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh1 = sc->sc_ioh1;
- bus_space_handle_t ioh2 = sc->sc_ioh2;
- bus_space_handle_t ioh4 = sc->sc_ioh4;
- int i;
- mtx_enter(&audio_lock);
- /*
- * Reset the GF1 chip
- */
- SELECT_GUS_REG(iot, ioh2, GUSREG_RESET);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00);
- delay(500);
- /*
- * Release reset
- */
- SELECT_GUS_REG(iot, ioh2, GUSREG_RESET);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, GUSMASK_MASTER_RESET);
- delay(500);
- /*
- * Reset MIDI port as well, if applicable
- */
- if (ioh4 != (bus_space_handle_t)NULL) {
- bus_space_write_1(iot, ioh4, GUS_MIDI_CONTROL, MIDI_RESET);
- delay(500);
- bus_space_write_1(iot, ioh4, GUS_MIDI_CONTROL, 0x00);
- }
- /*
- * Clear interrupts
- */
- SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00);
- SELECT_GUS_REG(iot, ioh2, GUSREG_TIMER_CONTROL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00);
- SELECT_GUS_REG(iot, ioh2, GUSREG_SAMPLE_CONTROL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00);
- gus_set_voices(sc, voices);
- bus_space_read_1(iot, ioh1, GUS_IRQ_STATUS);
- SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL);
- bus_space_read_1(iot, ioh2, GUS_DATA_HIGH);
- SELECT_GUS_REG(iot, ioh2, GUSREG_SAMPLE_CONTROL);
- bus_space_read_1(iot, ioh2, GUS_DATA_HIGH);
- SELECT_GUS_REG(iot, ioh2, GUSREG_IRQ_STATUS);
- bus_space_read_1(iot, ioh2, GUS_DATA_HIGH);
- /*
- * Reset voice specific information
- */
- for(i = 0; i < voices; i++) {
- bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) i);
- SELECT_GUS_REG(iot, ioh2, GUSREG_VOICE_CNTL);
- sc->sc_voc[i].voccntl = GUSMASK_VOICE_STOPPED |
- GUSMASK_STOP_VOICE;
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[i].voccntl);
- sc->sc_voc[i].volcntl = GUSMASK_VOLUME_STOPPED |
- GUSMASK_STOP_VOLUME;
- SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_CONTROL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, sc->sc_voc[i].volcntl);
- delay(100);
- gus_set_samprate(sc, i, 8000);
- SELECT_GUS_REG(iot, ioh2, GUSREG_START_ADDR_HIGH);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
- SELECT_GUS_REG(iot, ioh2, GUSREG_START_ADDR_LOW);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
- SELECT_GUS_REG(iot, ioh2, GUSREG_END_ADDR_HIGH);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
- SELECT_GUS_REG(iot, ioh2, GUSREG_END_ADDR_LOW);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
- SELECT_GUS_REG(iot, ioh2, GUSREG_VOLUME_RATE);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x01);
- SELECT_GUS_REG(iot, ioh2, GUSREG_START_VOLUME);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x10);
- SELECT_GUS_REG(iot, ioh2, GUSREG_END_VOLUME);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0xe0);
- SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_VOLUME);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
- SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_HIGH);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
- SELECT_GUS_REG(iot, ioh2, GUSREG_CUR_ADDR_LOW);
- bus_space_write_2(iot, ioh2, GUS_DATA_LOW, 0x0000);
- SELECT_GUS_REG(iot, ioh2, GUSREG_PAN_POS);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x07);
- }
- /*
- * Clear out any pending IRQs
- */
- bus_space_read_1(iot, ioh1, GUS_IRQ_STATUS);
- SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL);
- bus_space_read_1(iot, ioh2, GUS_DATA_HIGH);
- SELECT_GUS_REG(iot, ioh2, GUSREG_SAMPLE_CONTROL);
- bus_space_read_1(iot, ioh2, GUS_DATA_HIGH);
- SELECT_GUS_REG(iot, ioh2, GUSREG_IRQ_STATUS);
- bus_space_read_1(iot, ioh2, GUS_DATA_HIGH);
- SELECT_GUS_REG(iot, ioh2, GUSREG_RESET);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, GUSMASK_MASTER_RESET | GUSMASK_DAC_ENABLE |
- GUSMASK_IRQ_ENABLE);
- mtx_leave(&audio_lock);
- }
- int
- gus_init_cs4231(struct gus_softc *sc)
- {
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh1 = sc->sc_ioh1;
- int port = sc->sc_iobase;
- u_char ctrl;
- ctrl = (port & 0xf0) >> 4; /* set port address middle nibble */
- /*
- * The codec is a bit weird--swapped dma channels.
- */
- ctrl |= GUS_MAX_CODEC_ENABLE;
- if (sc->sc_drq >= 4)
- ctrl |= GUS_MAX_RECCHAN16;
- if (sc->sc_recdrq >= 4)
- ctrl |= GUS_MAX_PLAYCHAN16;
- bus_space_write_1(iot, ioh1, GUS_MAX_CTRL, ctrl);
- sc->sc_codec.sc_iot = sc->sc_iot;
- sc->sc_codec.sc_iobase = port+GUS_MAX_CODEC_BASE;
- if (ad1848_mapprobe(&sc->sc_codec, sc->sc_codec.sc_iobase) == 0) {
- sc->sc_flags &= ~GUS_CODEC_INSTALLED;
- return (0);
- } else {
- struct ad1848_volume vol = {AUDIO_MAX_GAIN, AUDIO_MAX_GAIN};
- sc->sc_flags |= GUS_CODEC_INSTALLED;
- sc->sc_codec.parent = sc;
- sc->sc_codec.sc_drq = sc->sc_recdrq;
- sc->sc_codec.sc_recdrq = sc->sc_drq;
- gus_hw_if = gusmax_hw_if;
- /* enable line in and mic in the GUS mixer; the codec chip
- will do the real mixing for them. */
- sc->sc_mixcontrol &= ~GUSMASK_LINE_IN; /* 0 enables. */
- sc->sc_mixcontrol |= GUSMASK_MIC_IN; /* 1 enables. */
- bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, sc->sc_mixcontrol);
- ad1848_attach(&sc->sc_codec);
- /* turn on pre-MUX microphone gain. */
- ad1848_set_mic_gain(&sc->sc_codec, &vol);
- return (1);
- }
- }
- /*
- * Return info about the audio device, for the AUDIO_GETINFO ioctl
- */
- int
- gus_getdev(void *addr, struct audio_device *dev)
- {
- *dev = gus_device;
- return 0;
- }
- /*
- * stubs (XXX)
- */
- int
- gus_set_in_gain(caddr_t addr, u_int gain, u_char balance)
- {
- DPRINTF(("gus_set_in_gain called\n"));
- return 0;
- }
- int
- gus_get_in_gain(caddr_t addr)
- {
- DPRINTF(("gus_get_in_gain called\n"));
- return 0;
- }
- int
- gusmax_dma_input(void *addr, void *buf, int size, void (*callback)(void *),
- void *arg)
- {
- struct ad1848_softc *sc = addr;
- return gus_dma_input(sc->parent, buf, size, callback, arg);
- }
- /*
- * Start sampling the input source into the requested DMA buffer.
- * Called at splaudio(), either from top-half or from interrupt handler.
- */
- int
- gus_dma_input(void *addr, void *buf, int size, void (*callback)(void *),
- void *arg)
- {
- struct gus_softc *sc = addr;
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh2 = sc->sc_ioh2;
- u_char dmac;
- DMAPRINTF(("gus_dma_input called\n"));
- /*
- * Sample SIZE bytes of data from the card, into buffer at BUF.
- */
- if (sc->sc_precision == 16) {
- return EINVAL; /* XXX */
- }
- /* set DMA modes */
- dmac = GUSMASK_SAMPLE_IRQ|GUSMASK_SAMPLE_START;
- if (sc->sc_recdrq >= 4)
- dmac |= GUSMASK_SAMPLE_DATA16;
- if (sc->sc_encoding == AUDIO_ENCODING_ULAW ||
- sc->sc_encoding == AUDIO_ENCODING_ALAW ||
- sc->sc_encoding == AUDIO_ENCODING_ULINEAR_LE ||
- sc->sc_encoding == AUDIO_ENCODING_ULINEAR_BE)
- dmac |= GUSMASK_SAMPLE_INVBIT;
- if (sc->sc_channels == 2)
- dmac |= GUSMASK_SAMPLE_STEREO;
- isa_dmastart(sc->sc_dev.dv_parent, sc->sc_recdrq, buf, size,
- NULL, DMAMODE_READ, BUS_DMA_NOWAIT);
- DMAPRINTF(("gus_dma_input isadma_started\n"));
- sc->sc_flags |= GUS_DMAIN_ACTIVE;
- sc->sc_dmainintr = callback;
- sc->sc_inarg = arg;
- sc->sc_dmaincnt = size;
- sc->sc_dmainaddr = buf;
- SELECT_GUS_REG(iot, ioh2, GUSREG_SAMPLE_CONTROL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, dmac); /* Go! */
- DMAPRINTF(("gus_dma_input returning\n"));
- return 0;
- }
- int
- gus_dmain_intr(struct gus_softc *sc)
- {
- void (*callback)(void *);
- void *arg;
- DMAPRINTF(("gus_dmain_intr called\n"));
- if (sc->sc_dmainintr) {
- isa_dmadone(sc->sc_dev.dv_parent, sc->sc_recdrq);
- callback = sc->sc_dmainintr;
- arg = sc->sc_inarg;
- sc->sc_dmainaddr = 0;
- sc->sc_dmaincnt = 0;
- sc->sc_dmainintr = 0;
- sc->sc_inarg = 0;
- sc->sc_flags &= ~GUS_DMAIN_ACTIVE;
- DMAPRINTF(("calling dmain_intr callback %p(%p)\n", callback, arg));
- (*callback)(arg);
- return 1;
- } else {
- DMAPRINTF(("gus_dmain_intr false?\n"));
- return 0; /* XXX ??? */
- }
- }
- int
- gusmax_halt_out_dma(void *addr)
- {
- struct ad1848_softc *sc = addr;
- return gus_halt_out_dma(sc->parent);
- }
- int
- gusmax_halt_in_dma(void *addr)
- {
- struct ad1848_softc *sc = addr;
- return gus_halt_in_dma(sc->parent);
- }
- /*
- * Stop any DMA output. Called at splaudio().
- */
- int
- gus_halt_out_dma(void *addr)
- {
- struct gus_softc *sc = addr;
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh2 = sc->sc_ioh2;
- mtx_enter(&audio_lock);
- DMAPRINTF(("gus_halt_out_dma called\n"));
- /*
- * Make sure the GUS _isn't_ setup for DMA
- */
- SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0);
- timeout_del(&sc->sc_dma_tmo);
- isa_dmaabort(sc->sc_dev.dv_parent, sc->sc_drq);
- sc->sc_flags &= ~(GUS_DMAOUT_ACTIVE|GUS_LOCKED);
- sc->sc_dmaoutintr = 0;
- sc->sc_outarg = 0;
- sc->sc_dmaoutaddr = 0;
- sc->sc_dmaoutcnt = 0;
- sc->sc_dmabuf = 0;
- sc->sc_bufcnt = 0;
- sc->sc_playbuf = -1;
- /* also stop playing */
- gus_stop_voice(sc, GUS_VOICE_LEFT, 1);
- gus_stop_voice(sc, GUS_VOICE_RIGHT, 0);
- mtx_leave(&audio_lock);
- return 0;
- }
- /*
- * Stop any DMA output. Called at splaudio().
- */
- int
- gus_halt_in_dma(void *addr)
- {
- struct gus_softc *sc = addr;
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh2 = sc->sc_ioh2;
- mtx_enter(&audio_lock);
- DMAPRINTF(("gus_halt_in_dma called\n"));
- /*
- * Make sure the GUS _isn't_ setup for DMA
- */
- SELECT_GUS_REG(iot, ioh2, GUSREG_SAMPLE_CONTROL);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH,
- bus_space_read_1(iot, ioh2, GUS_DATA_HIGH) & ~(GUSMASK_SAMPLE_START|GUSMASK_SAMPLE_IRQ));
- isa_dmaabort(sc->sc_dev.dv_parent, sc->sc_recdrq);
- sc->sc_flags &= ~GUS_DMAIN_ACTIVE;
- sc->sc_dmainintr = 0;
- sc->sc_inarg = 0;
- sc->sc_dmainaddr = 0;
- sc->sc_dmaincnt = 0;
- mtx_leave(&audio_lock);
- return 0;
- }
- ad1848_devmap_t gusmapping[] = {
- {GUSMAX_DAC_LVL, AD1848_KIND_LVL, AD1848_AUX1_CHANNEL},
- {GUSMAX_LINE_IN_LVL, AD1848_KIND_LVL, AD1848_LINE_CHANNEL},
- {GUSMAX_MONO_LVL, AD1848_KIND_LVL, AD1848_MONO_CHANNEL},
- {GUSMAX_CD_LVL, AD1848_KIND_LVL, AD1848_AUX2_CHANNEL},
- {GUSMAX_MONITOR_LVL, AD1848_KIND_LVL, AD1848_MONITOR_CHANNEL},
- {GUSMAX_OUT_LVL, AD1848_KIND_LVL, AD1848_DAC_CHANNEL},
- {GUSMAX_DAC_MUTE, AD1848_KIND_MUTE, AD1848_AUX1_CHANNEL},
- {GUSMAX_LINE_IN_MUTE, AD1848_KIND_MUTE, AD1848_LINE_CHANNEL},
- {GUSMAX_MONO_MUTE, AD1848_KIND_MUTE, AD1848_MONO_CHANNEL},
- {GUSMAX_CD_MUTE, AD1848_KIND_MUTE, AD1848_AUX2_CHANNEL},
- {GUSMAX_MONITOR_MUTE, AD1848_KIND_MUTE, AD1848_MONITOR_CHANNEL},
- {GUSMAX_REC_LVL, AD1848_KIND_RECORDGAIN, -1},
- {GUSMAX_RECORD_SOURCE, AD1848_KIND_RECORDSOURCE, -1}
- };
- int nummap = sizeof(gusmapping) / sizeof(gusmapping[0]);
- int
- gusmax_mixer_get_port(void *addr, mixer_ctrl_t *cp)
- {
- struct ad1848_softc *ac = addr;
- struct gus_softc *sc = ac->parent;
- struct ad1848_volume vol;
- int error = ad1848_mixer_get_port(ac, gusmapping, nummap, cp);
- if (error != ENXIO)
- return (error);
- error = EINVAL;
- switch (cp->dev) {
- case GUSMAX_SPEAKER_LVL: /* fake speaker for mute naming */
- if (cp->type == AUDIO_MIXER_VALUE) {
- if (sc->sc_mixcontrol & GUSMASK_LINE_OUT)
- vol.left = vol.right = AUDIO_MAX_GAIN;
- else
- vol.left = vol.right = AUDIO_MIN_GAIN;
- error = 0;
- ad1848_from_vol(cp, &vol);
- }
- break;
- case GUSMAX_SPEAKER_MUTE:
- if (cp->type == AUDIO_MIXER_ENUM) {
- cp->un.ord = sc->sc_mixcontrol & GUSMASK_LINE_OUT ? 1 : 0;
- error = 0;
- }
- break;
- default:
- error = ENXIO;
- break;
- }
- return(error);
- }
- int
- gus_mixer_get_port(void *addr, mixer_ctrl_t *cp)
- {
- struct gus_softc *sc = addr;
- struct ics2101_softc *ic = &sc->sc_mixer;
- struct ad1848_volume vol;
- int error = EINVAL;
- DPRINTF(("gus_mixer_get_port: dev=%d type=%d\n", cp->dev, cp->type));
- if (!HAS_MIXER(sc) && cp->dev > GUSICS_MASTER_MUTE)
- return ENXIO;
- switch (cp->dev) {
- case GUSICS_MIC_IN_MUTE: /* Microphone */
- if (cp->type == AUDIO_MIXER_ENUM) {
- if (HAS_MIXER(sc))
- cp->un.ord = ic->sc_mute[GUSMIX_CHAN_MIC][ICSMIX_LEFT];
- else
- cp->un.ord =
- sc->sc_mixcontrol & GUSMASK_MIC_IN ? 0 : 1;
- error = 0;
- }
- break;
- case GUSICS_LINE_IN_MUTE:
- if (cp->type == AUDIO_MIXER_ENUM) {
- if (HAS_MIXER(sc))
- cp->un.ord = ic->sc_mute[GUSMIX_CHAN_LINE][ICSMIX_LEFT];
- else
- cp->un.ord =
- sc->sc_mixcontrol & GUSMASK_LINE_IN ? 1 : 0;
- error = 0;
- }
- break;
- case GUSICS_MASTER_MUTE:
- if (cp->type == AUDIO_MIXER_ENUM) {
- if (HAS_MIXER(sc))
- cp->un.ord = ic->sc_mute[GUSMIX_CHAN_MASTER][ICSMIX_LEFT];
- else
- cp->un.ord =
- sc->sc_mixcontrol & GUSMASK_LINE_OUT ? 1 : 0;
- error = 0;
- }
- break;
- case GUSICS_DAC_MUTE:
- if (cp->type == AUDIO_MIXER_ENUM) {
- cp->un.ord = ic->sc_mute[GUSMIX_CHAN_DAC][ICSMIX_LEFT];
- error = 0;
- }
- break;
- case GUSICS_CD_MUTE:
- if (cp->type == AUDIO_MIXER_ENUM) {
- cp->un.ord = ic->sc_mute[GUSMIX_CHAN_CD][ICSMIX_LEFT];
- error = 0;
- }
- break;
- case GUSICS_MASTER_LVL:
- if (cp->type == AUDIO_MIXER_VALUE) {
- vol.left = ic->sc_setting[GUSMIX_CHAN_MASTER][ICSMIX_LEFT];
- vol.right = ic->sc_setting[GUSMIX_CHAN_MASTER][ICSMIX_RIGHT];
- if (ad1848_from_vol(cp, &vol))
- error = 0;
- }
- break;
- case GUSICS_MIC_IN_LVL: /* Microphone */
- if (cp->type == AUDIO_MIXER_VALUE) {
- vol.left = ic->sc_setting[GUSMIX_CHAN_MIC][ICSMIX_LEFT];
- vol.right = ic->sc_setting[GUSMIX_CHAN_MIC][ICSMIX_RIGHT];
- if (ad1848_from_vol(cp, &vol))
- error = 0;
- }
- break;
- case GUSICS_LINE_IN_LVL: /* line in */
- if (cp->type == AUDIO_MIXER_VALUE) {
- vol.left = ic->sc_setting[GUSMIX_CHAN_LINE][ICSMIX_LEFT];
- vol.right = ic->sc_setting[GUSMIX_CHAN_LINE][ICSMIX_RIGHT];
- if (ad1848_from_vol(cp, &vol))
- error = 0;
- }
- break;
- case GUSICS_CD_LVL:
- if (cp->type == AUDIO_MIXER_VALUE) {
- vol.left = ic->sc_setting[GUSMIX_CHAN_CD][ICSMIX_LEFT];
- vol.right = ic->sc_setting[GUSMIX_CHAN_CD][ICSMIX_RIGHT];
- if (ad1848_from_vol(cp, &vol))
- error = 0;
- }
- break;
- case GUSICS_DAC_LVL: /* dac out */
- if (cp->type == AUDIO_MIXER_VALUE) {
- vol.left = ic->sc_setting[GUSMIX_CHAN_DAC][ICSMIX_LEFT];
- vol.right = ic->sc_setting[GUSMIX_CHAN_DAC][ICSMIX_RIGHT];
- if (ad1848_from_vol(cp, &vol))
- error = 0;
- }
- break;
- case GUSICS_RECORD_SOURCE:
- if (cp->type == AUDIO_MIXER_ENUM) {
- /* Can't set anything else useful, sigh. */
- cp->un.ord = 0;
- }
- break;
- default:
- return ENXIO;
- /*NOTREACHED*/
- }
- return error;
- }
- void
- gusics_master_mute(struct ics2101_softc *ic, int mute)
- {
- ics2101_mix_mute(ic, GUSMIX_CHAN_MASTER, ICSMIX_LEFT, mute);
- ics2101_mix_mute(ic, GUSMIX_CHAN_MASTER, ICSMIX_RIGHT, mute);
- }
- void
- gusics_mic_mute(struct ics2101_softc *ic, int mute)
- {
- ics2101_mix_mute(ic, GUSMIX_CHAN_MIC, ICSMIX_LEFT, mute);
- ics2101_mix_mute(ic, GUSMIX_CHAN_MIC, ICSMIX_RIGHT, mute);
- }
- void
- gusics_linein_mute(struct ics2101_softc *ic, int mute)
- {
- ics2101_mix_mute(ic, GUSMIX_CHAN_LINE, ICSMIX_LEFT, mute);
- ics2101_mix_mute(ic, GUSMIX_CHAN_LINE, ICSMIX_RIGHT, mute);
- }
- void
- gusics_cd_mute(struct ics2101_softc *ic, int mute)
- {
- ics2101_mix_mute(ic, GUSMIX_CHAN_CD, ICSMIX_LEFT, mute);
- ics2101_mix_mute(ic, GUSMIX_CHAN_CD, ICSMIX_RIGHT, mute);
- }
- void
- gusics_dac_mute(struct ics2101_softc *ic, int mute)
- {
- ics2101_mix_mute(ic, GUSMIX_CHAN_DAC, ICSMIX_LEFT, mute);
- ics2101_mix_mute(ic, GUSMIX_CHAN_DAC, ICSMIX_RIGHT, mute);
- }
- int
- gusmax_mixer_set_port(void *addr, mixer_ctrl_t *cp)
- {
- struct ad1848_softc *ac = addr;
- struct gus_softc *sc = ac->parent;
- struct ad1848_volume vol;
- int error = ad1848_mixer_set_port(ac, gusmapping, nummap, cp);
- if (error != ENXIO)
- return (error);
- DPRINTF(("gusmax_mixer_set_port: dev=%d type=%d\n", cp->dev, cp->type));
- switch (cp->dev) {
- case GUSMAX_SPEAKER_LVL:
- if (cp->type == AUDIO_MIXER_VALUE &&
- cp->un.value.num_channels == 1) {
- if (ad1848_to_vol(cp, &vol)) {
- gus_speaker_ctl(sc, vol.left > AUDIO_MIN_GAIN ?
- SPKR_ON : SPKR_OFF);
- error = 0;
- }
- }
- break;
- case GUSMAX_SPEAKER_MUTE:
- if (cp->type == AUDIO_MIXER_ENUM) {
- gus_speaker_ctl(sc, cp->un.ord ? SPKR_OFF : SPKR_ON);
- error = 0;
- }
- break;
- default:
- return ENXIO;
- /*NOTREACHED*/
- }
- return error;
- }
- int
- gus_mixer_set_port(void *addr, mixer_ctrl_t *cp)
- {
- struct gus_softc *sc = addr;
- struct ics2101_softc *ic = &sc->sc_mixer;
- struct ad1848_volume vol;
- int error = EINVAL;
- DPRINTF(("gus_mixer_set_port: dev=%d type=%d\n", cp->dev, cp->type));
- if (!HAS_MIXER(sc) && cp->dev > GUSICS_MASTER_MUTE)
- return ENXIO;
- switch (cp->dev) {
- case GUSICS_MIC_IN_MUTE: /* Microphone */
- if (cp->type == AUDIO_MIXER_ENUM) {
- DPRINTF(("mic mute %d\n", cp->un.ord));
- if (HAS_MIXER(sc)) {
- gusics_mic_mute(ic, cp->un.ord);
- }
- gus_mic_ctl(sc, cp->un.ord ? SPKR_OFF : SPKR_ON);
- error = 0;
- }
- break;
- case GUSICS_LINE_IN_MUTE:
- if (cp->type == AUDIO_MIXER_ENUM) {
- DPRINTF(("linein mute %d\n", cp->un.ord));
- if (HAS_MIXER(sc)) {
- gusics_linein_mute(ic, cp->un.ord);
- }
- gus_linein_ctl(sc, cp->un.ord ? SPKR_OFF : SPKR_ON);
- error = 0;
- }
- break;
- case GUSICS_MASTER_MUTE:
- if (cp->type == AUDIO_MIXER_ENUM) {
- DPRINTF(("master mute %d\n", cp->un.ord));
- if (HAS_MIXER(sc)) {
- gusics_master_mute(ic, cp->un.ord);
- }
- gus_speaker_ctl(sc, cp->un.ord ? SPKR_OFF : SPKR_ON);
- error = 0;
- }
- break;
- case GUSICS_DAC_MUTE:
- if (cp->type == AUDIO_MIXER_ENUM) {
- gusics_dac_mute(ic, cp->un.ord);
- error = 0;
- }
- break;
- case GUSICS_CD_MUTE:
- if (cp->type == AUDIO_MIXER_ENUM) {
- gusics_cd_mute(ic, cp->un.ord);
- error = 0;
- }
- break;
- case GUSICS_MASTER_LVL:
- if (cp->type == AUDIO_MIXER_VALUE) {
- if (ad1848_to_vol(cp, &vol)) {
- ics2101_mix_attenuate(ic,
- GUSMIX_CHAN_MASTER,
- ICSMIX_LEFT,
- vol.left);
- ics2101_mix_attenuate(ic,
- GUSMIX_CHAN_MASTER,
- ICSMIX_RIGHT,
- vol.right);
- error = 0;
- }
- }
- break;
- case GUSICS_MIC_IN_LVL: /* Microphone */
- if (cp->type == AUDIO_MIXER_VALUE) {
- if (ad1848_to_vol(cp, &vol)) {
- ics2101_mix_attenuate(ic,
- GUSMIX_CHAN_MIC,
- ICSMIX_LEFT,
- vol.left);
- ics2101_mix_attenuate(ic,
- GUSMIX_CHAN_MIC,
- ICSMIX_RIGHT,
- vol.right);
- error = 0;
- }
- }
- break;
- case GUSICS_LINE_IN_LVL: /* line in */
- if (cp->type == AUDIO_MIXER_VALUE) {
- if (ad1848_to_vol(cp, &vol)) {
- ics2101_mix_attenuate(ic,
- GUSMIX_CHAN_LINE,
- ICSMIX_LEFT,
- vol.left);
- ics2101_mix_attenuate(ic,
- GUSMIX_CHAN_LINE,
- ICSMIX_RIGHT,
- vol.right);
- error = 0;
- }
- }
- break;
- case GUSICS_CD_LVL:
- if (cp->type == AUDIO_MIXER_VALUE) {
- if (ad1848_to_vol(cp, &vol)) {
- ics2101_mix_attenuate(ic,
- GUSMIX_CHAN_CD,
- ICSMIX_LEFT,
- vol.left);
- ics2101_mix_attenuate(ic,
- GUSMIX_CHAN_CD,
- ICSMIX_RIGHT,
- vol.right);
- error = 0;
- }
- }
- break;
- case GUSICS_DAC_LVL: /* dac out */
- if (cp->type == AUDIO_MIXER_VALUE) {
- if (ad1848_to_vol(cp, &vol)) {
- ics2101_mix_attenuate(ic,
- GUSMIX_CHAN_DAC,
- ICSMIX_LEFT,
- vol.left);
- ics2101_mix_attenuate(ic,
- GUSMIX_CHAN_DAC,
- ICSMIX_RIGHT,
- vol.right);
- error = 0;
- }
- }
- break;
- case GUSICS_RECORD_SOURCE:
- if (cp->type == AUDIO_MIXER_ENUM && cp->un.ord == 0) {
- /* Can't set anything else useful, sigh. */
- error = 0;
- }
- break;
- default:
- return ENXIO;
- /*NOTREACHED*/
- }
- return error;
- }
- int
- gus_get_props(void *addr)
- {
- struct gus_softc *sc = addr;
- return AUDIO_PROP_MMAP |
- (sc->sc_recdrq == sc->sc_drq ? 0 : AUDIO_PROP_FULLDUPLEX);
- }
- int
- gusmax_get_props(void *addr)
- {
- struct ad1848_softc *ac = addr;
- return gus_get_props(ac->parent);
- }
- int
- gusmax_mixer_query_devinfo(void *addr, mixer_devinfo_t *dip)
- {
- DPRINTF(("gusmax_query_devinfo: index=%d\n", dip->index));
- switch(dip->index) {
- #if 0
- case GUSMAX_MIC_IN_LVL: /* Microphone */
- dip->type = AUDIO_MIXER_VALUE;
- dip->mixer_class = GUSMAX_INPUT_CLASS;
- dip->prev = AUDIO_MIXER_LAST;
- dip->next = GUSMAX_MIC_IN_MUTE;
- strlcpy(dip->label.name, AudioNmicrophone, sizeof dip->label.name);
- dip->un.v.num_channels = 2;
- strlcpy(dip->un.v.units.name, AudioNvolume,
- sizeof dip->un.v.units.name);
- break;
- #endif
- case GUSMAX_MONO_LVL: /* mono/microphone mixer */
- dip->type = AUDIO_MIXER_VALUE;
- dip->mixer_class = GUSMAX_INPUT_CLASS;
- dip->prev = AUDIO_MIXER_LAST;
- dip->next = GUSMAX_MONO_MUTE;
- strlcpy(dip->label.name, AudioNmicrophone, sizeof dip->label.name);
- dip->un.v.num_channels = 1;
- strlcpy(dip->un.v.units.name, AudioNvolume,
- sizeof dip->un.v.units.name);
- break;
- case GUSMAX_DAC_LVL: /* dacout */
- dip->type = AUDIO_MIXER_VALUE;
- dip->mixer_class = GUSMAX_INPUT_CLASS;
- dip->prev = AUDIO_MIXER_LAST;
- dip->next = GUSMAX_DAC_MUTE;
- strlcpy(dip->label.name, AudioNdac, sizeof dip->label.name);
- dip->un.v.num_channels = 2;
- strlcpy(dip->un.v.units.name, AudioNvolume,
- sizeof dip->un.v.units.name);
- break;
- case GUSMAX_LINE_IN_LVL: /* line */
- dip->type = AUDIO_MIXER_VALUE;
- dip->mixer_class = GUSMAX_INPUT_CLASS;
- dip->prev = AUDIO_MIXER_LAST;
- dip->next = GUSMAX_LINE_IN_MUTE;
- strlcpy(dip->label.name, AudioNline, sizeof dip->label.name);
- dip->un.v.num_channels = 2;
- strlcpy(dip->un.v.units.name, AudioNvolume,
- sizeof dip->un.v.units.name);
- break;
- case GUSMAX_CD_LVL: /* cd */
- dip->type = AUDIO_MIXER_VALUE;
- dip->mixer_class = GUSMAX_INPUT_CLASS;
- dip->prev = AUDIO_MIXER_LAST;
- dip->next = GUSMAX_CD_MUTE;
- strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
- dip->un.v.num_channels = 2;
- strlcpy(dip->un.v.units.name, AudioNvolume,
- sizeof dip->un.v.units.name);
- break;
- case GUSMAX_MONITOR_LVL: /* monitor level */
- dip->type = AUDIO_MIXER_VALUE;
- dip->mixer_class = GUSMAX_MONITOR_CLASS;
- dip->next = GUSMAX_MONITOR_MUTE;
- dip->prev = AUDIO_MIXER_LAST;
- strlcpy(dip->label.name, AudioNmonitor, sizeof dip->label.name);
- dip->un.v.num_channels = 1;
- strlcpy(dip->un.v.units.name, AudioNvolume,
- sizeof dip->un.v.units.name);
- break;
- case GUSMAX_OUT_LVL: /* cs4231 output volume: not useful? */
- dip->type = AUDIO_MIXER_VALUE;
- dip->mixer_class = GUSMAX_MONITOR_CLASS;
- dip->prev = dip->next = AUDIO_MIXER_LAST;
- strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
- dip->un.v.num_channels = 2;
- strlcpy(dip->un.v.units.name, AudioNvolume,
- sizeof dip->un.v.units.name);
- break;
- case GUSMAX_SPEAKER_LVL: /* fake speaker volume */
- dip->type = AUDIO_MIXER_VALUE;
- dip->mixer_class = GUSMAX_MONITOR_CLASS;
- dip->prev = AUDIO_MIXER_LAST;
- dip->next = GUSMAX_SPEAKER_MUTE;
- strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name);
- dip->un.v.num_channels = 2;
- strlcpy(dip->un.v.units.name, AudioNvolume,
- sizeof dip->un.v.units.name);
- break;
- case GUSMAX_LINE_IN_MUTE:
- dip->mixer_class = GUSMAX_INPUT_CLASS;
- dip->type = AUDIO_MIXER_ENUM;
- dip->prev = GUSMAX_LINE_IN_LVL;
- dip->next = AUDIO_MIXER_LAST;
- goto mute;
- case GUSMAX_DAC_MUTE:
- dip->mixer_class = GUSMAX_INPUT_CLASS;
- dip->type = AUDIO_MIXER_ENUM;
- dip->prev = GUSMAX_DAC_LVL;
- dip->next = AUDIO_MIXER_LAST;
- goto mute;
- case GUSMAX_CD_MUTE:
- dip->mixer_class = GUSMAX_INPUT_CLASS;
- dip->type = AUDIO_MIXER_ENUM;
- dip->prev = GUSMAX_CD_LVL;
- dip->next = AUDIO_MIXER_LAST;
- goto mute;
- case GUSMAX_MONO_MUTE:
- dip->mixer_class = GUSMAX_INPUT_CLASS;
- dip->type = AUDIO_MIXER_ENUM;
- dip->prev = GUSMAX_MONO_LVL;
- dip->next = AUDIO_MIXER_LAST;
- goto mute;
- case GUSMAX_MONITOR_MUTE:
- dip->mixer_class = GUSMAX_OUTPUT_CLASS;
- dip->type = AUDIO_MIXER_ENUM;
- dip->prev = GUSMAX_MONITOR_LVL;
- dip->next = AUDIO_MIXER_LAST;
- goto mute;
- case GUSMAX_SPEAKER_MUTE:
- dip->mixer_class = GUSMAX_OUTPUT_CLASS;
- dip->type = AUDIO_MIXER_ENUM;
- dip->prev = GUSMAX_SPEAKER_LVL;
- dip->next = AUDIO_MIXER_LAST;
- mute:
- strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
- dip->un.e.num_mem = 2;
- strlcpy(dip->un.e.member[0].label.name, AudioNoff,
- sizeof dip->un.e.member[0].label.name);
- dip->un.e.member[0].ord = 0;
- strlcpy(dip->un.e.member[1].label.name, AudioNon,
- sizeof dip->un.e.member[1].label.name);
- dip->un.e.member[1].ord = 1;
- break;
- case GUSMAX_REC_LVL: /* record level */
- dip->type = AUDIO_MIXER_VALUE;
- dip->mixer_class = GUSMAX_RECORD_CLASS;
- dip->prev = AUDIO_MIXER_LAST;
- dip->next = GUSMAX_RECORD_SOURCE;
- strlcpy(dip->label.name, AudioNrecord, sizeof dip->label.name);
- dip->un.v.num_channels = 2;
- strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name);
- break;
- case GUSMAX_RECORD_SOURCE:
- dip->mixer_class = GUSMAX_RECORD_CLASS;
- dip->type = AUDIO_MIXER_ENUM;
- dip->prev = GUSMAX_REC_LVL;
- dip->next = AUDIO_MIXER_LAST;
- strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
- dip->un.e.num_mem = 4;
- strlcpy(dip->un.e.member[0].label.name, AudioNoutput,
- sizeof dip->un.e.member[0].label.name);
- dip->un.e.member[0].ord = DAC_IN_PORT;
- strlcpy(dip->un.e.member[1].label.name, AudioNmicrophone,
- sizeof dip->un.e.member[1].label.name);
- dip->un.e.member[1].ord = MIC_IN_PORT;
- strlcpy(dip->un.e.member[2].label.name, AudioNdac,
- sizeof dip->un.e.member[2].label.name);
- dip->un.e.member[2].ord = AUX1_IN_PORT;
- strlcpy(dip->un.e.member[3].label.name, AudioNline,
- sizeof dip->un.e.member[3].label.name);
- dip->un.e.member[3].ord = LINE_IN_PORT;
- break;
- case GUSMAX_INPUT_CLASS: /* input class descriptor */
- dip->type = AUDIO_MIXER_CLASS;
- dip->mixer_class = GUSMAX_INPUT_CLASS;
- dip->next = dip->prev = AUDIO_MIXER_LAST;
- strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
- break;
- case GUSMAX_OUTPUT_CLASS: /* output class descriptor */
- dip->type = AUDIO_MIXER_CLASS;
- dip->mixer_class = GUSMAX_OUTPUT_CLASS;
- dip->next = dip->prev = AUDIO_MIXER_LAST;
- strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
- break;
- case GUSMAX_MONITOR_CLASS: /* monitor class descriptor */
- dip->type = AUDIO_MIXER_CLASS;
- dip->mixer_class = GUSMAX_MONITOR_CLASS;
- dip->next = dip->prev = AUDIO_MIXER_LAST;
- strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name);
- break;
- case GUSMAX_RECORD_CLASS: /* record source class */
- dip->type = AUDIO_MIXER_CLASS;
- dip->mixer_class = GUSMAX_RECORD_CLASS;
- dip->next = dip->prev = AUDIO_MIXER_LAST;
- strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
- break;
- default:
- return ENXIO;
- /*NOTREACHED*/
- }
- DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
- return 0;
- }
- int
- gus_mixer_query_devinfo(void *addr, mixer_devinfo_t *dip)
- {
- struct gus_softc *sc = addr;
- DPRINTF(("gusmax_query_devinfo: index=%d\n", dip->index));
- if (!HAS_MIXER(sc) && dip->index > GUSICS_MASTER_MUTE)
- return ENXIO;
- switch(dip->index) {
- case GUSICS_MIC_IN_LVL: /* Microphone */
- dip->type = AUDIO_MIXER_VALUE;
- dip->mixer_class = GUSICS_INPUT_CLASS;
- dip->prev = AUDIO_MIXER_LAST;
- dip->next = GUSICS_MIC_IN_MUTE;
- strlcpy(dip->label.name, AudioNmicrophone,
- sizeof dip->label.name);
- dip->un.v.num_channels = 2;
- strlcpy(dip->un.v.units.name, AudioNvolume,
- sizeof dip->un.v.units.name);
- break;
- case GUSICS_LINE_IN_LVL: /* line */
- dip->type = AUDIO_MIXER_VALUE;
- dip->mixer_class = GUSICS_INPUT_CLASS;
- dip->prev = AUDIO_MIXER_LAST;
- dip->next = GUSICS_LINE_IN_MUTE;
- strlcpy(dip->label.name, AudioNline, sizeof dip->label.name);
- dip->un.v.num_channels = 2;
- strlcpy(dip->un.v.units.name, AudioNvolume,
- sizeof dip->un.v.units.name);
- break;
- case GUSICS_CD_LVL: /* cd */
- dip->type = AUDIO_MIXER_VALUE;
- dip->mixer_class = GUSICS_INPUT_CLASS;
- dip->prev = AUDIO_MIXER_LAST;
- dip->next = GUSICS_CD_MUTE;
- strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
- dip->un.v.num_channels = 2;
- strlcpy(dip->un.v.units.name, AudioNvolume,
- sizeof dip->un.v.units.name);
- break;
- case GUSICS_DAC_LVL: /* dacout */
- dip->type = AUDIO_MIXER_VALUE;
- dip->mixer_class = GUSICS_INPUT_CLASS;
- dip->prev = AUDIO_MIXER_LAST;
- dip->next = GUSICS_DAC_MUTE;
- strlcpy(dip->label.name, AudioNdac, sizeof dip->label.name);
- dip->un.v.num_channels = 2;
- strlcpy(dip->un.v.units.name, AudioNvolume,
- sizeof dip->un.v.units.name);
- break;
- case GUSICS_MASTER_LVL: /* master output */
- dip->type = AUDIO_MIXER_VALUE;
- dip->mixer_class = GUSICS_OUTPUT_CLASS;
- dip->prev = AUDIO_MIXER_LAST;
- dip->next = GUSICS_MASTER_MUTE;
- strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name);
- dip->un.v.num_channels = 2;
- strlcpy(dip->un.v.units.name, AudioNvolume,
- sizeof dip->un.v.units.name);
- break;
- case GUSICS_LINE_IN_MUTE:
- dip->mixer_class = GUSICS_INPUT_CLASS;
- dip->type = AUDIO_MIXER_ENUM;
- dip->prev = GUSICS_LINE_IN_LVL;
- dip->next = AUDIO_MIXER_LAST;
- goto mute;
- case GUSICS_DAC_MUTE:
- dip->mixer_class = GUSICS_INPUT_CLASS;
- dip->type = AUDIO_MIXER_ENUM;
- dip->prev = GUSICS_DAC_LVL;
- dip->next = AUDIO_MIXER_LAST;
- goto mute;
- case GUSICS_CD_MUTE:
- dip->mixer_class = GUSICS_INPUT_CLASS;
- dip->type = AUDIO_MIXER_ENUM;
- dip->prev = GUSICS_CD_LVL;
- dip->next = AUDIO_MIXER_LAST;
- goto mute;
- case GUSICS_MIC_IN_MUTE:
- dip->mixer_class = GUSICS_INPUT_CLASS;
- dip->type = AUDIO_MIXER_ENUM;
- dip->prev = GUSICS_MIC_IN_LVL;
- dip->next = AUDIO_MIXER_LAST;
- goto mute;
- case GUSICS_MASTER_MUTE:
- dip->mixer_class = GUSICS_OUTPUT_CLASS;
- dip->type = AUDIO_MIXER_ENUM;
- dip->prev = GUSICS_MASTER_LVL;
- dip->next = AUDIO_MIXER_LAST;
- mute:
- strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
- dip->un.e.num_mem = 2;
- strlcpy(dip->un.e.member[0].label.name, AudioNoff,
- sizeof dip->un.e.member[0].label.name);
- dip->un.e.member[0].ord = 0;
- strlcpy(dip->un.e.member[1].label.name, AudioNon,
- sizeof dip->un.e.member[1].label.name);
- dip->un.e.member[1].ord = 1;
- break;
- case GUSICS_RECORD_SOURCE:
- dip->mixer_class = GUSICS_RECORD_CLASS;
- dip->type = AUDIO_MIXER_ENUM;
- dip->prev = dip->next = AUDIO_MIXER_LAST;
- strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
- dip->un.e.num_mem = 1;
- strlcpy(dip->un.e.member[0].label.name, AudioNoutput,
- sizeof dip->un.e.member[0].label.name);
- dip->un.e.member[0].ord = GUSICS_MASTER_LVL;
- break;
- case GUSICS_INPUT_CLASS:
- dip->type = AUDIO_MIXER_CLASS;
- dip->mixer_class = GUSICS_INPUT_CLASS;
- dip->next = dip->prev = AUDIO_MIXER_LAST;
- strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
- break;
- case GUSICS_OUTPUT_CLASS:
- dip->type = AUDIO_MIXER_CLASS;
- dip->mixer_class = GUSICS_OUTPUT_CLASS;
- dip->next = dip->prev = AUDIO_MIXER_LAST;
- strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
- break;
- case GUSICS_RECORD_CLASS:
- dip->type = AUDIO_MIXER_CLASS;
- dip->mixer_class = GUSICS_RECORD_CLASS;
- dip->next = dip->prev = AUDIO_MIXER_LAST;
- strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
- break;
- default:
- return ENXIO;
- /*NOTREACHED*/
- }
- DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
- return 0;
- }
- int
- gus_query_encoding(void *addr, struct audio_encoding *fp)
- {
- switch (fp->index) {
- case 0:
- strlcpy(fp->name, AudioEslinear, sizeof fp->name);
- fp->encoding = AUDIO_ENCODING_SLINEAR;
- fp->precision = 8;
- fp->flags = 0;
- break;
- case 1:
- strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
- fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
- fp->precision = 16;
- fp->flags = 0;
- break;
- case 2:
- strlcpy(fp->name, AudioEulinear, sizeof fp->name);
- fp->encoding = AUDIO_ENCODING_ULINEAR;
- fp->precision = 8;
- fp->flags = 0;
- break;
- case 3:
- strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
- fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
- fp->precision = 16;
- fp->flags = 0;
- break;
- default:
- return(EINVAL);
- /*NOTREACHED*/
- }
- fp->bps = AUDIO_BPS(fp->precision);
- fp->msb = 1;
- return (0);
- }
- void *
- gus_malloc(void *addr, int direction, size_t size, int pool, int flags)
- {
- struct gus_softc *sc = addr;
- int drq;
- if (direction == AUMODE_PLAY)
- drq = sc->sc_drq;
- else
- drq = sc->sc_recdrq;
- return isa_malloc(sc->sc_isa, drq, size, pool, flags);
- }
- void
- gus_free(void *addr, void *ptr, int pool)
- {
- isa_free(ptr, pool);
- }
- size_t
- gus_round(void *addr, int direction, size_t size)
- {
- if (size > MAX_ISADMA)
- size = MAX_ISADMA;
- return size;
- }
- paddr_t
- gus_mappage(void *addr, void *mem, off_t off, int prot)
- {
- return isa_mappage(mem, off, prot);
- }
- /*
- * Setup the ICS mixer in "transparent" mode: reset everything to a sensible
- * level. Levels as suggested by GUS SDK code.
- */
- void
- gus_init_ics2101(struct gus_softc *sc)
- {
- struct ics2101_softc *ic = &sc->sc_mixer;
- sc->sc_mixer.sc_iot = sc->sc_iot;
- sc->sc_mixer.sc_selio = GUS_MIXER_SELECT;
- sc->sc_mixer.sc_selio_ioh = sc->sc_ioh3;
- sc->sc_mixer.sc_dataio = GUS_MIXER_DATA;
- sc->sc_mixer.sc_dataio_ioh = sc->sc_ioh2;
- sc->sc_mixer.sc_flags = (sc->sc_revision == 5) ? ICS_FLIP : 0;
- ics2101_mix_attenuate(ic,
- GUSMIX_CHAN_MIC,
- ICSMIX_LEFT,
- ICSMIX_MIN_ATTN);
- ics2101_mix_attenuate(ic,
- GUSMIX_CHAN_MIC,
- ICSMIX_RIGHT,
- ICSMIX_MIN_ATTN);
- /*
- * Start with microphone muted by the mixer...
- */
- gusics_mic_mute(ic, 1);
- /* ... and enabled by the GUS master mix control */
- gus_mic_ctl(sc, SPKR_ON);
- ics2101_mix_attenuate(ic,
- GUSMIX_CHAN_LINE,
- ICSMIX_LEFT,
- ICSMIX_MIN_ATTN);
- ics2101_mix_attenuate(ic,
- GUSMIX_CHAN_LINE,
- ICSMIX_RIGHT,
- ICSMIX_MIN_ATTN);
- ics2101_mix_attenuate(ic,
- GUSMIX_CHAN_CD,
- ICSMIX_LEFT,
- ICSMIX_MIN_ATTN);
- ics2101_mix_attenuate(ic,
- GUSMIX_CHAN_CD,
- ICSMIX_RIGHT,
- ICSMIX_MIN_ATTN);
- ics2101_mix_attenuate(ic,
- GUSMIX_CHAN_DAC,
- ICSMIX_LEFT,
- ICSMIX_MIN_ATTN);
- ics2101_mix_attenuate(ic,
- GUSMIX_CHAN_DAC,
- ICSMIX_RIGHT,
- ICSMIX_MIN_ATTN);
- ics2101_mix_attenuate(ic,
- ICSMIX_CHAN_4,
- ICSMIX_LEFT,
- ICSMIX_MAX_ATTN);
- ics2101_mix_attenuate(ic,
- ICSMIX_CHAN_4,
- ICSMIX_RIGHT,
- ICSMIX_MAX_ATTN);
- ics2101_mix_attenuate(ic,
- GUSMIX_CHAN_MASTER,
- ICSMIX_LEFT,
- ICSMIX_MIN_ATTN);
- ics2101_mix_attenuate(ic,
- GUSMIX_CHAN_MASTER,
- ICSMIX_RIGHT,
- ICSMIX_MIN_ATTN);
- /* unmute other stuff: */
- gusics_cd_mute(ic, 0);
- gusics_dac_mute(ic, 0);
- gusics_linein_mute(ic, 0);
- return;
- }
- void
- gus_subattach(struct gus_softc *sc, struct isa_attach_args *ia)
- {
- int i;
- bus_space_tag_t iot;
- unsigned char c,d,m;
- iot = sc->sc_iot;
- /*
- * Figure out our board rev, and see if we need to initialize the
- * mixer
- */
- c = bus_space_read_1(iot, sc->sc_ioh3, GUS_BOARD_REV);
- if (c != 0xff)
- sc->sc_revision = c;
- else
- sc->sc_revision = 0;
- SELECT_GUS_REG(iot, sc->sc_ioh2, GUSREG_RESET);
- bus_space_write_1(iot, sc->sc_ioh2, GUS_DATA_HIGH, 0x00);
- gusreset(sc, GUS_MAX_VOICES); /* initialize all voices */
- gusreset(sc, GUS_MIN_VOICES); /* then set to just the ones we use */
- /*
- * Setup the IRQ and DRQ lines in software, using values from
- * config file
- */
- m = GUSMASK_LINE_IN|GUSMASK_LINE_OUT; /* disable all */
- c = ((unsigned char) gus_irq_map[ia->ia_irq]) | GUSMASK_BOTH_RQ;
- if (sc->sc_recdrq == sc->sc_drq)
- d = (unsigned char) (gus_drq_map[sc->sc_drq] |
- GUSMASK_BOTH_RQ);
- else
- d = (unsigned char) (gus_drq_map[sc->sc_drq] |
- gus_drq_map[sc->sc_recdrq] << 3);
- /*
- * Program the IRQ and DMA channels on the GUS. Note that we hardwire
- * the GUS to only use one IRQ channel, but we give the user the
- * option of using two DMA channels (the other one given by the drq2
- * option in the config file). Two DMA channels are needed for full-
- * duplex operation.
- *
- * The order of these operations is very magical.
- */
- disable_intr(); /* XXX needed? */
- bus_space_write_1(iot, sc->sc_ioh1, GUS_REG_CONTROL, GUS_REG_IRQCTL);
- bus_space_write_1(iot, sc->sc_ioh1, GUS_MIX_CONTROL, m);
- bus_space_write_1(iot, sc->sc_ioh1, GUS_IRQCTL_CONTROL, 0x00);
- bus_space_write_1(iot, sc->sc_ioh1, 0x0f, 0x00);
- bus_space_write_1(iot, sc->sc_ioh1, GUS_MIX_CONTROL, m);
- /* magic reset? */
- bus_space_write_1(iot, sc->sc_ioh1, GUS_DMA_CONTROL, d | 0x80);
- bus_space_write_1(iot, sc->sc_ioh1, GUS_MIX_CONTROL,
- m | GUSMASK_CONTROL_SEL);
- bus_space_write_1(iot, sc->sc_ioh1, GUS_IRQ_CONTROL, c);
- bus_space_write_1(iot, sc->sc_ioh1, GUS_MIX_CONTROL, m);
- bus_space_write_1(iot, sc->sc_ioh1, GUS_DMA_CONTROL, d);
- bus_space_write_1(iot, sc->sc_ioh1, GUS_MIX_CONTROL,
- m | GUSMASK_CONTROL_SEL);
- bus_space_write_1(iot, sc->sc_ioh1, GUS_IRQ_CONTROL, c);
- bus_space_write_1(iot, sc->sc_ioh2, GUS_VOICE_SELECT, 0x00);
- /* enable line in, line out. leave mic disabled. */
- bus_space_write_1(iot, sc->sc_ioh1, GUS_MIX_CONTROL,
- (m | GUSMASK_LATCHES) & ~(GUSMASK_LINE_OUT|GUSMASK_LINE_IN));
- bus_space_write_1(iot, sc->sc_ioh2, GUS_VOICE_SELECT, 0x00);
- enable_intr();
- sc->sc_mixcontrol =
- (m | GUSMASK_LATCHES) & ~(GUSMASK_LINE_OUT|GUSMASK_LINE_IN);
- sc->sc_codec.sc_isa = sc->sc_isa;
- if (sc->sc_revision >= 5 && sc->sc_revision <= 9) {
- sc->sc_flags |= GUS_MIXER_INSTALLED;
- gus_init_ics2101(sc);
- }
- if (sc->sc_revision < 10 || !gus_init_cs4231(sc)) {
- /* Not using the CS4231, so create our DMA maps. */
- if (sc->sc_drq != -1) {
- if (isa_dmamap_create(sc->sc_isa, sc->sc_drq,
- MAX_ISADMA, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
- printf("%s: can't create map for drq %d\n",
- sc->sc_dev.dv_xname, sc->sc_drq);
- return;
- }
- }
- if (sc->sc_recdrq != -1 && sc->sc_recdrq != sc->sc_drq) {
- if (isa_dmamap_create(sc->sc_isa, sc->sc_recdrq,
- MAX_ISADMA, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
- printf("%s: can't create map for drq %d\n",
- sc->sc_dev.dv_xname, sc->sc_recdrq);
- return;
- }
- }
- }
- timeout_set(&sc->sc_dma_tmo, gus_dmaout_timeout, sc);
- SELECT_GUS_REG(iot, sc->sc_ioh2, GUSREG_RESET);
- /*
- * Check to see how much memory we have on this card; see if any
- * "mirroring" occurs. We're assuming at least 256K already exists
- * on the card; otherwise the initial probe would have failed
- */
- guspoke(iot, sc->sc_ioh2, 0L, 0x00);
- for(i = 1; i < 1024; i++) {
- u_long loc;
- /*
- * See if we've run into mirroring yet
- */
- if (guspeek(iot, sc->sc_ioh2, 0L) != 0)
- break;
- loc = i << 10;
- guspoke(iot, sc->sc_ioh2, loc, 0xaa);
- if (guspeek(iot, sc->sc_ioh2, loc) != 0xaa)
- break;
- }
- sc->sc_dsize = i;
- /*
- * The "official" (3.x) version number cannot easily be obtained.
- * The revision register does not correspond to the minor number
- * of the board version. Simply use the revision register as
- * identification.
- */
- snprintf(gus_device.version, sizeof gus_device.version, "%d",
- sc->sc_revision);
- printf(": ver %d", sc->sc_revision);
- if (sc->sc_revision >= 10)
- printf(", MAX");
- else {
- if (HAS_MIXER(sc))
- printf(", ICS2101 mixer");
- if (HAS_CODEC(sc))
- printf(", %s codec/mixer", sc->sc_codec.chip_name);
- }
- printf(", %dKB DRAM, ", sc->sc_dsize);
- if (sc->sc_recdrq == sc->sc_drq) {
- printf("half-duplex");
- } else {
- printf("full-duplex, record drq %d", sc->sc_recdrq);
- }
- printf("\n");
- /*
- * Setup a default interrupt handler
- */
- sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq,
- IST_EDGE, IPL_AUDIO | IPL_MPSAFE,
- gusintr, sc /* sc->sc_gusdsp */, sc->sc_dev.dv_xname);
- /*
- * Set some default values
- * XXX others start with 8kHz mono mulaw
- */
- sc->sc_irate = sc->sc_orate = 44100;
- sc->sc_encoding = AUDIO_ENCODING_SLINEAR_LE;
- sc->sc_precision = 16;
- sc->sc_voc[GUS_VOICE_LEFT].voccntl |= GUSMASK_DATA_SIZE16;
- sc->sc_voc[GUS_VOICE_RIGHT].voccntl |= GUSMASK_DATA_SIZE16;
- sc->sc_channels = 1;
- sc->sc_ogain = 340;
- gus_commit_settings(sc);
- /*
- * We always put the left channel full left & right channel
- * full right.
- * For mono playback, we set up both voices playing the same buffer.
- */
- bus_space_write_1(iot, sc->sc_ioh2, GUS_VOICE_SELECT,
- (u_char)GUS_VOICE_LEFT);
- SELECT_GUS_REG(iot, sc->sc_ioh2, GUSREG_PAN_POS);
- bus_space_write_1(iot, sc->sc_ioh2, GUS_DATA_HIGH, GUS_PAN_FULL_LEFT);
- bus_space_write_1(iot, sc->sc_ioh2, GUS_VOICE_SELECT,
- (u_char)GUS_VOICE_RIGHT);
- SELECT_GUS_REG(iot, sc->sc_ioh2, GUSREG_PAN_POS);
- bus_space_write_1(iot, sc->sc_ioh2, GUS_DATA_HIGH, GUS_PAN_FULL_RIGHT);
- /*
- * Attach to the generic audio layer
- */
- audio_attach_mi(&gus_hw_if, HAS_CODEC(sc) ? (void *)&sc->sc_codec :
- (void *)sc, &sc->sc_dev);
- }
- /*
- * Test to see if a particular I/O base is valid for the GUS. Return true
- * if it is.
- */
- int
- gus_test_iobase (bus_space_tag_t iot, int iobase)
- {
- bus_space_handle_t ioh1, ioh2, ioh3, ioh4;
- u_char s1, s2;
- int rv = 0;
- /* Map i/o space */
- if (bus_space_map(iot, iobase, GUS_NPORT1, 0, &ioh1))
- return 0;
- if (bus_space_map(iot, iobase+GUS_IOH2_OFFSET, GUS_NPORT2, 0, &ioh2))
- goto bad1;
- /* XXX Maybe we shouldn't fail on mapping this, but just assume
- * the card is of revision 0? */
- if (bus_space_map(iot, iobase+GUS_IOH3_OFFSET, GUS_NPORT3, 0, &ioh3))
- goto bad2;
- if (bus_space_map(iot, iobase+GUS_IOH4_OFFSET, GUS_NPORT4, 0, &ioh4))
- goto bad3;
- /*
- * Reset GUS to an initial state before we do anything.
- */
- mtx_enter(&audio_lock);
- delay(500);
- SELECT_GUS_REG(iot, ioh2, GUSREG_RESET);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00);
- delay(500);
- SELECT_GUS_REG(iot, ioh2, GUSREG_RESET);
- bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, GUSMASK_MASTER_RESET);
- delay(500);
- mtx_leave(&audio_lock);
- /*
- * See if we can write to the board's memory
- */
- s1 = guspeek(iot, ioh2, 0L);
- s2 = guspeek(iot, ioh2, 1L);
- guspoke(iot, ioh2, 0L, 0xaa);
- guspoke(iot, ioh2, 1L, 0x55);
- if (guspeek(iot, ioh2, 0L) != 0xaa)
- goto bad;
- guspoke(iot, ioh2, 0L, s1);
- guspoke(iot, ioh2, 1L, s2);
- rv = 1;
- bad:
- bus_space_unmap(iot, ioh4, GUS_NPORT4);
- bad3:
- bus_space_unmap(iot, ioh3, GUS_NPORT3);
- bad2:
- bus_space_unmap(iot, ioh2, GUS_NPORT2);
- bad1:
- bus_space_unmap(iot, ioh1, GUS_NPORT1);
- return rv;
- }
|