YMF754.Mod 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729
  1. MODULE YMF754; (** AUTHOR "mvt"; PURPOSE "Sound driver for Yamaha YMF754"; *)
  2. IMPORT
  3. SYSTEM, PCI, Strings, Files, Machine, Modules, SoundDevices,
  4. Plugins, Objects, Kernel, KernelLog;
  5. CONST
  6. (* Driver related constants *)
  7. Logging = TRUE; (* output to kernel log? *)
  8. FNameInstRAM = "YMF754.Bin"; (* name of instruction RAM file *)
  9. PluginDescPrefix = "Sound driver for Yamaha ";
  10. BufferSizeMS = 100; (* size of sound buffer in milliseconds *)
  11. (* Device related constants *)
  12. SizeDSPInstRAM = 80H;
  13. SizeCtrlInstRAM = 3000H;
  14. NofPlaySlots = 64;
  15. NofPlaySlotPairs = NofPlaySlots DIV 2;
  16. NofBanks = 2;
  17. NofMixerChannels = 6;
  18. NofNativeFreq = 7;
  19. WorkBitTimeout = 250000;
  20. (* PCI configuration register offsets *)
  21. PCIRegDS1EControl = 48H;
  22. (* PCI Audio control register offsets *)
  23. PCCRegAC97CmdData = 0060H;
  24. PCCRegAC97CmdAddress = 0062H;
  25. PCCRegAC97StatusData = 0064H;
  26. PCCRegAC97StatusAddress = 0066H;
  27. PCCRegVolLegOut = 0080H;
  28. PCCRegVolDACOut = 0084H;
  29. PCCRegVolZVOut = 0088H;
  30. PCCRegVolSecAC97Out = 008CH;
  31. PCCRegVolADCOut = 0090H;
  32. PCCRegVolADCIn = 00A8H;
  33. PCCRegVolRECIn = 00ACH;
  34. PCCRegVolP44Out = 00B0H;
  35. PCCRegVolSPDIFOut = 00B8H;
  36. PCCRegADCSlotSamplingRate = 00C0H;
  37. PCCRegADCSlotFormat = 00C8H;
  38. PCCRegStatus = 0100H;
  39. PCCRegControlSelect = 0104H;
  40. PCCRegMode = 0108H;
  41. PCCRegConfig = 0114H;
  42. PCCRegPlayCtrlSize = 0140H;
  43. PCCRegRecCtrlSize = 0144H;
  44. PCCRegMapOfRec = 0150H;
  45. PCCRegMapOfEff = 0154H;
  46. PCCRegPlayCtrlBase = 0158H;
  47. PCCRegRecCtrlBase = 015CH;
  48. PCCRegEffCtrlBase = 0160H;
  49. PCCRegWorkBase = 0164H;
  50. PCCRegDSPInstRAM = 1000H;
  51. PCCRegCtrlInstRAM = 4000H;
  52. (* AC97 control register offsets *)
  53. ACCRegReset = 00H;
  54. ACCRegVolMasterOut = 02H;
  55. ACCRegVolMic = 0EH;
  56. ACCRegVolLineIn = 10H;
  57. ACCRegVolCD = 12H;
  58. ACCRegVolPCM = 18H;
  59. ACCRegRecordSelect = 1AH;
  60. ACCRegRecordGain= 1CH;
  61. TYPE
  62. BufferListener = SoundDevices.BufferListener;
  63. Buffer = SoundDevices.Buffer;
  64. MixerChangedProc = SoundDevices.MixerChangedProc;
  65. (* Native frequencies table *)
  66. NativeFreqTable = ARRAY NofNativeFreq OF RECORD
  67. hz: LONGINT; (* frequency in Hz *)
  68. valRec: LONGINT; (* corresponding value to write to record register *)
  69. valLpfK: LONGINT; (* corresponding value to write to LpfK registers *)
  70. valLpfQ: LONGINT; (* corresponding value to write to LpfQ registers *)
  71. END;
  72. (* Mixer channel listener list type *)
  73. ListMixerChangedProc = POINTER TO RECORD
  74. proc: MixerChangedProc;
  75. next: ListMixerChangedProc
  76. END;
  77. (* Buffer list type *)
  78. ListBuffer = POINTER TO RECORD
  79. buff: Buffer;
  80. next: ListBuffer;
  81. END;
  82. (* Player channel list type *)
  83. ListPlayerChannel = POINTER TO RECORD
  84. channel: PlayerChannel;
  85. next: ListPlayerChannel;
  86. END;
  87. (* String types *)
  88. NameStr = ARRAY 32 OF CHAR;
  89. DescStr = ARRAY 128 OF CHAR;
  90. (* Buffer type for playing and recording data *)
  91. PlayRecBuffer = POINTER TO ARRAY OF CHAR;
  92. (* PCI Audio play control data table *)
  93. PlayCtrlDataTable = RECORD
  94. numOfPlay: LONGINT;
  95. playSlotBase: ARRAY NofPlaySlots OF LONGINT;
  96. END;
  97. (* PCI Audio record slot control data *)
  98. RecSlotCtrlData = RECORD
  99. recSlotREC: ARRAY NofBanks OF RecBank;
  100. recSlotADC: ARRAY NofBanks OF RecBank;
  101. END;
  102. (* Bank for record slot control data
  103. For description of the fields, see YMF754 hardware specification manual *)
  104. RecBank = RECORD;
  105. pgBase,
  106. pgLoopEndAdr,
  107. pgStartAdr,
  108. numOfLoops: LONGINT;
  109. END;
  110. (* Bank for play slot control data
  111. For description of the fields, see YMF754 hardware specification manual *)
  112. PlayBank = RECORD
  113. format, loopDefault, pgBase, pgLoop, pgLoopEnd, pgLoopFrac,
  114. pgDeltaEnd, lpfKEnd, egGainEnd, lchGainEnd, rchGainEnd, effect1GainEnd,
  115. effect2GainEnd, effect3GainEnd, lpfQ, status, numOfFrames, loopCount,
  116. pgStart, pgStartFrac, pgDelta, lpfK, egGain, lchGain,
  117. rchGain, effect1Gain, effect2Gain, effect3Gain, lpfD1, lpfD2: LONGINT;
  118. END;
  119. (* PCI Audio play slot control data *)
  120. PlaySlotCtrlData = ARRAY NofBanks OF PlayBank;
  121. (* Active object for calling buffer listeners *)
  122. BufferListenerCaller = OBJECT
  123. VAR
  124. bufferListener: BufferListener; (* this one will be called - NIL if none is registered *)
  125. first, last: ListBuffer; (* first and last pointer of queue *)
  126. close: BOOLEAN; (* close state: return all buffers and end ACTIVE part *)
  127. actualListener: BufferListener; (* used by ACTIVE part *)
  128. actualBuffer: Buffer; (* used by ACTIVE part *)
  129. (* Constructor *)
  130. PROCEDURE &Constr*;
  131. BEGIN
  132. bufferListener := NIL;
  133. first := NIL;
  134. last := NIL;
  135. close := FALSE;
  136. END Constr;
  137. (* Go to close state *)
  138. PROCEDURE Close;
  139. BEGIN {EXCLUSIVE}
  140. close := TRUE;
  141. END Close;
  142. (* Register a new buffer listener *)
  143. PROCEDURE RegisterBufferListener(bufferListener: BufferListener);
  144. BEGIN {EXCLUSIVE}
  145. SELF.bufferListener := bufferListener;
  146. END RegisterBufferListener;
  147. (* Queue a buffer to be returned by listener *)
  148. PROCEDURE ReturnBuffer(buffer: Buffer);
  149. VAR item: ListBuffer;
  150. BEGIN {EXCLUSIVE}
  151. IF bufferListener = NIL THEN RETURN END;
  152. NEW(item);
  153. item.buff := buffer;
  154. item.next := NIL;
  155. IF first = NIL THEN
  156. first := item;
  157. last := item;
  158. ELSE
  159. last.next := item;
  160. last := item;
  161. END;
  162. END ReturnBuffer;
  163. (* Active part of object *)
  164. BEGIN {ACTIVE, SAFE, PRIORITY(Objects.High)}
  165. WHILE ~close DO
  166. BEGIN {EXCLUSIVE}
  167. AWAIT((first # NIL) OR close);
  168. IF ~close THEN
  169. (* get actual listener and buffer for calling afterwards *)
  170. actualListener := bufferListener;
  171. actualBuffer := first.buff;
  172. first := first.next;
  173. END;
  174. END;
  175. (* Do listener calls outside of EXCLUSIVE region! *)
  176. IF close THEN
  177. (* return all buffers *)
  178. WHILE first # NIL DO
  179. bufferListener(first.buff);
  180. first := first.next;
  181. END;
  182. ELSE
  183. (* return actual buffer *)
  184. actualListener(actualBuffer);
  185. END;
  186. END;
  187. bufferListener := NIL;
  188. END BufferListenerCaller;
  189. (* PCI Audio control object *)
  190. PCIAudioControl = OBJECT
  191. VAR base: ADDRESS;
  192. CntrlInst1E: BOOLEAN; (* What Cntrl code to load: CntrlInst or CntrlInst1E *)
  193. (* Constructor *)
  194. PROCEDURE &Constr*(base: ADDRESS; CntrlInst1E: BOOLEAN);
  195. BEGIN
  196. SELF.base := base;
  197. SELF.CntrlInst1E := CntrlInst1E;
  198. END Constr;
  199. (* Routines for reading and writing PCI Audio registers *)
  200. PROCEDURE RegRead8(offset: LONGINT): LONGINT;
  201. BEGIN
  202. RETURN SYSTEM.GET8(base + offset);
  203. END RegRead8;
  204. PROCEDURE RegRead16(offset: LONGINT): LONGINT;
  205. BEGIN
  206. RETURN SYSTEM.GET16(base + offset);
  207. END RegRead16;
  208. PROCEDURE RegRead32(offset: LONGINT): LONGINT;
  209. BEGIN
  210. RETURN SYSTEM.GET32(base + offset);
  211. END RegRead32;
  212. PROCEDURE RegWrite8(offset: LONGINT; val: LONGINT);
  213. BEGIN
  214. SYSTEM.PUT8(base + offset, val);
  215. END RegWrite8;
  216. PROCEDURE RegWrite16(offset: LONGINT; val: LONGINT);
  217. BEGIN
  218. SYSTEM.PUT16(base + offset, val);
  219. END RegWrite16;
  220. PROCEDURE RegWrite32(offset: LONGINT; val: LONGINT);
  221. BEGIN
  222. SYSTEM.PUT32(base + offset, val);
  223. END RegWrite32;
  224. (* Initialize PCI Audio device *)
  225. PROCEDURE Initialize;
  226. VAR
  227. cnt: LONGINT;
  228. t: Kernel.Timer;
  229. BEGIN {EXCLUSIVE}
  230. (* Mute DAC volume before resetting *)
  231. RegWrite32(PCCRegVolDACOut, 0);
  232. (* Reset PCI Audio *)
  233. RegWrite32(PCCRegConfig, 0);
  234. cnt := 0;
  235. WHILE (cnt < WorkBitTimeout) & (1 IN SYSTEM.VAL(SET, RegRead32(PCCRegStatus))) DO
  236. INC(cnt);
  237. END;
  238. RegWrite32(PCCRegMode, 10000H);
  239. RegWrite32(PCCRegMode, 0);
  240. (* Init registers *)
  241. RegWrite32(PCCRegMapOfRec, 0);
  242. RegWrite32(PCCRegMapOfEff, 0);
  243. RegWrite32(PCCRegPlayCtrlBase, 0);
  244. RegWrite32(PCCRegRecCtrlBase, 0);
  245. RegWrite32(PCCRegEffCtrlBase, 0);
  246. RegWrite32(PCCRegWorkBase, 0);
  247. (* Load instruction code *)
  248. LoadInstructionCode;
  249. (* Enable DSP *)
  250. RegWrite32(PCCRegConfig, 1);
  251. (* Wait until instruction code takes effect *)
  252. NEW(t);
  253. cnt := 50; (* timeout = 50*2ms *)
  254. WHILE (cnt >= 0) & ~((SIZEOF(PlayBank) DIV 4 = RegRead32(PCCRegPlayCtrlSize)) & (SIZEOF(RecBank) DIV 4 = RegRead32(PCCRegRecCtrlSize))) DO
  255. t.Sleep(2); (* sleep for 2ms *)
  256. DEC(cnt);
  257. END;
  258. ASSERT(cnt >= 0); (* timeout - instruction code could not be correctly loaded! *)
  259. (* Sleep for 10ms before volume init to prevent scratching sounds *)
  260. t.Sleep(10);
  261. (* Mute unused native volumes *)
  262. RegWrite32(PCCRegVolLegOut, 0);
  263. RegWrite32(PCCRegVolZVOut, 0);
  264. RegWrite32(PCCRegVolSecAC97Out, 0);
  265. RegWrite32(PCCRegVolADCOut, 0);
  266. RegWrite32(PCCRegVolRECIn, 0);
  267. RegWrite32(PCCRegVolP44Out, 0);
  268. RegWrite32(PCCRegVolSPDIFOut, 0);
  269. (* Maximize DAC volume *)
  270. RegWrite32(PCCRegVolDACOut, 3FFF3FFFH);
  271. (* Minimize ADC volume (record channel volume) *)
  272. RegWrite32(PCCRegVolADCIn, 0);
  273. END Initialize;
  274. (* Uninitialize PCI Audio device *)
  275. PROCEDURE UnInitialize;
  276. VAR cnt: LONGINT;
  277. BEGIN {EXCLUSIVE}
  278. (* Mute volumes *)
  279. RegWrite32(PCCRegVolDACOut, 0);
  280. RegWrite32(PCCRegVolADCIn, 0);
  281. (* Reset PCI Audio *)
  282. RegWrite32(PCCRegConfig, 0);
  283. cnt := 0;
  284. WHILE (cnt < WorkBitTimeout) & (1 IN SYSTEM.VAL(SET, RegRead32(PCCRegStatus))) DO
  285. INC(cnt);
  286. END;
  287. RegWrite32(PCCRegMode, 10000H);
  288. (* Init registers *)
  289. RegWrite32(PCCRegMapOfRec, 0);
  290. RegWrite32(PCCRegMapOfEff, 0);
  291. RegWrite32(PCCRegPlayCtrlBase, 0);
  292. RegWrite32(PCCRegRecCtrlBase, 0);
  293. RegWrite32(PCCRegEffCtrlBase, 0);
  294. RegWrite32(PCCRegWorkBase, 0);
  295. END UnInitialize;
  296. (* Load instruction code into device RAM *)
  297. PROCEDURE LoadInstructionCode;
  298. VAR
  299. f: Files.File;
  300. r: Files.Reader;
  301. offset, data: LONGINT;
  302. BEGIN
  303. f := Files.Old(FNameInstRAM);
  304. ASSERT(f # NIL); (* assert existance of file *)
  305. ASSERT(f.Length() = SizeDSPInstRAM + SizeCtrlInstRAM * 2); (* assert length of file *)
  306. Files.OpenReader(r, f, 0);
  307. offset := PCCRegDSPInstRAM; (* begin with DSP instruction code *)
  308. WHILE offset < (PCCRegCtrlInstRAM + SizeCtrlInstRAM) DO
  309. r.RawLInt(data);
  310. RegWrite32(offset, data);
  311. INC(offset, SIZEOF(LONGINT));
  312. IF offset = PCCRegDSPInstRAM + SizeDSPInstRAM THEN
  313. (* Switch to controller instruction code *)
  314. offset := PCCRegCtrlInstRAM;
  315. (* Skip CtrlInst code *)
  316. IF CntrlInst1E THEN
  317. r.SkipBytes(SizeCtrlInstRAM);
  318. END;
  319. END;
  320. END;
  321. END LoadInstructionCode;
  322. END PCIAudioControl;
  323. (* AC97 control object *)
  324. AC97Control = OBJECT
  325. VAR PCC: PCIAudioControl;
  326. (* Constructor *)
  327. PROCEDURE &Constr*(PCC: PCIAudioControl);
  328. BEGIN
  329. SELF.PCC := PCC;
  330. END Constr;
  331. (* Routines for reading and writing AC97 registers (always 16 Bit) *)
  332. PROCEDURE RegRead16(offset: LONGINT): LONGINT;
  333. BEGIN {EXCLUSIVE}
  334. PCC.RegWrite16(PCCRegAC97CmdAddress, offset + 8000H);
  335. ASSERT(BusyWait());
  336. RETURN PCC.RegRead16(PCCRegAC97StatusData);
  337. END RegRead16;
  338. PROCEDURE RegWrite16(offset: LONGINT; val: LONGINT);
  339. BEGIN {EXCLUSIVE}
  340. PCC.RegWrite16(PCCRegAC97CmdAddress, offset);
  341. PCC.RegWrite16(PCCRegAC97CmdData, val);
  342. ASSERT(BusyWait());
  343. END RegWrite16;
  344. (* Wait while AC97 controller is busy. Return FALSE when timeout occurs. *)
  345. PROCEDURE BusyWait(): BOOLEAN;
  346. VAR t: Kernel.MilliTimer;
  347. BEGIN
  348. Kernel.SetTimer(t, 2); (* timeout is 2 ms *)
  349. WHILE ~Kernel.Expired(t) DO
  350. IF ~(15 IN SYSTEM.VAL(SET, PCC.RegRead16(PCCRegAC97StatusAddress))) THEN
  351. RETURN TRUE;
  352. END;
  353. END;
  354. RETURN FALSE;
  355. END BusyWait;
  356. PROCEDURE Reset;
  357. BEGIN
  358. RegWrite16(ACCRegReset, 0);
  359. RegWrite16(ACCRegRecordSelect, 0505H); (* select stereo mix (also works for mono) *)
  360. END Reset;
  361. END AC97Control;
  362. (** MixerChannel object, allows to set and get volume information *)
  363. MixerChannel* = OBJECT(SoundDevices. MixerChannel)
  364. VAR
  365. drv: Driver; (* driver object *)
  366. name: NameStr; (* name of mixer channel *)
  367. desc: DescStr; (* description of mixer channel *)
  368. regVol: LONGINT; (* volume register offset *)
  369. inverted: BOOLEAN; (* is maximum register value = maximum volume or inverted? *)
  370. volBits: LONGINT; (* number of bits for volume range *)
  371. volume: LONGINT; (* current volume *)
  372. mute: BOOLEAN; (* current mute state *)
  373. (* Constructor *)
  374. PROCEDURE &Constr*(drv: Driver; regVol: LONGINT; inverted, mute: BOOLEAN; name: NameStr; desc: DescStr);
  375. VAR tmpVol: LONGINT;
  376. BEGIN
  377. SELF.drv := drv;
  378. SELF.regVol := regVol;
  379. SELF.inverted := inverted;
  380. SELF.name := name;
  381. SELF.desc := desc;
  382. (* Get number of volume bits *)
  383. drv.ACC.RegWrite16(regVol, 803FH); (* set first 6 bits and mute bit *)
  384. tmpVol := drv.ACC.RegRead16(regVol); (* read back volume value *)
  385. SELF.volBits := 0;
  386. WHILE ODD(tmpVol) DO
  387. tmpVol := LSH(tmpVol, -1);
  388. INC(SELF.volBits);
  389. END;
  390. SELF.mute := mute; (* set mute state of channel *)
  391. SetVolume(128); (* set volume to middle position *)
  392. END Constr;
  393. (* Call mixer channel listeners *)
  394. PROCEDURE CallListeners;
  395. VAR item: ListMixerChangedProc;
  396. BEGIN
  397. item := drv.mixerChannelListeners;
  398. WHILE item # NIL DO
  399. item.proc(SELF);
  400. item := item.next;
  401. END;
  402. END CallListeners;
  403. (** Return the name (as UTF-8 Unicode) of this channel *)
  404. PROCEDURE GetName*(VAR name : ARRAY OF CHAR);
  405. BEGIN
  406. COPY(SELF.name, name);
  407. END GetName;
  408. (** Return the description string (as UTF-8 Unicode) of this channel *)
  409. PROCEDURE GetDesc*(VAR desc : ARRAY OF CHAR);
  410. BEGIN
  411. COPY(SELF.desc, desc);
  412. END GetDesc;
  413. (** Set the volume of the channel (0-255) *)
  414. PROCEDURE SetVolume*(volume : LONGINT);
  415. BEGIN {EXCLUSIVE}
  416. ASSERT((volume >= 0) & (volume <= 255));
  417. SELF.volume := volume;
  418. IF inverted THEN
  419. volume := 255 - volume;
  420. END;
  421. volume := LSH(volume, volBits - 8); (* adapt volume resolution *)
  422. volume := volume + LSH(volume, 8); (* set L and R (also works for mono) *)
  423. IF SELF.mute THEN
  424. volume := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, volume) + {15});
  425. END;
  426. drv.ACC.RegWrite16(regVol, volume);
  427. CallListeners;
  428. END SetVolume;
  429. (** Get the volume of the channel (0-255) *)
  430. PROCEDURE GetVolume*() : LONGINT;
  431. BEGIN
  432. RETURN SELF.volume;
  433. END GetVolume;
  434. (** Mute or unmute the channel *)
  435. PROCEDURE SetMute*(mute : BOOLEAN);
  436. VAR volume: SET;
  437. BEGIN {EXCLUSIVE}
  438. SELF.mute := mute;
  439. volume := SYSTEM.VAL(SET, drv.ACC.RegRead16(regVol));
  440. IF mute THEN
  441. volume := volume + {15};
  442. ELSE
  443. volume := volume - {15};
  444. END;
  445. drv.ACC.RegWrite16(regVol, SYSTEM.VAL(LONGINT, volume));
  446. CallListeners;
  447. END SetMute;
  448. (** Get the mute-state of the channel *)
  449. PROCEDURE GetIsMute*() : BOOLEAN;
  450. BEGIN
  451. RETURN SELF.mute;
  452. END GetIsMute;
  453. END MixerChannel;
  454. (** Channel object *)
  455. Channel* = OBJECT(SoundDevices.Channel)
  456. VAR
  457. drv: Driver; (* driver object *)
  458. bufferListenerCaller: BufferListenerCaller; (* buffer listener call object *)
  459. buffFirst, buffLast: ListBuffer; (* buffer queue (FIFO) *)
  460. buffFirstPos: LONGINT; (* position in currently used buffer *)
  461. playRecBuff: PlayRecBuffer; (* ring buffer for playing/recording *)
  462. playRecBuffSize: LONGINT; (* size of ring buffer for playing/recording *)
  463. playRecBuffPhys: LONGINT; (* physical address of ring buffer *)
  464. playRecBuffPos: LONGINT; (* position marker in ring buffer in bytes *)
  465. samplePosition: LONGINT; (* current absolute position in samples *)
  466. bytesPerSampleExp: LONGINT; (* bytesPerSampleExp^2 = bytes per sample *)
  467. running: BOOLEAN; (* is channel currently playing/recording? *)
  468. closed: BOOLEAN; (* has channel been closed? *)
  469. volume: LONGINT; (* current volume *)
  470. (* Constructor *)
  471. PROCEDURE &Constr*(drv: Driver);
  472. BEGIN
  473. SELF.drv := drv;
  474. buffFirst := NIL;
  475. buffLast := NIL;
  476. buffFirstPos := 0;
  477. samplePosition := 0;
  478. running := FALSE;
  479. closed := FALSE;
  480. volume := 0;
  481. NEW(bufferListenerCaller);
  482. END Constr;
  483. (** Register a delegate that handles reuse / processing of buffers.
  484. Only one Buffer listener can be registered per channel.
  485. *)
  486. PROCEDURE RegisterBufferListener*(bufferListener : BufferListener);
  487. BEGIN {EXCLUSIVE}
  488. ASSERT(~closed);
  489. bufferListenerCaller.RegisterBufferListener(bufferListener);
  490. IF Logging THEN
  491. IF bufferListener = NIL THEN
  492. KernelLog.String("YMF754 - BufferListener unregistered");
  493. ELSE
  494. KernelLog.String("YMF754 - BufferListener registered");
  495. END;
  496. KernelLog.Ln;
  497. END;
  498. END RegisterBufferListener;
  499. (** Queue another buffer for playing / recording *)
  500. PROCEDURE QueueBuffer*(x : Buffer);
  501. VAR buffItem: ListBuffer;
  502. BEGIN {EXCLUSIVE}
  503. ASSERT(~closed);
  504. ASSERT(x # NIL);
  505. ASSERT(x.data # NIL);
  506. ASSERT(x.len MOD LSH(1, bytesPerSampleExp) = 0); (* Buffer length must be sample aligned *)
  507. NEW(buffItem);
  508. buffItem.buff := x;
  509. buffItem.next := NIL;
  510. IF buffFirst = NIL THEN
  511. buffFirst := buffItem;
  512. ELSE
  513. buffLast.next := buffItem;
  514. END;
  515. buffLast := buffItem;
  516. END QueueBuffer;
  517. (* Removes current buffer from queue and returns it to listener (if registered) - queue must not be empty! *)
  518. PROCEDURE ReturnCurrentBuffer;
  519. BEGIN
  520. bufferListenerCaller.ReturnBuffer(buffFirst.buff);
  521. buffFirst := buffFirst.next;
  522. buffFirstPos := 0;
  523. END ReturnCurrentBuffer;
  524. (* Prepare data - this procedure is called for each channel every time PCI Audio generates an interrupt *)
  525. PROCEDURE PrepareData;
  526. BEGIN
  527. HALT(99); (* abstract *)
  528. END PrepareData;
  529. (* Activate channel - init banks and start playback/record *)
  530. PROCEDURE Activate;
  531. BEGIN
  532. HALT(99); (* abstract *)
  533. END Activate;
  534. (* Deactivate channel - stop playback/record *)
  535. PROCEDURE Deactivate;
  536. BEGIN
  537. HALT(99); (* abstract *)
  538. END Deactivate;
  539. (* Set volume for play or record channel (0-255) *)
  540. PROCEDURE SetPlayRecVol(volume: LONGINT);
  541. BEGIN
  542. HALT(99); (* abstract *)
  543. END SetPlayRecVol;
  544. (** Set the current volume of the channel (8.8 bit fixed point value) *)
  545. PROCEDURE SetVolume*(volume : LONGINT);
  546. BEGIN {EXCLUSIVE}
  547. ASSERT(~closed);
  548. ASSERT(volume >= 0);
  549. SELF.volume := volume;
  550. IF volume > 255 THEN (* 1.0 fix point value is maximum volume *)
  551. volume := 255;
  552. END;
  553. SetPlayRecVol(volume);
  554. END SetVolume;
  555. (** Get the current volume of the channel (8.8 bit fixed point value) *)
  556. PROCEDURE GetVolume*() : LONGINT;
  557. BEGIN
  558. ASSERT(~closed);
  559. RETURN SELF.volume;
  560. END GetVolume;
  561. (** GetPosition returns the current position in samples. MAY CHANGE TO HUGEINT*)
  562. PROCEDURE GetPosition*() : LONGINT;
  563. BEGIN
  564. ASSERT(~closed);
  565. RETURN samplePosition;
  566. END GetPosition;
  567. (** Start playing / recording *)
  568. PROCEDURE Start*;
  569. BEGIN {EXCLUSIVE}
  570. ASSERT(~closed);
  571. IF ~running THEN
  572. Activate;
  573. running := TRUE;
  574. END;
  575. END Start;
  576. (** Pause playing / recording, no buffers are returned *)
  577. PROCEDURE Pause*;
  578. BEGIN {EXCLUSIVE}
  579. ASSERT(~closed);
  580. PauseChannel;
  581. END Pause;
  582. (** Stop the playing / recording and return all buffers *)
  583. PROCEDURE Stop*;
  584. BEGIN {EXCLUSIVE}
  585. ASSERT(~closed);
  586. StopChannel;
  587. END Stop;
  588. (* Used to prevent recursive calls of EXCLUSIVE sections *)
  589. PROCEDURE PauseChannel;
  590. BEGIN
  591. IF running THEN
  592. Deactivate;
  593. running := FALSE;
  594. END;
  595. END PauseChannel;
  596. (* Used to prevent recursive calls of EXCLUSIVE sections *)
  597. PROCEDURE StopChannel;
  598. BEGIN
  599. PauseChannel;
  600. (* Return all buffers *)
  601. WHILE buffFirst # NIL DO
  602. ReturnCurrentBuffer;
  603. END;
  604. samplePosition := 0;
  605. END StopChannel;
  606. END Channel;
  607. (** Player channel *)
  608. PlayerChannel* = OBJECT(Channel)
  609. VAR
  610. playSlotPair: LONGINT; (* play slot pair this channel is using *)
  611. playSlot: ARRAY 2 OF POINTER TO PlaySlotCtrlData; (* play slot control data *)
  612. playSlotPhys: ARRAY 2 OF LONGINT; (* physical address *)
  613. nofSubCh: LONGINT; (* number of sub channels *)
  614. silentData: CHAR; (* silent data byte *)
  615. (* Constructor *)
  616. PROCEDURE &ConstrPlay*(drv: Driver; sRate, sRes, nofSubCh, playslotpair: LONGINT);
  617. VAR
  618. i, j: LONGINT;
  619. pgDelta, lpfK, lpfQ: LONGINT;
  620. BEGIN
  621. Constr(drv); (* call parent constructor *)
  622. SELF.bytesPerSampleExp := nofSubCh - sRes;
  623. SELF.nofSubCh := nofSubCh;
  624. SELF.playSlotPair := playslotpair;
  625. INCL(drv.playSlotPairsUsed, playSlotPair); (* occupy this channels play slot pair *)
  626. drv.PlayerChannelListAdd(SELF); (* add to list of currently active player channels *)
  627. silentData := CHR(LSH(sRes, 7)); (* calculate silent data byte *)
  628. (* Allocate buffer memory / init buffer *)
  629. playRecBuffSize := sRate * nofSubCh * (2-sRes) * BufferSizeMS DIV 1000; (* calculate buffer size *)
  630. NEW(playRecBuff, playRecBuffSize);
  631. playRecBuffPhys := GetPhysicalAdr(ADDRESSOF(playRecBuff^), playRecBuffSize);
  632. playRecBuffPos := 0;
  633. (* Calculate pgDelta *)
  634. pgDelta := LSH(LSH(sRate, 15) DIV 48000, 13); (* sRate * 2^28 / 48000 *)
  635. (* Calculate lpfK and lpfQ *)
  636. i := 0;
  637. WHILE sRate > NativeFreqTab[i].hz DO
  638. INC(i); (* "i" can't go above upper array bound because sRate is asserted to be <= 48000 *)
  639. END;
  640. lpfK := NativeFreqTab[i].valLpfK;
  641. lpfQ := NativeFreqTab[i].valLpfQ;
  642. (* Allocate control data memory and init banks *)
  643. FOR i := 0 TO nofSubCh - 1 DO
  644. NEW(playSlot[i]);
  645. playSlotPhys[i] := GetPhysicalAdr(ADDRESSOF(playSlot[i]^), SIZEOF(PlaySlotCtrlData));
  646. FOR j := 0 TO NofBanks - 1 DO
  647. playSlot[i][j].format := i + LSH(nofSubCh-1, 16) + LSH(sRes, 31);
  648. playSlot[i][j].loopDefault := 0;
  649. playSlot[i][j].pgBase := playRecBuffPhys;
  650. playSlot[i][j].pgLoop := 0;
  651. playSlot[i][j].pgLoopEnd := LSH(playRecBuffSize, -bytesPerSampleExp);
  652. playSlot[i][j].pgLoopFrac := 0;
  653. playSlot[i][j].pgDeltaEnd := pgDelta;
  654. playSlot[i][j].lpfKEnd := lpfK;
  655. playSlot[i][j].egGainEnd := 0;
  656. playSlot[i][j].lchGainEnd := 40000000H;
  657. playSlot[i][j].rchGainEnd := 40000000H;
  658. playSlot[i][j].effect1GainEnd := 0;
  659. playSlot[i][j].effect2GainEnd := 0;
  660. playSlot[i][j].effect3GainEnd := 0;
  661. playSlot[i][j].lpfQ := lpfQ;
  662. playSlot[i][j].status := 0;
  663. playSlot[i][j].numOfFrames := 0;
  664. playSlot[i][j].loopCount := 0;
  665. playSlot[i][j].pgStart := 0;
  666. playSlot[i][j].pgStartFrac := 0;
  667. playSlot[i][j].pgDelta := pgDelta;
  668. playSlot[i][j].lpfK := lpfK;
  669. playSlot[i][j].egGain := 0;
  670. playSlot[i][j].lchGain := 40000000H;
  671. playSlot[i][j].rchGain := 40000000H;
  672. playSlot[i][j].effect1Gain := 0;
  673. playSlot[i][j].effect2Gain := 0;
  674. playSlot[i][j].effect3Gain := 0;
  675. playSlot[i][j].lpfD1 := 0;
  676. playSlot[i][j].lpfD2 := 0;
  677. END;
  678. END;
  679. SetVolume(255); (* set initial volume to maximum *)
  680. END ConstrPlay;
  681. (* Prepare data - this procedure is called for each channel every time PCI Audio generates an interrupt *)
  682. PROCEDURE PrepareData;
  683. VAR
  684. curBuffPos: LONGINT; (* current recording position in ring buffer in bytes *)
  685. copySize: LONGINT; (* size of next block to copy in bytes *)
  686. BEGIN
  687. IF ~running THEN RETURN END;
  688. curBuffPos := LSH(playSlot[0][drv.inactiveBank].pgStart, bytesPerSampleExp);
  689. WHILE (buffFirst # NIL) & (playRecBuffPos # curBuffPos) DO
  690. (* Calculate copy size *)
  691. copySize := curBuffPos - playRecBuffPos;
  692. IF copySize < 0 THEN
  693. copySize := playRecBuffSize - playRecBuffPos;
  694. END;
  695. copySize := Strings.Min(copySize, buffFirst.buff.len - buffFirstPos);
  696. (* Copy *)
  697. SYSTEM.MOVE(
  698. ADDRESSOF(buffFirst.buff.data^) + buffFirstPos,
  699. ADDRESSOF(playRecBuff^) + playRecBuffPos,
  700. copySize);
  701. INC(playRecBuffPos, copySize);
  702. INC(buffFirstPos, copySize);
  703. INC(samplePosition, LSH(copySize, -bytesPerSampleExp));
  704. (* Handle special cases *)
  705. IF playRecBuffPos = playRecBuffSize THEN
  706. playRecBuffPos := 0;
  707. END;
  708. IF buffFirstPos = buffFirst.buff.len THEN
  709. ReturnCurrentBuffer;
  710. END;
  711. END;
  712. (* Output silent data if no PCM data is available *)
  713. WHILE playRecBuffPos # curBuffPos DO
  714. playRecBuff[playRecBuffPos] := silentData;
  715. playRecBuffPos := (playRecBuffPos + 1) MOD playRecBuffSize;
  716. END;
  717. END PrepareData;
  718. (* Init banks and start playback/record *)
  719. PROCEDURE Activate;
  720. VAR copySize, i, j: LONGINT;
  721. BEGIN
  722. IF Logging THEN
  723. KernelLog.String("YMF754 - Starting PlayerChannel number ");
  724. KernelLog.Int(playSlotPair, 0);
  725. KernelLog.Ln;
  726. END;
  727. (* Init buffer *)
  728. playRecBuffPos := 0;
  729. WHILE (buffFirst # NIL) & (playRecBuffPos < playRecBuffSize) DO
  730. (* Calculate copy size *)
  731. copySize := Strings.Min(buffFirst.buff.len, playRecBuffSize - playRecBuffPos);
  732. (* Copy *)
  733. SYSTEM.MOVE(
  734. ADDRESSOF(buffFirst.buff.data^),
  735. ADDRESSOF(playRecBuff^) + playRecBuffPos,
  736. copySize);
  737. INC(playRecBuffPos, copySize);
  738. INC(buffFirstPos, copySize);
  739. INC(samplePosition, LSH(copySize, -bytesPerSampleExp));
  740. (* Handle special cases *)
  741. IF buffFirstPos = buffFirst.buff.len THEN
  742. ReturnCurrentBuffer;
  743. END;
  744. END;
  745. (* Output silent data if no PCM data is available *)
  746. FOR i := playRecBuffPos TO playRecBuffSize - 1 DO
  747. playRecBuff[i] := silentData;
  748. END;
  749. (* Init banks and start *)
  750. FOR i := 0 TO nofSubCh - 1 DO
  751. FOR j := 0 TO NofBanks - 1 DO
  752. playSlot[i][j].pgStart := 0;
  753. playSlot[i][j].pgStartFrac := 0;
  754. END;
  755. drv.PCD.playSlotBase[2*playSlotPair+i] := playSlotPhys[i];
  756. END;
  757. END Activate;
  758. (* Stop playback/record *)
  759. PROCEDURE Deactivate;
  760. VAR i: LONGINT;
  761. BEGIN
  762. IF Logging THEN
  763. KernelLog.String("YMF754 - Stopping/Pausing PlayerChannel number ");
  764. KernelLog.Int(playSlotPair, 0);
  765. KernelLog.Ln;
  766. END;
  767. FOR i := 0 TO nofSubCh - 1 DO
  768. drv.PCD.playSlotBase[2*playSlotPair+i] := 0;
  769. END;
  770. END Deactivate;
  771. (* Set volume for play or record channel (0-255) *)
  772. PROCEDURE SetPlayRecVol(volume: LONGINT);
  773. VAR i, j: LONGINT;
  774. BEGIN
  775. volume := LSH(volume, 22);
  776. FOR i := 0 TO nofSubCh - 1 DO
  777. IF running THEN
  778. playSlot[i][drv.inactiveBank].egGainEnd := volume;
  779. ELSE
  780. FOR j := 0 TO NofBanks - 1 DO
  781. playSlot[i][j].egGainEnd := volume;
  782. playSlot[i][j].egGain := volume;
  783. END;
  784. END;
  785. END;
  786. END SetPlayRecVol;
  787. (** Get kind of channel *)
  788. PROCEDURE GetChannelKind*(): LONGINT;
  789. BEGIN
  790. ASSERT(~closed);
  791. RETURN SoundDevices.ChannelPlay;
  792. END GetChannelKind;
  793. (** Close the channel, the driver may release any ressources reserved for it.
  794. The object is still there but can never be opened again *)
  795. PROCEDURE Close*;
  796. BEGIN {EXCLUSIVE}
  797. ASSERT(~closed);
  798. IF Logging THEN
  799. KernelLog.String("YMF754 - Closing PlayerChannel number ");
  800. KernelLog.Int(playSlotPair, 0);
  801. KernelLog.Ln;
  802. END;
  803. StopChannel; (* stop playing *)
  804. bufferListenerCaller.Close; (* close buffer listener caller object *)
  805. drv.PlayerChannelListRemove(SELF); (* remove from list uf currently active player channels *)
  806. EXCL(drv.playSlotPairsUsed, playSlotPair); (* free used play slot pair *)
  807. closed := TRUE;
  808. IF Logging THEN
  809. KernelLog.String("YMF754 - Closing done"); KernelLog.Ln;
  810. END;
  811. END Close;
  812. END PlayerChannel;
  813. (** Recoder channel *)
  814. RecordChannel* = OBJECT(Channel)
  815. VAR
  816. recSlot: POINTER TO RecSlotCtrlData; (* record slot control data *)
  817. recSlotPhys: LONGINT; (* physical address of it *)
  818. (* Constructor *)
  819. PROCEDURE &ConstrRec*(drv: Driver; sRate, sRes, nofSubCh: LONGINT);
  820. VAR i: LONGINT;
  821. BEGIN
  822. Constr(drv); (* call parent constructor *)
  823. bytesPerSampleExp := nofSubCh - sRes;
  824. (* Allocate buffer memory / init buffer *)
  825. playRecBuffSize := NativeFreqTab[sRate].hz * nofSubCh * (2-sRes) * BufferSizeMS DIV 1000; (* calculate buffer size *)
  826. NEW(playRecBuff, playRecBuffSize);
  827. playRecBuffPhys := GetPhysicalAdr(ADDRESSOF(playRecBuff^), playRecBuffSize);
  828. playRecBuffPos := 0;
  829. (* Allocate control data memory *)
  830. NEW(recSlot);
  831. recSlotPhys := GetPhysicalAdr(ADDRESSOF(recSlot^), SIZEOF(RecSlotCtrlData));
  832. (* Register control data memory *)
  833. drv.PCC.RegWrite32(PCCRegRecCtrlBase, recSlotPhys);
  834. (* Set channel config *)
  835. drv.PCC.RegWrite16(PCCRegADCSlotSamplingRate, NativeFreqTab[sRate].valRec);
  836. drv.PCC.RegWrite16(PCCRegADCSlotFormat, LSH(nofSubCh-1, 1) + sRes);
  837. (* Init ADC slot *)
  838. FOR i := 0 TO NofBanks - 1 DO
  839. recSlot.recSlotADC[i].pgBase := playRecBuffPhys;
  840. recSlot.recSlotADC[i].pgLoopEndAdr := playRecBuffSize;
  841. recSlot.recSlotADC[i].pgStartAdr := 0;
  842. recSlot.recSlotADC[i].numOfLoops := 0;
  843. END;
  844. SetVolume(255); (* set initial volume to maximum *)
  845. END ConstrRec;
  846. (* Prepare data - this procedure is called for each channel every time PCI Audio generates an interrupt *)
  847. PROCEDURE PrepareData;
  848. VAR
  849. curBuffPos: LONGINT; (* current recording position in ring buffer in bytes *)
  850. copySize: LONGINT; (* size of next block to copy in bytes *)
  851. BEGIN
  852. IF ~running THEN RETURN END;
  853. curBuffPos := recSlot.recSlotADC[drv.inactiveBank].pgStartAdr;
  854. WHILE (buffFirst # NIL) & (playRecBuffPos # curBuffPos) DO
  855. (* Calculate copy size *)
  856. copySize := curBuffPos - playRecBuffPos;
  857. IF copySize < 0 THEN
  858. copySize := playRecBuffSize - playRecBuffPos;
  859. END;
  860. copySize := Strings.Min(copySize, buffFirst.buff.len - buffFirstPos);
  861. (* Copy *)
  862. SYSTEM.MOVE(
  863. ADDRESSOF(playRecBuff^) + playRecBuffPos,
  864. ADDRESSOF(buffFirst.buff.data^) + buffFirstPos,
  865. copySize);
  866. INC(playRecBuffPos, copySize);
  867. INC(buffFirstPos, copySize);
  868. INC(samplePosition, LSH(copySize, -bytesPerSampleExp));
  869. (* Handle special cases *)
  870. IF playRecBuffPos = playRecBuffSize THEN
  871. playRecBuffPos := 0;
  872. END;
  873. IF buffFirstPos = buffFirst.buff.len THEN
  874. ReturnCurrentBuffer;
  875. END;
  876. END;
  877. END PrepareData;
  878. (* Init banks and start playback/record *)
  879. PROCEDURE Activate;
  880. VAR i: LONGINT;
  881. BEGIN
  882. IF Logging THEN
  883. KernelLog.String("YMF754 - Starting RecordChannel"); KernelLog.Ln;
  884. END;
  885. FOR i := 0 TO NofBanks - 1 DO
  886. recSlot.recSlotADC[i].pgStartAdr := 0;
  887. END;
  888. drv.PCC.RegWrite32(PCCRegMapOfRec, 2); (* activate ADC slot *)
  889. END Activate;
  890. (* Stop playback/record *)
  891. PROCEDURE Deactivate;
  892. BEGIN
  893. IF Logging THEN
  894. KernelLog.String("YMF754 - Stopping/Pausing RecordChannel"); KernelLog.Ln;
  895. END;
  896. drv.PCC.RegWrite32(PCCRegMapOfRec, 0); (* deactivate ADC slot *)
  897. playRecBuffPos := 0;
  898. END Deactivate;
  899. (* Set volume for play or record channel (0-255) *)
  900. PROCEDURE SetPlayRecVol(volume: LONGINT);
  901. BEGIN
  902. volume := LSH(volume, 6);
  903. drv.PCC.RegWrite32(PCCRegVolADCIn, volume + LSH(volume, 16));
  904. END SetPlayRecVol;
  905. (** Get kind of channel *)
  906. PROCEDURE GetChannelKind*(): LONGINT;
  907. BEGIN
  908. ASSERT(~closed);
  909. RETURN SoundDevices.ChannelRecord;
  910. END GetChannelKind;
  911. (** Close the channel, the driver may release any ressources reserved for it.
  912. The object is still there but can never be opened again *)
  913. PROCEDURE Close*;
  914. BEGIN {EXCLUSIVE}
  915. ASSERT(~closed);
  916. IF Logging THEN
  917. KernelLog.String("YMF754 - Closing RecordChannel"); KernelLog.Ln;
  918. END;
  919. StopChannel; (* stop recording *)
  920. bufferListenerCaller.Close; (* close buffer listener caller object *)
  921. SetPlayRecVol(0); (* mute ADC slot *)
  922. drv.recSlot := NIL; (* free record slot *)
  923. closed := TRUE;
  924. IF Logging THEN
  925. KernelLog.String("YMF754 - Closing done"); KernelLog.Ln;
  926. END;
  927. END Close;
  928. END RecordChannel;
  929. (** Driver object *)
  930. Driver* = OBJECT (SoundDevices.Driver)
  931. VAR
  932. base: ADDRESS; (* virtual PCI Audio register base address *)
  933. irq: LONGINT; (* IRQ number *)
  934. ACC: AC97Control; (* AC97 controller object *)
  935. PCC: PCIAudioControl; (* PCI Audio controller object *)
  936. PCD: POINTER TO PlayCtrlDataTable; (* PCI Audio play control data table *)
  937. mixerChannels: ARRAY NofMixerChannels OF MixerChannel; (* array of mixer channels *)
  938. mixerChannelListeners: ListMixerChangedProc; (* list of mixer channel listeners *)
  939. playChannels: ListPlayerChannel; (* list of currently active player channels *)
  940. playSlotPairsUsed: SET; (* set of currently used PlaySlotPairs *)
  941. recSlot: RecordChannel; (* record channel currently using record slot *)
  942. inactiveBank: LONGINT; (* bank that is currently not used by PCI Audio *)
  943. (* Constructor *)
  944. PROCEDURE &Constr*(name: ARRAY OF CHAR; physbase, irq: LONGINT; CntrlInst1E: BOOLEAN);
  945. VAR
  946. i: LONGINT; res: WORD;
  947. PCDbase: LONGINT; (* physical base address of PCI Audio play control data table *)
  948. BEGIN
  949. SELF.irq := irq;
  950. SELF.SetName(name);
  951. SELF.desc := PluginDescPrefix;
  952. Strings.Append(SELF.desc, name);
  953. (* Map base address *)
  954. Machine.MapPhysical(physbase, 8000H (* 32KB *), base);
  955. ASSERT(base # Machine.NilAdr);
  956. IF Logging THEN
  957. KernelLog.String(" Initializing driver object:"); KernelLog.Ln;
  958. KernelLog.String(" Device name: "); KernelLog.String(name); KernelLog.Ln;
  959. KernelLog.String(" Physical base address: "); KernelLog.Hex(physbase, 0); KernelLog.Char("h"); KernelLog.Ln;
  960. KernelLog.String(" Mapped base address: "); KernelLog.Hex(base, 0); KernelLog.Char("h"); KernelLog.Ln;
  961. KernelLog.String(" Mapped space: 32KB"); KernelLog.Ln;
  962. KernelLog.String(" Hardware interrupt (IRQ): "); KernelLog.Int(irq, 0); KernelLog.Ln;
  963. END;
  964. (* Create controller register objects *)
  965. NEW(PCC, base, CntrlInst1E);
  966. NEW(ACC, PCC);
  967. (* Initialize PCI Audio *)
  968. PCC.Initialize;
  969. (* Reset AC97 controller *)
  970. ACC.Reset;
  971. (* Init used slots and channels *)
  972. playChannels := NIL;
  973. playSlotPairsUsed := {};
  974. recSlot := NIL;
  975. inactiveBank := 0;
  976. (* Init mixer channel listener list *)
  977. mixerChannelListeners := NIL;
  978. (* Create mixer channel objects *)
  979. NEW(mixerChannels[0], SELF, ACCRegVolMasterOut, TRUE, FALSE, "MasterOut", "Master output mixer channel");
  980. NEW(mixerChannels[1], SELF, ACCRegRecordGain, FALSE, FALSE, "MasterIn", "Master input mixer channel");
  981. NEW(mixerChannels[2], SELF, ACCRegVolLineIn, TRUE, TRUE, "LineIn", "LineIn mixer channel");
  982. NEW(mixerChannels[3], SELF, ACCRegVolPCM, TRUE, FALSE, "PCM", "PCM mixer channel");
  983. NEW(mixerChannels[4], SELF, ACCRegVolCD, TRUE, TRUE, "CD", "CD mixer channel");
  984. NEW(mixerChannels[5], SELF, ACCRegVolMic, TRUE, TRUE, "Mic", "Microphone mixer channel");
  985. (* Allocate DMA memory for PCI Audio control data table *)
  986. NEW(PCD);
  987. PCDbase := GetPhysicalAdr(ADDRESSOF(PCD^), SIZEOF(PlayCtrlDataTable));
  988. (* Initialize PCI Audio play control data *)
  989. PCD.numOfPlay := NofPlaySlots;
  990. FOR i := 0 TO NofPlaySlots - 1 DO
  991. PCD.playSlotBase[i] := 0;
  992. END;
  993. PCC.RegWrite32(PCCRegPlayCtrlBase, PCDbase);
  994. ASSERT((irq >= 1) & (irq <= 15));
  995. (* Install Objects interrupt handler *)
  996. Objects.InstallHandler(HandleInterrupt, Machine.IRQ0+irq);
  997. (* Register in SoundDevices *)
  998. SoundDevices.devices.Add(SELF, res);
  999. ASSERT(res = Plugins.Ok);
  1000. (* Update table of all active sound drivers *)
  1001. SoundDevices.devices.GetAll(DriverTab);
  1002. IF Logging THEN
  1003. KernelLog.String(" Initializing finished."); KernelLog.Ln;
  1004. END;
  1005. END Constr;
  1006. (** Finalizer *)
  1007. PROCEDURE Finalize*;
  1008. VAR
  1009. item: ListPlayerChannel;
  1010. BEGIN
  1011. IF Logging THEN
  1012. KernelLog.String(" Finalizing driver object:"); KernelLog.Ln;
  1013. KernelLog.String(" Device name: "); KernelLog.String(name); KernelLog.Ln;
  1014. KernelLog.String(" Mapped base address: "); KernelLog.Hex(base, 0); KernelLog.Char("h"); KernelLog.Ln;
  1015. KernelLog.String(" Hardware interrupt (IRQ): "); KernelLog.Int(irq, 0); KernelLog.Ln;
  1016. END;
  1017. (* Close all channels *)
  1018. item := playChannels;
  1019. WHILE item # NIL DO
  1020. item.channel.Close;
  1021. item := item.next;
  1022. END;
  1023. IF recSlot # NIL THEN
  1024. recSlot.Close;
  1025. END;
  1026. (* Reset AC97 controller *)
  1027. ACC.Reset;
  1028. (* Uninitialize PCI Audio *)
  1029. PCC.UnInitialize;
  1030. (* Unmap base address *)
  1031. Machine.UnmapPhysical(base, 8000H (* 32KB *));
  1032. (* Remove plugin *)
  1033. SoundDevices.devices.Remove(SELF);
  1034. (* Update table of all active sound drivers *)
  1035. SoundDevices.devices.GetAll(DriverTab);
  1036. (* Remove Objects interrupt handler *)
  1037. Objects.RemoveHandler(HandleInterrupt, Machine.IRQ0+irq);
  1038. IF Logging THEN
  1039. KernelLog.String(" Finalizing finished."); KernelLog.Ln;
  1040. END;
  1041. END Finalize;
  1042. (* Interrupt handler *)
  1043. PROCEDURE HandleInterrupt;
  1044. VAR
  1045. item: ListPlayerChannel;
  1046. regMode: SET;
  1047. BEGIN
  1048. (* Check if PCI Audio generated the interrupt *)
  1049. IF ~(31 IN SYSTEM.VAL(SET, PCC.RegRead32(PCCRegStatus))) THEN RETURN END;
  1050. (* Handle PCI Audio interrupt *)
  1051. PCC.RegWrite32(PCCRegStatus, SYSTEM.VAL(LONGINT, {31})); (* deassert INTA# *)
  1052. inactiveBank := PCC.RegRead32(PCCRegControlSelect) MOD 2; (* get inactive bank *)
  1053. (* Prepare data in channels *)
  1054. item := playChannels;
  1055. WHILE item # NIL DO
  1056. item.channel.PrepareData;
  1057. item := item.next;
  1058. END;
  1059. IF recSlot # NIL THEN
  1060. recSlot.PrepareData;
  1061. END;
  1062. IF (playChannels = NIL) & (recSlot = NIL) THEN
  1063. (* Stop PCI Audio operation *)
  1064. PCC.RegWrite32(PCCRegMode, 0);
  1065. ELSE
  1066. (* Notify PCI Audio that interrupt has been finished *)
  1067. regMode := SYSTEM.VAL(SET, PCC.RegRead32(PCCRegMode));
  1068. INCL(regMode, 1);
  1069. PCC.RegWrite32(PCCRegMode, SYSTEM.VAL(LONGINT, regMode));
  1070. END;
  1071. END HandleInterrupt;
  1072. (** Sound device routines *)
  1073. PROCEDURE Init*;
  1074. (* Not used *)
  1075. END Init;
  1076. PROCEDURE Enable*;
  1077. (* Not used *)
  1078. END Enable;
  1079. PROCEDURE Disable*;
  1080. (* Not used *)
  1081. END Disable;
  1082. (** Capabilities *)
  1083. PROCEDURE NofNativeFrequencies*():LONGINT;
  1084. BEGIN
  1085. RETURN NofNativeFreq;
  1086. END NofNativeFrequencies;
  1087. PROCEDURE GetNativeFrequeny*(nr : LONGINT):LONGINT;
  1088. BEGIN
  1089. RETURN NativeFreqTab[nr].hz;
  1090. END GetNativeFrequeny;
  1091. PROCEDURE NofSamplingResolutions*():LONGINT;
  1092. BEGIN
  1093. RETURN 2; (* 16 Bit and 8 Bit *)
  1094. END NofSamplingResolutions;
  1095. PROCEDURE GetSamplingResolution*(nr : LONGINT):LONGINT;
  1096. BEGIN
  1097. ASSERT((nr >= 0) & (nr < 2));
  1098. IF nr = 0 THEN
  1099. RETURN 16;
  1100. ELSE
  1101. RETURN 8;
  1102. END;
  1103. END GetSamplingResolution;
  1104. (** How many different sub channel settings are possible *)
  1105. PROCEDURE NofSubChannelSettings*():LONGINT;
  1106. BEGIN
  1107. RETURN 2; (* mono and stereo *)
  1108. END NofSubChannelSettings;
  1109. (** Get sub channel setting nr. *)
  1110. PROCEDURE GetSubChannelSetting*(nr : LONGINT):LONGINT;
  1111. BEGIN
  1112. ASSERT((nr >= 0) & (nr < 2));
  1113. IF nr = 0 THEN
  1114. RETURN 1; (* mono *)
  1115. ELSE
  1116. RETURN 2; (* stereo *)
  1117. END;
  1118. END GetSubChannelSetting;
  1119. (** How many different wave formats are possible *)
  1120. PROCEDURE NofWaveFormats*():LONGINT;
  1121. BEGIN
  1122. RETURN 1; (* only PCM *)
  1123. END NofWaveFormats;
  1124. (** Get wave format nr. *)
  1125. PROCEDURE GetWaveFormat*(nr : LONGINT):LONGINT;
  1126. BEGIN
  1127. ASSERT(nr = 0);
  1128. RETURN SoundDevices.FormatPCM; (* PCM *)
  1129. END GetWaveFormat;
  1130. (** Playing *)
  1131. (** Open a new channel for playing
  1132. The maximum number of playing channels opened at the same time is 32.
  1133. res is the result code (see constants in SoundDevices)
  1134. channel is the resulting Play channel, NIL if an error occured.
  1135. samplingRate is the desired samplingRate ( IMPORTANT: all values from 8000 to 48000 are allowed ! )
  1136. samplingResolution = 8/16 Bit
  1137. nofSubChannes = 1 for Mono, 2 for Stereo
  1138. format is the wave format
  1139. *)
  1140. PROCEDURE OpenPlayChannel*(VAR channel : SoundDevices.Channel; samplingRate, samplingResolution, nofSubChannels, format : LONGINT; VAR res : WORD);
  1141. VAR
  1142. playSlotPair: LONGINT;
  1143. playChannel: PlayerChannel;
  1144. BEGIN {EXCLUSIVE}
  1145. (* Searching for free play slot pair *)
  1146. IF Logging THEN
  1147. KernelLog.String("YMF754 - Opening PlayerChannel");
  1148. END;
  1149. playSlotPair := 0;
  1150. WHILE (playSlotPair < NofPlaySlotPairs) & (playSlotPair IN playSlotPairsUsed) DO
  1151. INC(playSlotPair);
  1152. END;
  1153. IF playSlotPair = NofPlaySlotPairs THEN
  1154. IF Logging THEN
  1155. KernelLog.String(" - rejected: no more channels available"); KernelLog.Ln;
  1156. END;
  1157. res := SoundDevices.ResNoMoreChannels;
  1158. channel := NIL;
  1159. RETURN;
  1160. END;
  1161. (* Free play slot pair found *)
  1162. CheckChannelParam(FALSE, samplingRate, samplingResolution, nofSubChannels, format, res);
  1163. IF res = SoundDevices.ResOK THEN
  1164. NEW(playChannel, SELF, samplingRate, samplingResolution, nofSubChannels, playSlotPair);
  1165. IF Logging THEN
  1166. KernelLog.String(" number ");
  1167. KernelLog.Int(playSlotPair, 0);
  1168. KernelLog.String(" - done");
  1169. KernelLog.Ln;
  1170. END;
  1171. channel := playChannel;
  1172. StartPCIAudio;
  1173. ELSE
  1174. IF Logging THEN
  1175. KernelLog.String(" - rejected: invalid parameters"); KernelLog.Ln;
  1176. END;
  1177. channel := NIL;
  1178. END;
  1179. END OpenPlayChannel;
  1180. (** Recording *)
  1181. (** Open a new channel for recording.
  1182. Only one record channel can be opened at the same time!
  1183. res is the result code (see constants in SoundDevices)
  1184. channel is the resulting Recorder channel, NIL if an error occured.
  1185. samplingRate is the desired samplingRate ( IMPORTANT: only native frequencies are allowed ! )
  1186. samplingResolution = 8/16 Bit
  1187. nofSubChannes = 1 for Mono, 2 for Stereo
  1188. format is the wave format
  1189. *)
  1190. PROCEDURE OpenRecordChannel*(VAR channel : SoundDevices.Channel; samplingRate, samplingResolution, nofSubChannels, format : LONGINT; VAR res : WORD);
  1191. BEGIN {EXCLUSIVE}
  1192. IF Logging THEN
  1193. KernelLog.String("YMF754 - Opening RecordChannel");
  1194. END;
  1195. (* Testing for free record slot *)
  1196. IF recSlot # NIL THEN
  1197. IF Logging THEN
  1198. KernelLog.String(" - rejected: RecordChannel currently in use"); KernelLog.Ln;
  1199. END;
  1200. res := SoundDevices.ResNoMoreChannels;
  1201. channel := NIL;
  1202. RETURN;
  1203. END;
  1204. (* RecSlot is available *)
  1205. CheckChannelParam(TRUE, samplingRate, samplingResolution, nofSubChannels, format, res);
  1206. IF res = SoundDevices.ResOK THEN
  1207. NEW(recSlot, SELF, samplingRate, samplingResolution, nofSubChannels);
  1208. IF Logging THEN
  1209. KernelLog.String(" - done"); KernelLog.Ln;
  1210. END;
  1211. channel := recSlot;
  1212. StartPCIAudio;
  1213. ELSE
  1214. IF Logging THEN
  1215. KernelLog.String(" - rejected: invalid parameters"); KernelLog.Ln;
  1216. END;
  1217. channel := NIL;
  1218. END;
  1219. END OpenRecordChannel;
  1220. (* Start PCI Audio operation - if not already operating *)
  1221. PROCEDURE StartPCIAudio;
  1222. BEGIN
  1223. IF ~ODD(PCC.RegRead32(PCCRegMode)) THEN
  1224. (* Not operating - starting operation *)
  1225. PCC.RegWrite32(PCCRegMode, 3);
  1226. END;
  1227. END StartPCIAudio;
  1228. (* Check channel parameters and convert the values for internal use *)
  1229. PROCEDURE CheckChannelParam(onlyNativeFreq: BOOLEAN; VAR sRate, sResolution, nofSubCh, format: LONGINT; VAR res: WORD);
  1230. VAR i: LONGINT;
  1231. BEGIN
  1232. res := SoundDevices.ResOK;
  1233. (* Samling rate *)
  1234. IF onlyNativeFreq THEN
  1235. (* only native freqencies are allowed *)
  1236. i := 0;
  1237. WHILE (i < NofNativeFreq) & (NativeFreqTab[i].hz # sRate) DO INC(i) END;
  1238. IF i < NofNativeFreq THEN
  1239. sRate := i; (* corresponding array position is returned as sRate *)
  1240. ELSE
  1241. res := SoundDevices.ResUnsupportedFrequency;
  1242. END;
  1243. ELSE
  1244. (* all frequencies in specified range are allowed *)
  1245. IF (sRate < 8000) OR (sRate > 48000) THEN
  1246. res := SoundDevices.ResUnsupportedFrequency;
  1247. END;
  1248. END;
  1249. (* Sampling resolution *)
  1250. IF sResolution = 16 THEN
  1251. sResolution := 0;
  1252. ELSIF sResolution = 8 THEN
  1253. sResolution := 1;
  1254. ELSE
  1255. res := SoundDevices.ResUnsupportedSamplingRes;
  1256. END;
  1257. (* Sub channel setting *)
  1258. IF (nofSubCh # 1) & (nofSubCh # 2) THEN
  1259. res := SoundDevices.ResUnsupportedSubChannels;
  1260. END;
  1261. (* Format *)
  1262. IF format # SoundDevices.FormatPCM THEN
  1263. res := SoundDevices.ResUnsupportedFormat;
  1264. END;
  1265. END CheckChannelParam;
  1266. (* Add a player channel to the list of currently active player channels - always called by the channel itself *)
  1267. PROCEDURE PlayerChannelListAdd(channel: PlayerChannel);
  1268. VAR item: ListPlayerChannel;
  1269. BEGIN (* can't be exclusive because it is called by ConstrPlay() of object created in OpenPlayChannel() *)
  1270. ASSERT(channel # NIL);
  1271. NEW(item);
  1272. item.channel := channel;
  1273. item.next := playChannels;
  1274. playChannels := item;
  1275. END PlayerChannelListAdd;
  1276. (* Remove a player channel from the list of currently active player channels - always called by the channel itself *)
  1277. PROCEDURE PlayerChannelListRemove(channel: PlayerChannel);
  1278. VAR item: ListPlayerChannel;
  1279. BEGIN {EXCLUSIVE}
  1280. item := playChannels;
  1281. IF item = NIL THEN
  1282. (* not found - empty list *)
  1283. RETURN;
  1284. END;
  1285. IF item.channel = channel THEN
  1286. (* found - remove first item *)
  1287. playChannels := item.next;
  1288. RETURN;
  1289. END;
  1290. WHILE (item.next # NIL) & (item.next.channel # channel) DO
  1291. item := item.next;
  1292. END;
  1293. IF item.next # NIL THEN
  1294. (* found - remove item *)
  1295. item.next := item.next.next;
  1296. END;
  1297. END PlayerChannelListRemove;
  1298. (** Mixer *)
  1299. (** Register a listener for channel changes, the number of listeners is not limited.
  1300. Listeners run in the thread of the changeing program, therefore they have to
  1301. return control immediately after beeing called.
  1302. *)
  1303. PROCEDURE RegisterMixerChangeListener*(mixChangedProc : MixerChangedProc);
  1304. VAR item: ListMixerChangedProc;
  1305. BEGIN {EXCLUSIVE}
  1306. ASSERT(mixChangedProc # NIL);
  1307. NEW(item);
  1308. item.proc := mixChangedProc;
  1309. item.next := mixerChannelListeners;
  1310. mixerChannelListeners := item;
  1311. IF Logging THEN
  1312. KernelLog.String("YMF754 - MixerChangeListener registered"); KernelLog.Ln;
  1313. END;
  1314. END RegisterMixerChangeListener;
  1315. (** Unregister a previously registered listener *)
  1316. PROCEDURE UnregisterMixerChangeListener*(mixChangedProc : MixerChangedProc);
  1317. VAR item: ListMixerChangedProc;
  1318. BEGIN {EXCLUSIVE}
  1319. IF Logging THEN
  1320. KernelLog.String("YMF754 - Unregistering MixerChangeListener");
  1321. END;
  1322. item := mixerChannelListeners;
  1323. IF item = NIL THEN
  1324. (* not found - empty list *)
  1325. IF Logging THEN
  1326. KernelLog.String(" - failed: no listener was registered"); KernelLog.Ln;
  1327. END;
  1328. RETURN;
  1329. END;
  1330. IF item.proc = mixChangedProc THEN
  1331. (* found - remove first item *)
  1332. mixerChannelListeners := item.next;
  1333. IF Logging THEN
  1334. KernelLog.String(" - done"); KernelLog.Ln;
  1335. END;
  1336. RETURN;
  1337. END;
  1338. WHILE (item.next # NIL) & (item.next.proc # mixChangedProc) DO
  1339. item := item.next;
  1340. END;
  1341. IF item.next # NIL THEN
  1342. (* found - remove item *)
  1343. item.next := item.next.next;
  1344. IF Logging THEN
  1345. KernelLog.String(" - done"); KernelLog.Ln;
  1346. END;
  1347. ELSE
  1348. IF Logging THEN
  1349. KernelLog.String(" - failed: listener was not registered"); KernelLog.Ln;
  1350. END;
  1351. END;
  1352. END UnregisterMixerChangeListener;
  1353. (** Return channel object
  1354. channel 0 is always present and is specified as the master output volume
  1355. channel 1 is always present and is specified as the master input volume
  1356. Drivers may ignore channel 0 or 1 but need to return a generic "Channel" object for these channel numbers
  1357. GetMixerChannel returns NIL if the channelNr is invalid
  1358. *)
  1359. PROCEDURE GetMixerChannel*(channelNr : LONGINT; VAR channel : SoundDevices.MixerChannel);
  1360. VAR name: NameStr;
  1361. BEGIN
  1362. IF (channelNr >= 0) & (channelNr < NofMixerChannels) THEN
  1363. channel := mixerChannels[channelNr];
  1364. IF Logging THEN
  1365. channel.GetName(name);
  1366. KernelLog.String("YMF754 - GetMixerChannel (");
  1367. KernelLog.String(name);
  1368. KernelLog.String(")");
  1369. KernelLog.Ln;
  1370. END;
  1371. ELSE
  1372. channel := NIL;
  1373. END;
  1374. END GetMixerChannel;
  1375. (** Returns the number of mixer channels available, at least 2 *)
  1376. PROCEDURE GetNofMixerChannels*() : LONGINT;
  1377. BEGIN
  1378. RETURN NofMixerChannels;
  1379. END GetNofMixerChannels;
  1380. END Driver;
  1381. (* Module variables *)
  1382. VAR
  1383. NativeFreqTab: NativeFreqTable; (* parameter of native frequencies *)
  1384. DriverTab: Plugins.Table; (* table of all active sound drivers *)
  1385. (** Module routines *)
  1386. (* Fill native frequencies table *)
  1387. PROCEDURE FillNativeFreqTable;
  1388. BEGIN
  1389. NativeFreqTab[0].hz := 8000;
  1390. NativeFreqTab[0].valRec := 24575;
  1391. NativeFreqTab[0].valLpfK := 18B00000H;
  1392. NativeFreqTab[0].valLpfQ := 32020000H;
  1393. NativeFreqTab[1].hz := 11025;
  1394. NativeFreqTab[1].valRec := 17832;
  1395. NativeFreqTab[1].valLpfK := 20900000H;
  1396. NativeFreqTab[1].valLpfQ := 31780000H;
  1397. NativeFreqTab[2].hz := 16000;
  1398. NativeFreqTab[2].valRec := 12287;
  1399. NativeFreqTab[2].valLpfK := 2B980000H;
  1400. NativeFreqTab[2].valLpfQ := 31380000H;
  1401. NativeFreqTab[3].hz := 22050;
  1402. NativeFreqTab[3].valRec := 8915;
  1403. NativeFreqTab[3].valLpfK := 35A00000H;
  1404. NativeFreqTab[3].valLpfQ := 31C80000H;
  1405. NativeFreqTab[4].hz := 32000;
  1406. NativeFreqTab[4].valRec := 6143;
  1407. NativeFreqTab[4].valLpfK := 40000000H;
  1408. NativeFreqTab[4].valLpfQ := 33D00000H;
  1409. NativeFreqTab[5].hz := 44100;
  1410. NativeFreqTab[5].valRec := 4457;
  1411. NativeFreqTab[5].valLpfK := 40000000H;
  1412. NativeFreqTab[5].valLpfQ := 40000000H;
  1413. NativeFreqTab[6].hz := 48000;
  1414. NativeFreqTab[6].valRec := 4095;
  1415. NativeFreqTab[6].valLpfK := 40000000H;
  1416. NativeFreqTab[6].valLpfQ := 40000000H;
  1417. END FillNativeFreqTable;
  1418. (* Get physical address for DMA access *)
  1419. PROCEDURE GetPhysicalAdr(adr: ADDRESS; size: SIZE): Machine.Address32;
  1420. VAR physadr: Machine.Address32;
  1421. BEGIN
  1422. (* All data must be continous in physical memory ! *)
  1423. (* This can not be forced, but Aos seems to do it anyway. *)
  1424. physadr := Machine.Ensure32BitAddress (Machine.PhysicalAdr(adr, size));
  1425. ASSERT(physadr # Machine.NilAdr); (* check if it is continous in physical memory ! *)
  1426. ASSERT(physadr MOD 4 = 0); (* must be 4 byte aligned in physical memory *)
  1427. RETURN physadr;
  1428. END GetPhysicalAdr;
  1429. (* Scan the PCI bus for the specified card *)
  1430. PROCEDURE ScanPCI(vendor, device: LONGINT; name: Plugins.Name; CntrlInst1E: BOOLEAN);
  1431. VAR
  1432. len, reg, index: LONGINT; res: WORD;
  1433. bus, dev, fct: LONGINT;
  1434. base, irq: LONGINT;
  1435. d: Driver;
  1436. BEGIN
  1437. index := 0;
  1438. WHILE (index < 10) & (PCI.FindPCIDevice(device, vendor, index, bus, dev, fct) = PCI.Done) DO
  1439. (* Get physical base address *)
  1440. res := PCI.ReadConfigDword(bus, dev, fct, PCI.Adr0Reg, base); ASSERT(res = PCI.Done);
  1441. ASSERT(~ODD(base)); (* memory mapped *)
  1442. DEC(base, base MOD 16); (* zero last 4 bits *)
  1443. (* Get IRQ number *)
  1444. res := PCI.ReadConfigByte(bus, dev, fct, PCI.IntlReg, irq); ASSERT(res = PCI.Done);
  1445. (* Reset AC97 link (must be done here at PCI bus level) *)
  1446. res := PCI.ReadConfigByte(bus, dev, fct, PCIRegDS1EControl, reg); ASSERT(res = PCI.Done);
  1447. IF ODD(reg) THEN
  1448. DEC(reg);
  1449. res := PCI.WriteConfigByte(bus, dev, fct, PCIRegDS1EControl, reg); ASSERT(res = PCI.Done);
  1450. END;
  1451. res := PCI.WriteConfigByte(bus, dev, fct, PCIRegDS1EControl, reg + 1); ASSERT(res = PCI.Done);
  1452. res := PCI.WriteConfigByte(bus, dev, fct, PCIRegDS1EControl, reg); ASSERT(res = PCI.Done);
  1453. (* Add digit to name *)
  1454. len := Strings.Length(name);
  1455. name[len] := "#";
  1456. INC(len);
  1457. name[len] := CHR(ORD("0") + index);
  1458. INC(len);
  1459. name[len] := 0X;
  1460. (* Instanciate new driver object *)
  1461. NEW(d, name, base, irq, CntrlInst1E);
  1462. INC(index)
  1463. END
  1464. END ScanPCI;
  1465. (* Initialize the driver module *)
  1466. PROCEDURE Init;
  1467. BEGIN
  1468. FillNativeFreqTable; (* fill native frequencies table *)
  1469. DriverTab := NIL; (* init table of active sound drivers *)
  1470. IF Logging THEN
  1471. KernelLog.String("Scanning for devices..."); KernelLog.Ln;
  1472. END;
  1473. (* Scan for Yamaha YMF724 - YMF724E *)
  1474. ScanPCI(1073H, 0004H, "YMF724", FALSE);
  1475. (* Scan for Yamaha YMF740 and YMF740B *)
  1476. ScanPCI(1073H, 000AH, "YMF740", FALSE);
  1477. (* Scan for Yamaha YMF740C *)
  1478. ScanPCI(1073H, 000CH, "YMF740C", TRUE);
  1479. (* Scan for Yamaha YMF724F *)
  1480. ScanPCI(1073H, 000DH, "YMF724F", TRUE);
  1481. (* Scan for Yamaha YMF744 *)
  1482. ScanPCI(1073H, 0010H, "YMF744", TRUE);
  1483. (* Scan for Yamaha YMF754 *)
  1484. ScanPCI(1073H, 0012H, "YMF754", TRUE);
  1485. IF Logging THEN
  1486. KernelLog.String("Scanning finished."); KernelLog.Ln;
  1487. END;
  1488. END Init;
  1489. PROCEDURE Install*;
  1490. (* Init routines are called implicitly *)
  1491. END Install;
  1492. (** Called when unloading module *)
  1493. PROCEDURE Close*;
  1494. VAR
  1495. i: LONGINT;
  1496. BEGIN
  1497. IF Logging THEN
  1498. KernelLog.String("Unloading driver module..."); KernelLog.Ln;
  1499. END;
  1500. (* Finalize all driver objects of this module *)
  1501. IF DriverTab # NIL THEN
  1502. FOR i := 0 TO LEN(DriverTab^) - 1 DO
  1503. IF DriverTab[i] IS Driver THEN
  1504. DriverTab[i](Driver).Finalize;
  1505. END;
  1506. END;
  1507. END;
  1508. IF Logging THEN
  1509. KernelLog.String("Unloading finished."); KernelLog.Ln;
  1510. END;
  1511. END Close;
  1512. BEGIN
  1513. ASSERT(BufferSizeMS <= 10000);
  1514. Modules.InstallTermHandler(Close);
  1515. Init;
  1516. END YMF754.
  1517. Aos.Call YMF754.Install ~
  1518. System.Free YMF754 ~
  1519. Installation
  1520. add YMF754.Install to Configuration.XML, section 'Autostart' to load driver at system startup.