Open Firmware

Open Firmware Svn Source Tree

Root/dev/hdaudio/core.fth

Source at commit HEAD created 1 year 11 months ago.
By tooch, ARM Simulator - Oops. We never enabled conditional execution of instructions. Apparently we rarely use that feature.
1\ Intel HD Audio driver
2\ See license at end of file
3
4\ warning off
5hex
6
7\ \ Defers
8
9\ detect-codec fills in the defers below to suit the available hardware
10defer detect-codec
11
12defer open-codec ' noop to open-codec
13defer close-codec ' noop to close-codec
14defer enable-codec-recording ' noop to enable-codec-recording
15defer disable-codec-recording ' noop to disable-codec-recording
16defer enable-codec-playback ' noop to enable-codec-playback
17defer disable-codec-playback ' noop to disable-codec-playback
18
19defer with-dac \ select digital to analogue converter node
20defer with-adc \ select analogue to digital converter node
21
22\ \ DMA setup
23
240 value au
25
26my-address my-space encode-phys
270 encode-int encode+ 0 encode-int encode+
28
290 0 my-space h# 0300.0010 + encode-phys encode+
300 encode-int encode+ h# 4000 encode-int encode+
31" reg" property
32
33: my-w@ ( offset -- w ) my-space + " config-w@" $call-parent ;
34: my-w! ( w offset -- ) my-space + " config-w!" $call-parent ;
35
36: map-regs ( -- )
37 0 0 my-space h# 0300.0010 + h# 4000 " map-in" $call-parent to au
38 4 my-w@ 6 or 4 my-w!
39;
40: unmap-regs ( -- )
41 4 my-w@ 7 invert and 4 my-w!
42 au h# 4000 " map-out" $call-parent
43;
44
45: dma-alloc ( len -- adr ) " dma-alloc" $call-parent ;
46: dma-free ( adr size -- ) " dma-free" $call-parent ;
47: dma-map-in ( adr len flag -- adr ) " dma-map-in" $call-parent ;
48: dma-map-out ( adr len -- ) " dma-map-out" $call-parent ;
49
50\ \ Register definitions
51
52: icw h# 60 au + ; \ Immediate Command Write
53: irr h# 64 au + ; \ Immediate Response Read
54: ics h# 68 au + ; \ Immediate Command Status
55: gctl h# 08 au + ;
56: wakeen h# 0c au + ; \ Wake enable
57: statests h# 0e au + ; \ Wake status
58: counter h# 30 au + ; \ Wall Clock Counter
59: ssync h# 38 au + ; \ Stream synchronization
60: corblbase h# 40 au + ;
61: corbubase h# 44 au + ;
62: corbwp h# 48 au + ; \ CORB write pointer (last valid command)
63: corbrp h# 4a au + ; \ CORB read pointer (last processed command)
64: corbctl h# 4c au + ;
65: corbsts h# 4d au + ;
66: corbsize h# 4e au + ;
67: rirblbase h# 50 au + ;
68: rirbubase h# 54 au + ;
69: rirbwp h# 58 au + ;
70: rirbctl h# 5c au + ;
71: rirbsts h# 5d au + ;
72: rirbsize h# 5e au + ;
73: dplbase h# 70 au + ;
74: dpubase h# 74 au + ;
75
760 value time-limit
77: set-time-limit ( ms -- ) get-msecs + to time-limit ;
78: 1sec-time-limit ( -- ) d# 1000 set-time-limit ;
79: ?timeout ( -- )
80 get-msecs time-limit - 0> if
81 ." Audio device timeout!" cr
82 abort
83 then
84;
85: running? ( -- ? ) gctl rl@ 1 and 0<> ;
86: reset ( -- )
87 0 gctl rl!
88 1sec-time-limit begin ?timeout running? 0= until
89;
90: start ( -- )
91 1 gctl rl!
92 1sec-time-limit begin ?timeout running? until
93;
94
95\ \\ Stream Descriptors
96\ Default: 48kHz 16bit stereo
970 value sample-base
980 value sample-mul
990 value sample-div
1001 value sample-format
1012 value #channels
102
103variable in-stream-format h# 10 in-stream-format ! \ 48kHz 16bit mono
104variable out-stream-format h# 11 out-stream-format ! \ 48kHz 16bit stereo
105
106defer selected-stream-format ' out-stream-format to selected-stream-format
107
108: stream-format ( -- u )
109 sample-base d# 14 lshift ( acc )
110 sample-mul d# 11 lshift or ( acc )
111 sample-div d# 8 lshift or ( acc )
112 sample-format 4 lshift or ( acc )
113 #channels 1- or ( fmt )
114;
115
116: sample-rate! ( base mul div -- )
117 8 lshift swap d# 11 lshift or swap d# 14 lshift or ( rate-code )
118 selected-stream-format @ h# ffffff00 invert and or selected-stream-format !
119;
120: sample-width! ( code -- )
121 4 lshift
122 selected-stream-format @ h# f0 invert and or selected-stream-format !
123;
124: channels! ( #channels -- )
125 1-
126 selected-stream-format @ h# f invert and or selected-stream-format !
127;
128
129: 48kHz ( -- ) 0 0 0 sample-rate! ;
130: 44.1kHz ( -- ) 1 0 0 sample-rate! ;
131: 96kHz ( -- ) 0 1 0 sample-rate! ;
132: 192kHz ( -- ) 0 3 0 sample-rate! ;
133
134: 8bit ( -- ) 0 sample-width! ;
135: 16bit ( -- ) 1 sample-width! ;
136: 20bit ( -- ) 2 sample-width! ;
137: 24bit ( -- ) 3 sample-width! ;
138: 32bit ( -- ) 4 sample-width! ;
139
140: mono ( -- ) 1 channels! ;
141: stereo ( -- ) 2 channels! ;
142
143\ Stream descriptor register interface.
144\ There are multiple stream descriptors, each with their own register set.
1450 value sd#
146: sd+ ( offset -- adr ) sd# h# 20 * + au + ;
147
148: sdctl h# 80 sd+ ;
149: sdsts h# 83 sd+ ;
150: sdlpib h# 84 sd+ ;
151: sdcbl h# 88 sd+ ;
152: sdlvi h# 8c sd+ ;
153: sdfifos h# 90 sd+ ;
154: sdfmt h# 92 sd+ ;
155: sdbdpl h# 98 sd+ ;
156: sdbdpu h# 9c sd+ ;
157: sdlicba h# 2084 sd+ ;
158
159\ \ CORB/RIRB command interface
160\ DMA-based circular command / response buffers.
161
162\ \\ CORB - Command Output Ring Buffer
163
164d# 1024 constant /corb
1650 value corb
1660 value corb-phys
1670 value corb-pos
168
169: corb-dma-on ( -- ) 2 corbctl rb! ;
170: corb-dma-off ( -- )
171 0 corbctl rb!
172 1sec-time-limit begin ?timeout corbctl rb@ 2 and 0= until
173;
174
175: init-corb ( -- )
176 /corb dma-alloc to corb
177 corb /corb 0 fill
178 corb /corb true dma-map-in to corb-phys
179 corb-dma-off
180 corb-phys corblbase rl!
181 0 corbubase rl!
182 2 corbsize rb! \ 256 entries
183 corbrp rw@ to corb-pos
184 corb-dma-on
185;
186
187: wait-for-corb-sync ( -- )
188 1sec-time-limit
189 begin ?timeout corbrp rw@ corb-pos = until
190;
191
192: corb-tx ( u -- )
193 corb-pos 1+ d# 256 mod to corb-pos
194 corb-pos cells corb + ! ( )
195 corb-pos corbwp rw!
196 wait-for-corb-sync
197;
198
199\ \\ RIRB - Response Inbound Ring Buffer
200
201d# 256 2* cells constant /rirb
2020 value rirb
2030 value rirb-phys
2040 value rirb-pos
205
206: rirb-dma-off ( -- ) 0 rirbctl rb! ;
207: rirb-dma-on ( -- ) 2 rirbctl rb! ;
208
209: init-rirb ( -- )
210 rirb-dma-off
211 /rirb dma-alloc to rirb
212 rirb /rirb 0 fill
213 rirb /rirb true dma-map-in to rirb-phys
214 rirb-phys rirblbase rl!
215 0 rirbubase rl!
216 2 rirbsize rb! \ 256 entries
217 rirbwp rw@ to rirb-pos
218 rirb-dma-on
219;
220
221: rirb-data? ( -- ) rirb-pos rirbwp rw@ <> ;
222
223: rirb-read ( -- resp solicited? )
224 1sec-time-limit begin ?timeout rirb-data? until
225 rirb-pos 1+ d# 256 mod to rirb-pos
226 rirb-pos 2 * cells rirb + ( adr )
227 dup @ ( adr resp )
228 swap cell+ @ ( resp resp-ex )
229 h# 10 and 0= ( resp? solicited? )
230;
231
232: rirb-rx ( -- )
233 begin
234 rirb-read ( resp solicited? )
235 if exit else ." unsolicited response: " . cr then
236 again
237;
238
239\ \ Commands to codecs
240
2410 0 value codec value node \ current target for commands
242
243: encode-command ( verb -- )
244 codec d# 28 lshift node d# 20 lshift or or
245;
246
247: cmd? ( verb -- resp ) encode-command corb-tx rirb-rx ;
248: cmd ( verb -- ) cmd? drop ;
249
250\ \ Streams
251\ \\ Starting and stopping channels
252
253: assert-stream-reset ( -- )
254 1 sdctl rb!
255 1sec-time-limit begin ?timeout sdctl rb@ 1 and 1 = until
256;
257: deassert-stream-reset ( -- )
258 0 sdctl rb!
259 1sec-time-limit begin ?timeout sdctl rb@ 1 and 0 = until
260;
261
262: reset-stream ( -- ) assert-stream-reset deassert-stream-reset ;
263: start-stream ( -- )
264 2 sdctl rb!
265 1sec-time-limit begin ?timeout sdctl rb@ 2 and 0<> until
266;
267: stop-stream ( -- )
268 0 sdctl rb!
269 1sec-time-limit begin ?timeout sdctl rb@ 2 and 0= until
270 4 sdsts rb! \ clear completion flag
271;
272
273defer playback-alarm
2740 value alarmed?
275
276: install-playback-alarm ( -- )
277 true to alarmed? ['] playback-alarm d# 20 alarm
278;
279: uninstall-playback-alarm ( -- )
280 alarmed? if
281 ['] playback-alarm d# 0 alarm
282 false to alarmed?
283 then
284;
285
286\ \ Device open and close
287
288: restart-controller ( -- ) reset start 1 ms ( 250us wait required ) ;
289: init-controller ( -- ) map-regs restart-controller init-corb init-rirb ;
290: init-codec ( -- ) detect-codec open-codec ;
291: close-controller ( -- ) reset unmap-regs ;
292
293d# 48.000 value sample-rate
2941 value scale-factor
295: upsampling? ( -- ? ) scale-factor 1 <> ;
296
297: low-rate? ( Hz ) dup d# 48.000 < swap d# 44.100 <> and ;
298
299: set-sample-rate ( Hz -- )
300 dup to sample-rate ( Hz )
301 dup low-rate? if ( Hz )
302 48kHz d# 48.000 swap / to scale-factor
303 else ( Hz )
304 1 to scale-factor
305 d# 48.000 / case \ find nearest supported rate
306 0 of 44.1kHz endof
307 1 of 48kHz endof
308 2 of 96kHz endof
309 3 of 48kHz 2 to scale-factor endof
310 dup of 192kHz endof
311 endcase
312 then
313;
314
3150 value open-count
316: open ( -- flag )
317 open-count 0= if init-controller init-codec then
318 open-count 1+ to open-count
319 true
320;
321: close ( -- )
322 open-count 1 = if
323 uninstall-playback-alarm close-codec close-controller
324 then
325 open-count 1- 0 max to open-count
326;
327
328\ \ Streams
329
330\ \\ Sound buffer
331\ Sample data for playback or recording.
332
3330 value in-buffer
3340 value in-buffer-phys
3350 value /in-buffer
336
3370 value out-buffer
3380 value out-buffer-phys
3390 value /out-buffer
340
341: install-in-buffer ( adr len -- )
342 2dup to /in-buffer to in-buffer
343 true dma-map-in to in-buffer-phys
344;
345
346: release-in-buffer ( -- )
347 in-buffer in-buffer-phys /in-buffer dma-map-out
348;
349
350: install-out-buffer ( adr len -- )
351 2dup to /out-buffer to out-buffer
352 true dma-map-in to out-buffer-phys
353;
354
355: release-out-buffer ( -- )
356 out-buffer out-buffer-phys /out-buffer dma-map-out
357 \ If we are upsampling, we allocated out-buffer so we need to free it.
358 \ If not, the caller owns out-buffer.
359 upsampling? if out-buffer /out-buffer dma-free then
360;
361
362\ Pad buffer: filled with zeros to pad out the end of the stream.
363\ (Streams automatically repeat -- this is so we'll have time to stop
364\ before that happens.)
365
366d# 8092 value /pad-buffer
367
3680 value in-pad
3690 value in-pad-phys
370
371: alloc-in-pad ( -- )
372 /pad-buffer dma-alloc to in-pad
373 in-pad /pad-buffer true dma-map-in to in-pad-phys
374 in-pad /pad-buffer 0 fill
375;
376
377: free-in-pad ( -- )
378 in-pad in-pad-phys /pad-buffer dma-map-out
379 in-pad /pad-buffer dma-free
380;
381
3820 value out-pad
3830 value out-pad-phys
384
385: alloc-out-pad ( -- )
386 /pad-buffer dma-alloc to out-pad
387 out-pad /pad-buffer true dma-map-in to out-pad-phys
388 out-pad /pad-buffer 0 fill
389;
390
391: free-out-pad ( -- )
392 out-pad out-pad-phys /pad-buffer dma-map-out
393 out-pad /pad-buffer dma-free
394;
395
396\ \\ Buffer Descriptor List
397
398struct ( buffer descriptor )
399 4 field >bd-laddr
400 4 field >bd-uaddr
401 4 field >bd-len
402 4 field >bd-ioc
403constant /bd
404
405: set-buffer-descriptor ( phys uaddr len ioc bd-adr -- )
406 tuck >bd-ioc ! tuck >bd-len ! tuck >bd-uaddr ! >bd-laddr !
407;
408
409d# 256 /bd * value /bdl
410
4110 value in-bdl
4120 value in-bdl-phys
413
414: in-buffer-descriptor ( n -- adr ) /bd * in-bdl + ;
415
416: allocate-in-bdl ( -- )
417 /bdl dma-alloc to in-bdl
418 in-bdl /bdl 0 fill
419 in-bdl /bdl true dma-map-in to in-bdl-phys
420;
421
422: free-in-bdl ( -- ) in-bdl in-bdl-phys /bdl dma-map-out in-bdl /bdl dma-free ;
423
424: setup-in-bdl ( -- )
425 allocate-in-bdl
426 in-buffer-phys 0 /in-buffer 1 0 in-buffer-descriptor set-buffer-descriptor
427 alloc-in-pad
428 in-pad-phys 0 /pad-buffer 0 1 in-buffer-descriptor set-buffer-descriptor
429;
430
431: teardown-in-bdl ( -- ) free-in-bdl free-in-pad ;
432
4330 value out-bdl
4340 value out-bdl-phys
435
436: out-buffer-descriptor ( n -- adr ) /bd * out-bdl + ;
437
438: allocate-out-bdl ( -- )
439 /bdl dma-alloc to out-bdl
440 out-bdl /bdl 0 fill
441 out-bdl /bdl true dma-map-in to out-bdl-phys
442;
443
444: free-out-bdl ( -- ) out-bdl out-bdl-phys /bdl dma-map-out out-bdl /bdl dma-free ;
445
446: setup-out-bdl ( -- )
447 allocate-out-bdl
448 out-buffer-phys 0 /out-buffer 1 0 out-buffer-descriptor set-buffer-descriptor
449 alloc-out-pad
450 out-pad-phys 0 /pad-buffer 0 1 out-buffer-descriptor set-buffer-descriptor
451;
452
453: teardown-out-bdl ( -- ) free-out-bdl free-out-pad ;
454
455\ \\ Stream descriptor (DMA engine)
456
457: setup-out-stream ( -- )
458 reset-stream
459 /out-buffer /pad-buffer + sdcbl rl! \ bytes of stream data
460 h# 440000 sdctl rl! \ stream 4
461 1 sdlvi rw! \ two buffers
462 1c sdsts rb! \ clear status flags
463 out-bdl-phys sdbdpl rl!
464 0 sdbdpu rl!
465 out-stream-format @ sdfmt rw!
466;
467
468: stream-done? ( -- ) sdsts c@ 4 and 0<> ;
469: wait-stream-done ( -- )
470 d# 20,000 set-time-limit begin ?timeout stream-done? until
471;
472
473\ \\ Upsampling
474
4750 value src
4760 value /src
4770 value dst
4780 value /dst
4790 value upsample-factor
480
481: dst! ( value step# sample# -- )
482 upsample-factor * + ( value dst-sample# ) 4 * dst + w!
483;
484
485\ Copy source sample N into a series of interpolated destination samples.
486: copy-sample ( n -- )
487 dup 4 * src + ( n src-adr )
488 dup <w@ swap 4 + <w@ ( n s1 s2 )
489 over - upsample-factor / ( n s1 step )
490 upsample-factor 0 do
491 2dup i * + ( n s1 step s )
492 i 4 pick ( n s1 step s i n )
493 dst!
494 loop
495 3drop
496;
497
498: upsample-channel ( -- )
499 upsample-factor 6 = if
500 src /src dst 4 " 8khz>48khz" evaluate
501 else
502 /src 4 / 1 do i copy-sample loop
503 then
504;
505
506: upsample ( adr len factor -- adr len )
507 to upsample-factor to /src to src
508 /src upsample-factor * to /dst
509 /dst dma-alloc to dst
510 upsample-channel \ left
511 src 2+ to src dst 2+ to dst
512 upsample-channel \ right
513 dst 2- to dst ( )
514 dst /dst ( dst dst-len )
515;
516
517\ \\ Amplifier control
518
519: output-gain ( gain -- ) h# 3b000 or cmd ;
520: input-gain ( gain -- ) h# 37000 or cmd ;
521
522: amp-caps ( -- u ) h# f0012 cmd? ;
523
524: gain-steps ( -- n ) amp-caps 8 rshift h# 7f and 1+ ; \ how many steps?
525: step-size ( -- n ) amp-caps d# 16 rshift h# 7f and 1+ ; \ in units of -0.25dB
526: 0dB-step ( -- n ) amp-caps h# 7f and ; \ which step is 0dB?
527
528: steps/dB ( -- #steps ) step-size 4 * ;
529: dB>steps ( dB -- #steps ) -4 * step-size / ;
530: dB>step# ( dB -- step ) dB>steps 0dB-step swap - ;
531
532\ \\ Playback
533
5344 constant out-sd
535
536false value playing?
537
538: open-out ( -- )
539 ['] out-stream-format to selected-stream-format
540 d# 48.000 set-sample-rate
541;
542
543: start-audio-out ( adr len -- )
544 install-out-buffer ( )
545 setup-out-bdl
546 out-sd to sd#
547 setup-out-stream
548 enable-codec-playback
549 start-stream
550 true to playing?
551;
552: audio-out ( adr len -- actual )
553 dup >r
554 upsampling? if scale-factor upsample then ( adr len )
555 start-audio-out
556 r> ( actual )
557;
558
559: stop-out ( -- )
560 out-sd to sd#
561 stop-stream
562 teardown-out-bdl
563 release-out-buffer
564 uninstall-playback-alarm
565 false to playing?
566;
567: write-done ( -- ) out-sd to sd# wait-stream-done stop-out ;
568
569: write ( adr len -- actual )
570 audio-out install-playback-alarm
571;
572
573: ?end-playing ( -- )
574 out-sd to sd# stream-done? if stop-out then
575;
576
577false value stop-lock
578: stop-sound ( -- )
579 true to stop-lock
580 playing? if stop-out then
581 false to stop-lock
582;
583
584\ Alarm handle to stop the stream when the content has been played.
585: playback-completed-alarm ( -- )
586 stop-lock if exit then
587 playing? if
588 ?end-playing
589 else
590 \ If playback has already stopped as a result of
591 \ someone else having waited for completion, we
592 \ just uninstall ourself.
593 uninstall-playback-alarm
594 then
595;
596
597' playback-completed-alarm is playback-alarm
598
599: still-playing? ( -- flag )
600 playing? 0= if false exit then
601 stop-lock if true exit then
602 ?end-playing
603 playing?
604;
605
606: wait-sound ( -- )
607 true to stop-lock
608 begin playing? while d# 10 ms ?end-playing repeat
609 false to stop-lock
610;
611
612false value left-mute?
613false value right-mute?
614
615: set-volume ( dB -- )
616 with-dac
617 dB>step#
618 dup left-mute? if h# 80 or then h# 3a000 or cmd \ left gain
619 right-mute? if h# 80 or then h# 39000 or cmd \ right gain
620;
621
622\ \\ Recording
623
6240 constant in-sd
6250 value recbuf
6260 value recbuf-phys
627
628: open-in ( -- )
629 ['] in-stream-format to selected-stream-format
630 d# 48.000 set-sample-rate
631;
632
633: setup-in-stream ( -- )
634 in-sd to sd#
635\ 1 to #channels
636 reset-stream
637 /in-buffer /pad-buffer + sdcbl rl! \ buffer length
638 h# 100000 sdctl rl! \ stream 1, input
639 1 sdlvi rw! \ two buffers
640 h# 1c sdsts c! \ clear status flags
641 in-bdl-phys sdbdpl rl!
642 0 sdbdpu rl!
643 in-stream-format @ sdfmt rw!
644 with-adc
645 h# 70610 cmd \ 706sc - stream 1, channel 0
646 h# 20000 in-stream-format @ or cmd \ stream format
647;
648
6490 value recording?
650: start-audio-in ( adr len -- )
651 install-in-buffer ( )
652 setup-in-bdl
653 setup-in-stream
654 enable-codec-recording
655 start-stream
656 true to recording?
657;
658: stop-in ( -- )
659 in-sd is sd#
660 stop-stream
661 teardown-in-bdl
662 release-in-buffer
663 false to recording?
664;
665: ?end-recording ( -- )
666 in-sd to sd#
667 stream-done? if stop-in then
668;
669: audio-in ( adr len -- actual )
670 start-audio-in
671 wait-stream-done
672 stop-in
673 /in-buffer
674;
675
676: out-in ( out-adr out-len in-adr in-len -- )
677 upsampling? if 2swap scale-factor upsample 2swap then ( out-adr,len in-adr,len )
678 1 out-sd lshift 1 in-sd lshift or ssync rl! \ Block the streams while setting up
679 start-audio-in ( out-adr out-len )
680 start-audio-out ( )
681 0 ssync rl! ( ) \ Unblock the streams to start them simultaneously
682 begin
683 recording? if ?end-recording then
684 playing? if ?end-playing then
685 recording? 0= playing? 0= and
686 until
687;
688
689: close-in ( -- ) disable-codec-recording ;
690
691: pbuf " load-base 10000" evaluate ;
692: rbuf " load-base 1meg + 20000" evaluate ;
693: bufs ( -- pbuf,len rbuf,len ) pbuf rbuf ;
694
6950 value boost-db
696
697: mic+20db ( -- ) d# 20 to boost-db ;
698: mic+0db ( -- ) 0 to boost-db ;
699
700: in-amp-caps ( -- u ) h# f000d cmd? ;
701: in-gain-steps ( -- n ) in-amp-caps 8 rshift h# 7f and 1+ ;
702: set-record-gain ( dB -- ) drop ( hardcoded for now ) with-adc h# 40 input-gain ;
703
704
705\ LICENSE_BEGIN
706\ Copyright (c) 2009 Luke Gorrie <luke@bup.co.nz>
707\
708\ Permission is hereby granted, free of charge, to any person obtaining
709\ a copy of this software and associated documentation files (the
710\ "Software"), to deal in the Software without restriction, including
711\ without limitation the rights to use, copy, modify, merge, publish,
712\ distribute, sublicense, and/or sell copies of the Software, and to
713\ permit persons to whom the Software is furnished to do so, subject to
714\ the following conditions:
715\
716\ The above copyright notice and this permission notice shall be
717\ included in all copies or substantial portions of the Software.
718\
719\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
720\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
721\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
722\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
723\ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
724\ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
725\ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
726\
727\ LICENSE_END

Archive Download this file

Revision: HEAD