PageRenderTime 55ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/hdaudio.fth

https://github.com/lukego/fwd
Forth | 817 lines | 636 code | 152 blank | 29 comment | 16 complexity | 84c22074cf7f509dc4beb70995057cce MD5 | raw file
  1. \ Intel HD Audio driver (work in progress) -*- forth -*-
  2. \ Copyright 2009 Luke Gorrie <luke@bup.co.nz>
  3. \ warning off
  4. \ Section and subsection comments - for Emacs
  5. : \\ postpone \ ; immediate
  6. : \\\ postpone \ ; immediate
  7. \\ Device node
  8. ." loading hdaudio" cr
  9. [ifndef] hdaudio-loaded
  10. \ dev /pci8086,2668
  11. dev /pci/pci1106,3288@14
  12. extend-package
  13. " hdaudio" name
  14. 0 value au
  15. [then]
  16. \\ DMA setup
  17. my-address my-space encode-phys
  18. 0 encode-int encode+ 0 encode-int encode+
  19. 0 0 my-space h# 0300.0010 + encode-phys encode+
  20. 0 encode-int encode+ h# 4000 encode-int encode+
  21. " reg" property
  22. : my-w@ ( offset -- w ) my-space + " config-w@" $call-parent ;
  23. : my-w! ( w offset -- ) my-space + " config-w!" $call-parent ;
  24. : map-regs ( -- )
  25. 0 0 my-space h# 0300.0010 + h# 4000 " map-in" $call-parent to au
  26. 4 my-w@ 6 or 4 my-w!
  27. ;
  28. : unmap-regs ( -- )
  29. 4 my-w@ 7 invert and 4 my-w!
  30. au h# 4000 " map-out" $call-parent
  31. ;
  32. : dma-alloc ( len -- adr ) " dma-alloc" $call-parent ;
  33. : dma-free ( adr size -- ) " dma-free" $call-parent ;
  34. : dma-map-in ( adr len flag -- adr ) " dma-map-in" $call-parent ;
  35. : dma-map-out ( adr len -- ) " dma-map-out" $call-parent ;
  36. \\ Register definitions
  37. : icw h# 60 au + ; \ Immediate Command Write
  38. : irr h# 64 au + ; \ Immediate Response Read
  39. : ics h# 68 au + ; \ Immediate Command Status
  40. : gctl h# 08 au + ;
  41. : wakeen h# 0c au + ; \ Wake enable
  42. : statests h# 0e au + ; \ Wake status
  43. : counter h# 30 au + ; \ Wall Clock Counter
  44. : corblbase h# 40 au + ;
  45. : corbubase h# 44 au + ;
  46. : corbwp h# 48 au + ; \ CORB write pointer (last valid command)
  47. : corbrp h# 4a au + ; \ CORB read pointer (last processed command)
  48. : corbctl h# 4c au + ;
  49. : corbsts h# 4d au + ;
  50. : corbsize h# 4e au + ;
  51. : rirblbase h# 50 au + ;
  52. : rirbubase h# 54 au + ;
  53. : rirbwp h# 58 au + ;
  54. : rirbctl h# 5c au + ;
  55. : rirbsts h# 5d au + ;
  56. : rirbsize h# 5e au + ;
  57. : dplbase h# 70 au + ;
  58. : dpubase h# 74 au + ;
  59. : running? ( -- ? ) gctl rl@ 1 and 0<> ;
  60. : reset ( -- ) 0 gctl rl! begin running? 0= until ;
  61. : start ( -- ) 1 gctl rl! begin running? until ;
  62. \\\ Stream Descriptors
  63. \ Default: 48kHz 16bit stereo
  64. 0 value scale-factor
  65. 0 value sample-base
  66. 0 value sample-mul
  67. 0 value sample-div
  68. 1 value sample-format
  69. 2 value #channels
  70. : stream-format ( -- u )
  71. sample-base d# 14 lshift ( acc )
  72. sample-mul d# 11 lshift or ( acc )
  73. sample-div d# 8 lshift or ( acc )
  74. sample-format 4 lshift or ( acc )
  75. #channels 1- or ( fmt )
  76. ;
  77. : sample-rate! ( base mul div ) to sample-div to sample-mul to sample-base ;
  78. : 48kHz ( -- ) 0 0 0 sample-rate! ;
  79. : 44.1kHz ( -- ) 1 0 0 sample-rate! ;
  80. : 96kHz ( -- ) 0 1 0 sample-rate! ;
  81. : 192kHz ( -- ) 0 3 0 sample-rate! ;
  82. : 8bit ( -- ) 0 to sample-format ;
  83. : 16bit ( -- ) 1 to sample-format ;
  84. : 20bit ( -- ) 2 to sample-format ;
  85. : 24bit ( -- ) 3 to sample-format ;
  86. : 32bit ( -- ) 4 to sample-format ;
  87. \ Stream descriptor index.
  88. 4 constant sd#
  89. : sd+ ( offset -- adr ) sd# h# 20 * + au + ;
  90. : sdctl h# 80 sd+ ;
  91. : sdsts h# 83 sd+ ;
  92. : sdlpib h# 84 sd+ ;
  93. : sdcbl h# 88 sd+ ;
  94. : sdlvi h# 8c sd+ ;
  95. : sdfifos h# 90 sd+ ;
  96. : sdfmt h# 92 sd+ ;
  97. : sdbdpl h# 98 sd+ ;
  98. : sdbdpu h# 9c sd+ ;
  99. : sdlicba h# 2084 sd+ ;
  100. \\ Immediate command interface
  101. \ XXX The spec makes the immediate command registers optional and my
  102. \ EEE doesn't seem to support them.
  103. : command-ready? ( -- ? ) ics rw@ 1 and 0= ;
  104. : response-ready? ( -- ? ) ics rw@ 2 and 0<> ;
  105. : write-command ( c -- ) begin command-ready? until icw rl! ;
  106. : read-response ( -- r ) begin response-ready? until irr rl@ ;
  107. : immediate-codec! ( chan nid verb -- )
  108. running? 0<> abort" hdaudio not running"
  109. -rot d# 28 lshift ( nid verb chan' )
  110. -rot d# 20 lshift ( verb chan' nid' )
  111. or or ( command )
  112. write-command
  113. read-response
  114. ;
  115. \\ CORB/RIRB command interface
  116. \ DMA-based circular command / response buffers.
  117. \\\ CORB - Command Output Ring Buffer
  118. d# 1024 constant /corb
  119. 0 value corb
  120. 0 value corb-phys
  121. 0 value corb-pos
  122. : corb-dma-on ( -- ) 2 corbctl rb! ;
  123. : corb-dma-off ( -- ) 0 corbctl rb! begin corbctl rb@ 2 and 0= until ;
  124. : init-corb ( -- )
  125. /corb dma-alloc to corb
  126. corb /corb 0 fill
  127. corb /corb true dma-map-in to corb-phys
  128. corb-dma-off
  129. corb-phys corblbase rl!
  130. 0 corbubase rl!
  131. 2 corbsize rb! \ 256 entries
  132. corbrp rw@ to corb-pos
  133. corb-dma-on
  134. ;
  135. : wait-for-corb-sync ( -- ) begin corbrp rw@ corb-pos = until ;
  136. : corb-tx ( u -- )
  137. corb-pos 1+ d# 256 mod to corb-pos
  138. corb-pos cells corb + ! ( )
  139. corb-pos corbwp rw!
  140. wait-for-corb-sync
  141. ;
  142. \\\ RIRB - Response Inbound Ring Buffer
  143. d# 256 2* cells constant /rirb
  144. 0 value rirb
  145. 0 value rirb-phys
  146. 0 value rirb-pos
  147. : rirb-dma-off ( -- ) 0 rirbctl rb! ;
  148. : rirb-dma-on ( -- ) 2 rirbctl rb! ;
  149. : init-rirb ( -- )
  150. rirb-dma-off
  151. /rirb dma-alloc to rirb
  152. rirb /rirb 0 fill
  153. rirb /corb true dma-map-in to rirb-phys
  154. rirb-phys rirblbase rl!
  155. 0 rirbubase rl!
  156. 2 rirbsize rb! \ 256 entries
  157. rirbwp rw@ to rirb-pos
  158. rirb-dma-on
  159. ;
  160. : rirb-data? ( -- ) rirb-pos rirbwp rw@ <> ;
  161. : rirb-read ( -- resp solicited? )
  162. begin rirb-data? key? abort" key interrupt" until
  163. rirb-pos 1+ d# 256 mod to rirb-pos
  164. rirb-pos 2 * cells rirb + ( adr )
  165. dup @ ( adr resp )
  166. swap cell+ @ ( resp resp-ex )
  167. h# 10 and 0= ( resp? solicited? )
  168. ;
  169. : rirb-rx ( -- )
  170. begin
  171. rirb-read ( resp solicited? )
  172. if exit else ." unsolicited response: " . cr then
  173. again
  174. ;
  175. \\ Commands to codecs
  176. 0 0 value codec value node \ current target for commands
  177. : encode-command ( codec node verb -- )
  178. codec d# 28 lshift node d# 20 lshift or or
  179. ;
  180. : cmd ( verb -- resp ) encode-command corb-tx rirb-rx ;
  181. \\\ Getting parameters
  182. : config-default ( -- c ) f1c00 cmd ;
  183. : default-device ( -- d ) config-default d# 20 rshift f and ;
  184. : connectivity ( -- c ) config-default d# 30 rshift ;
  185. : #subnodes f0004 cmd h# ff and ;
  186. : first-subnode f0004 cmd d# 16 rshift ;
  187. : widget-type ( -- u ) f0009 cmd d# 20 rshift f and ;
  188. : pin-widget? ( -- ? ) widget-type 4 = ;
  189. : builtin? ( -- ? ) connectivity 2 = ;
  190. : speaker? ( -- ? ) default-device 1 = ;
  191. : headphone? ( -- ? ) default-device 2 = ;
  192. : mic? ( -- ? ) default-device h# a = ;
  193. \\ Widget graph
  194. \\\ Traversal
  195. ' noop value do-xt
  196. 0 value do-tree-level
  197. : do-subtree ( xt codec node -- )
  198. to node to codec ( )
  199. do-xt execute ( )
  200. codec first-subnode #subnodes bounds ?do ( codec )
  201. do-tree-level 1 + to do-tree-level
  202. dup i recurse
  203. do-tree-level 1 - to do-tree-level
  204. loop ( codec )
  205. drop
  206. ;
  207. : do-tree ( xt -- ) to do-xt 0 0 do-subtree ;
  208. \\\ Find and setup the interesting widgets
  209. 0 value amp
  210. : connection0 ( -- n ) f0200 cmd ( connection-list ) ff and ;
  211. : setup-widget ( -- )
  212. pin-widget? headphone? and if
  213. 3b000 cmd drop \ unmute
  214. 707c0 cmd drop \ pin widget: enable output, headphones
  215. connection0 to amp
  216. then
  217. pin-widget? speaker? builtin? and and if
  218. 3b000 cmd drop \ unmute
  219. 70740 cmd drop \ pin widget: enable output
  220. then
  221. ;
  222. : init-widgets ( -- ) ['] setup-widget do-tree ;
  223. \\ Streams
  224. \\\ Starting and stopping channels
  225. : assert-stream-reset ( -- ) 1 sdctl rb! begin sdctl rb@ 1 and 1 = until ;
  226. : deassert-stream-reset ( -- ) 0 sdctl rb! begin sdctl rb@ 1 and 0 = until ;
  227. : reset-stream ( -- ) assert-stream-reset deassert-stream-reset ;
  228. : stop-stream ( -- ) 0 sdctl rb! begin sdctl rb@ 2 and 0= until ;
  229. : start-stream ( -- ) 2 sdctl rb! begin sdctl rb@ 2 and 0<> until ;
  230. \\ DMA position buffer
  231. 0 value dma-pos
  232. 0 value dma-pos-phys
  233. d# 4096 value /dma-pos
  234. : init-dma-pos-buffer ( -- )
  235. /dma-pos dma-alloc to dma-pos
  236. dma-pos /dma-pos true dma-map-in to dma-pos-phys
  237. dma-pos /dma-pos 0 fill
  238. dma-pos-phys 1 or dplbase rl!
  239. 0 dpubase rl!
  240. ;
  241. \\ Module interface
  242. \\\ Device open and close
  243. : reset-status-regs ( -- )
  244. 0 wakeen rw! 0 statests rw!
  245. 8 0 do i to sd# 1c sdsts rb! loop
  246. ;
  247. : via-extra ( -- )
  248. 01 to node 705 8 lshift 0 or cmd drop \ set power state
  249. 10 to node 705 8 lshift 0 or cmd drop \ ...
  250. 11 to node 705 8 lshift 0 or cmd drop
  251. 12 to node 705 8 lshift 0 or cmd drop
  252. 14 to node 705 8 lshift 0 or cmd drop
  253. 15 to node 705 8 lshift 0 or cmd drop
  254. 16 to node 705 8 lshift 0 or cmd drop
  255. 17 to node 705 8 lshift 0 or cmd drop
  256. 18 to node 705 8 lshift 0 or cmd drop
  257. 19 to node 705 8 lshift 0 or cmd drop
  258. 1a to node 705 8 lshift 0 or cmd drop
  259. 1b to node 705 8 lshift 0 or cmd drop
  260. 1c to node 705 8 lshift 0 or cmd drop
  261. 1d to node 705 8 lshift 0 or cmd drop
  262. 1e to node 705 8 lshift 0 or cmd drop
  263. 1f to node 705 8 lshift 0 or cmd drop
  264. 20 to node 705 8 lshift 0 or cmd drop
  265. 21 to node 705 8 lshift 0 or cmd drop
  266. 22 to node 705 8 lshift 0 or cmd drop
  267. 23 to node 705 8 lshift 0 or cmd drop
  268. 24 to node 705 8 lshift 0 or cmd drop
  269. 14 to node 300 8 lshift 6006 or cmd drop \ set volume
  270. 14 to node 300 8 lshift 5006 or cmd drop \ ...
  271. 23 to node 300 8 lshift 6004 or cmd drop
  272. 23 to node 300 8 lshift 5004 or cmd drop
  273. 17 to node 300 8 lshift a004 or cmd drop
  274. 17 to node 300 8 lshift 9004 or cmd drop
  275. 18 to node 300 8 lshift a004 or cmd drop
  276. 18 to node 300 8 lshift 9004 or cmd drop
  277. 14 to node 300 8 lshift 6200 or cmd drop
  278. 14 to node 300 8 lshift 5200 or cmd drop
  279. 10 to node 300 8 lshift a03e or cmd drop
  280. 10 to node 300 8 lshift 903e or cmd drop
  281. 10 to node 706 8 lshift 40 or cmd drop \ converter stream (4)
  282. 10 to node 200 8 lshift 11 or cmd drop \ converter format
  283. ;
  284. : init-all ( -- ) init-corb init-rirb init-widgets via-extra ;
  285. : init ( -- ) ;
  286. : restart-controller ( -- )
  287. reset
  288. init-dma-pos-buffer
  289. start
  290. 1 ms \ allow 250us for codecs to initialize
  291. ;
  292. : sanity-check ( -- )
  293. statests rw@ 1 <> if
  294. ." hdaudio: expected one codec but found this bitset: " statests rw@ . cr
  295. then
  296. ;
  297. : open ( -- flag )
  298. map-regs restart-controller sanity-check init-all true
  299. ;
  300. : close ( -- )
  301. reset unmap-regs
  302. ;
  303. \\\ Audio API
  304. : gain/mute! ( gain mute? -- )
  305. if h# 80 or then ( gain/mute )
  306. h# 3f000 or \ set output, input, left, right
  307. cmd
  308. ;
  309. : unmute-in ( -- ) h# 37000 cmd drop ;
  310. : unmute-out ( -- ) h# 3b000 cmd drop ;
  311. : amp-caps ( -- u ) f0012 cmd ;
  312. : gain-steps ( -- n ) amp-caps 8 rshift 7f and 1+ ;
  313. : step-size ( -- n ) amp-caps d# 16 rshift 7f and 1+ ;
  314. : 0dB-step ( -- n ) amp-caps 7f and ;
  315. : steps/dB ( -- #steps ) step-size 4 * ;
  316. : dB>steps ( dB -- #steps ) 4 * step-size / ;
  317. : set-volume ( dB -- )
  318. amp to node
  319. dB>steps 0dB-step + false gain/mute!
  320. ;
  321. : low-rate? ( Hz ) dup d# 48.000 < swap d# 44.100 <> and ;
  322. : set-sample-rate ( Hz -- )
  323. dup low-rate? if
  324. 48kHz d# 48.000 swap / to scale-factor
  325. else
  326. 1 to scale-factor
  327. d# 48.000 / case \ find nearest supported rate
  328. 0 of 44.1kHz endof
  329. 1 of 48kHz endof
  330. 2 of 96kHz endof
  331. 3 of 48kHz 2 to scale-factor endof
  332. dup of 192kHz endof
  333. endcase
  334. then
  335. ;
  336. \\ Sound buffers
  337. \\\ Sound buffer
  338. \ Sound buffer contains the real sound samples for both playback and recording.
  339. 0 value sound-buffer
  340. 0 value sound-buffer-phys
  341. 0 value /sound-buffer
  342. : install-sound-buffer ( adr len -- )
  343. 2dup to /sound-buffer to sound-buffer
  344. true dma-map-in to sound-buffer-phys
  345. ;
  346. 0 value pad-buffer
  347. 0 value pad-buffer-phys
  348. d# 2048 value /pad-buffer
  349. : alloc-pad-buffer ( -- )
  350. /pad-buffer dma-alloc to pad-buffer
  351. pad-buffer /pad-buffer true dma-map-in to pad-buffer-phys
  352. pad-buffer /pad-buffer 0 fill
  353. ;
  354. : free-pad-buffer ( -- )
  355. pad-buffer pad-buffer-phys /pad-buffer dma-map-out
  356. pad-buffer /pad-buffer dma-free
  357. ;
  358. \\\ Buffer Descriptor List
  359. struct ( buffer descriptor )
  360. 4 field >bd-laddr
  361. 4 field >bd-uaddr
  362. 4 field >bd-len
  363. 4 field >bd-ioc
  364. constant /bd
  365. 0 value bdl
  366. 0 value bdl-phys
  367. d# 256 /bd * value /bdl
  368. : buffer-descriptor ( n -- adr ) /bd * bdl + ;
  369. : allocate-bdl ( -- )
  370. /bdl dma-alloc to bdl
  371. bdl /bdl 0 fill
  372. bdl /bdl true dma-map-in to bdl-phys
  373. ;
  374. : free-bdl ( -- ) bdl-phys /bdl dma-map-out bdl /bdl dma-free ;
  375. : setup-bdl ( -- )
  376. allocate-bdl
  377. sound-buffer-phys 0 buffer-descriptor >bd-laddr ! ( len )
  378. 0 0 buffer-descriptor >bd-uaddr ! ( len )
  379. /sound-buffer 0 buffer-descriptor >bd-len ! ( )
  380. 1 0 buffer-descriptor >bd-ioc !
  381. \ pad buffer
  382. alloc-pad-buffer
  383. pad-buffer-phys 1 buffer-descriptor >bd-laddr !
  384. 0 1 buffer-descriptor >bd-uaddr !
  385. /pad-buffer 1 buffer-descriptor >bd-len !
  386. 0 1 buffer-descriptor >bd-ioc !
  387. ;
  388. : teardown-bdl ( -- )
  389. free-bdl
  390. free-pad-buffer
  391. ;
  392. \\\ Stream descriptor (DMA engine)
  393. : setup-stream ( -- )
  394. reset-stream
  395. /sound-buffer /pad-buffer + sdcbl rl! \ bytes of stream data
  396. 440000 sdctl rl! \ stream 4
  397. 1 sdlvi rw! \ two buffers
  398. 1c sdsts c! \ clear status flags
  399. bdl-phys sdbdpl rl!
  400. 0 sdbdpu rl!
  401. stream-format sdfmt rw!
  402. \ FIXME
  403. 10 to node 20000 stream-format or cmd drop
  404. ;
  405. : stream-done? ( -- ) sdsts c@ 4 and 0<> ;
  406. : wait-stream-done ( -- ) begin stream-done? until ;
  407. \\\ Upsampling
  408. 0 value src
  409. 0 value /src
  410. 0 value dst
  411. 0 value /dst
  412. 0 value upsample-factor
  413. : dst! ( value step# sample# -- )
  414. upsample-factor * + ( value dst-sample# ) 4 * dst + w!
  415. ;
  416. \ Copy source sample N into a series of interpolated destination samples.
  417. : copy-sample ( n -- )
  418. dup 4* src + ( n src-adr )
  419. dup <w@ swap 4 + <w@ ( n s1 s2 )
  420. over - upsample-factor / ( n s1 step )
  421. upsample-factor 0 do
  422. 2dup i * + ( n s1 step s )
  423. i 4 pick ( n s1 step s i n )
  424. dst!
  425. loop
  426. 3drop
  427. ;
  428. : upsample-channel ( -- )
  429. /src 4 / 1 do
  430. i b3b0 = if i . cr then
  431. i copy-sample
  432. loop
  433. ;
  434. : upsample ( adr len factor -- adr len )
  435. to upsample-factor to /src to src
  436. /src upsample-factor * to /dst
  437. /dst dma-alloc to dst
  438. upsample-channel \ left
  439. src 2+ to src dst 2+ to dst
  440. upsample-channel \ right
  441. dst 2 - /dst ( dst dst-len )
  442. ;
  443. \\\ Audio interface
  444. : upsampling? ( -- ? ) scale-factor 1 <> ;
  445. : write ( adr len -- actual )
  446. 48kHz
  447. upsampling? if scale-factor upsample then ( adr len )
  448. install-sound-buffer ( )
  449. setup-bdl
  450. setup-stream
  451. start-stream
  452. /sound-buffer ( actual )
  453. ;
  454. : release-sound-buffer ( -- )
  455. sound-buffer-phys /sound-buffer dma-map-out
  456. upsampling? if sound-buffer /sound-buffer dma-free then
  457. ;
  458. : write-done ( -- )
  459. wait-stream-done
  460. stop-stream
  461. free-bdl
  462. release-sound-buffer
  463. ;
  464. \\ Microphone
  465. : open-in ( -- )
  466. ;
  467. : record-stream ( -- )
  468. 0 to sd#
  469. 48kHz
  470. reset-stream
  471. /sound-buffer /pad-buffer + sdcbl rl! \ buffer length
  472. 100000 sdctl rl! \ stream 1, input
  473. 1 sdlvi rw! \ two buffers
  474. 1c sdsts c! \ clear status flags
  475. bdl-phys sdbdpl rl!
  476. 0 sdbdpu rl!
  477. stream-format sdfmt rw!
  478. \ extra magic
  479. 14 to node
  480. 70610 cmd drop \
  481. 20010 cmd drop \ stream format 48kHz, 16-bit, mono
  482. \ 17 to node 70101 cmd drop
  483. 1a to node 70721 cmd drop
  484. 1b to node 70721 cmd drop
  485. 14 to node 37040 cmd drop
  486. ;
  487. : start-recording ( adr len -- )
  488. install-sound-buffer ( )
  489. alloc-pad-buffer ( adr len )
  490. setup-bdl
  491. record-stream
  492. start-stream
  493. ;
  494. 0 value recbuf
  495. 0 value recbuf-phys
  496. d# 65535 value /recbuf
  497. : audio-in ( adr len -- actual )
  498. debug-me
  499. start-recording
  500. wait-stream-done
  501. \ release-sound-buffer
  502. free-pad-buffer
  503. /recbuf
  504. ;
  505. : enable-mic ( node -- )
  506. to node
  507. 70720 cmd drop
  508. ;
  509. : config-audio-input ( -- )
  510. 14 to node
  511. 70610 cmd drop \ stream 1, channel 0
  512. 20000 stream-format or cmd drop \ stream format
  513. ;
  514. : record-test ( n -- )
  515. to /recbuf
  516. /recbuf dma-alloc to recbuf
  517. recbuf /recbuf true dma-map-in to recbuf-phys
  518. recbuf-phys /recbuf audio-in
  519. ;
  520. \\ Verifying pin sense
  521. : can-pin-sense? ( -- ? ) f000c cmd 4 and 0<> ;
  522. : pin-sense? ( -- ? ) f0900 cmd 8000.0000 and 0<> ;
  523. : sense-mic ( -- ) mic? can-pin-sense? and if node . pin-sense? . cr then ;
  524. \\ Testing
  525. \ d# 512 d# 1024 * constant /square-wave
  526. 100 constant /square-wave
  527. create square-wave /square-wave allot
  528. : init-square-wave ( -- )
  529. square-wave /square-wave d# 96 - bounds do
  530. i d# 48 bounds do
  531. c00 i * /square-wave / 2 * i w!
  532. -c00 i * /square-wave / 2 * i d# 48 + w!
  533. 2 +loop
  534. d# 96 +loop
  535. ;
  536. : play-square-wave ( -- )
  537. init-square-wave square-wave /square-wave write write-done
  538. ;
  539. : shh ( -- ) 10 to node 3b080 cmd drop ;
  540. \ The use of CREATE DOES here is probably gratuitious. But how will I
  541. \ learn if I never use it? -luke
  542. : param@ ( n -- u ) f0000 or cmd ;
  543. : get-hex# ( "number" -- n )
  544. safe-parse-word push-hex $number abort" bad hex#" pop-base
  545. ;
  546. : param: ( "name" "id" -- value )
  547. get-hex# create ,
  548. does> @ param@
  549. ;
  550. param: 00 vendor-id
  551. param: 02 revision-id
  552. param: 04 subnodes
  553. param: 05 function-type
  554. param: 08 function-caps
  555. param: 09 widget-caps
  556. param: 0a pcm-support
  557. param: 0b stream-formats
  558. param: 0c pin-caps
  559. \ param: 0d amp-caps
  560. param: 0e connections
  561. param: 0f power-states
  562. param: 10 processing-caps
  563. param: 11 gpio-count
  564. param: 13 volume-caps
  565. : config-default ( -- c ) f1c00 cmd ;
  566. : connection-select ( -- n ) f0100 cmd ;
  567. : default-device ( -- d ) config-default d# 20 rshift f and ;
  568. : location ( -- l ) config-default d# 24 rshift 3f and ;
  569. : color ( -- c ) config-default d# 12 rshift f and ;
  570. : connectivity ( -- c ) config-default d# 30 rshift ;
  571. : gain/mute ( output? left? -- gain mute? )
  572. 0 swap if h# 2000 or then
  573. swap if h# 8000 or then
  574. h# b0000 or cmd
  575. dup h# 7f and ( res gain )
  576. swap h# 80 and 0<> ( gain mute? )
  577. ;
  578. \\\ Inspecting widgets
  579. : .connectivity ( -- )
  580. case connectivity
  581. 0 of ." external " endof
  582. 1 of ." unused " endof
  583. 2 of ." builtin " endof
  584. 3 of ." builtin/external " endof
  585. endcase
  586. ;
  587. : .color ( -- )
  588. case color
  589. 1 of ." black " endof
  590. 2 of ." grey " endof
  591. 3 of ." blue " endof
  592. 4 of ." green " endof
  593. 5 of ." red " endof
  594. 6 of ." orange " endof
  595. 7 of ." yellow " endof
  596. 8 of ." purple " endof
  597. 9 of ." pink " endof
  598. e of ." white " endof
  599. endcase
  600. ;
  601. : .location ( -- )
  602. case location
  603. 1 of ." rear " endof
  604. 2 of ." front " endof
  605. 3 of ." left " endof
  606. 4 of ." right " endof
  607. 5 of ." top " endof
  608. 6 of ." bottom " endof
  609. 7 of ." special " endof
  610. endcase
  611. ;
  612. : .default-device ( -- )
  613. case default-device
  614. 0 of ." line out)" endof
  615. 1 of ." speaker)" endof
  616. 2 of ." HP out)" endof
  617. 3 of ." CD)" endof
  618. 4 of ." SPDIF out)" endof
  619. 5 of ." digital other out)" endof
  620. 6 of ." modem line side)" endof
  621. 7 of ." modem handset side)" endof
  622. 8 of ." line in)" endof
  623. 9 of ." aux)" endof
  624. a of ." mic in)" endof
  625. b of ." telephony)" endof
  626. c of ." SPDIF in)" endof
  627. d of ." digital other in)" endof
  628. dup of ." unknown)" endof
  629. endcase
  630. ;
  631. : .node ( -- )
  632. do-tree-level spaces
  633. codec . ." / " node .
  634. f0200 cmd lbsplit 4 0 do <# u# u# u#> type space loop 2 spaces
  635. widget-type case
  636. 0 of ." audio output" endof
  637. 1 of ." audio input" endof
  638. 2 of ." audio mixer" endof
  639. 3 of ." audio selector" endof
  640. 4 of ." pin widget (" .connectivity .color .location .default-device endof
  641. 5 of ." power widget" endof
  642. 6 of ." volume knob" endof
  643. 7 of ." beep generator" endof
  644. dup of endof
  645. endcase
  646. cr exit? abort" "
  647. ;
  648. : in-amp-caps ( -- u ) f000d cmd ;
  649. : in-gain-steps ( -- n ) in-amp-caps 8 rshift 7f and 1+ ;
  650. : in-step-size ( -- n ) in-amp-caps d# 16 rshift 7f and 1+ ;
  651. : in-0dB-step ( -- n ) in-amp-caps 7f and ;
  652. : in-steps/dB ( -- #steps ) in-step-size 4 * ;
  653. : .input-amp ( -- )
  654. ." gain steps: " in-gain-steps . cr
  655. ." left gain: " false true gain/mute swap . if ." (muted)" then cr
  656. ." right gain: " false false gain/mute swap . if ." (muted)" then cr
  657. ;
  658. ." loaded" cr
  659. [ifndef] hdaudio-loaded
  660. select /hdaudio
  661. [else]
  662. ( close open ) select /hdaudio
  663. [then]
  664. create hdaudio-loaded
  665.