| @@ -1,513 +1,507 @@ | | | @@ -1,513 +1,507 @@ |
1 | /* $NetBSD: tms320av110.c,v 1.23 2012/10/27 17:18:23 chs Exp $ */ | | 1 | /* $NetBSD: tms320av110.c,v 1.23.12.1 2020/03/08 09:15:34 martin Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1997 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1997 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Ignatios Souvatzis. | | 8 | * by Ignatios Souvatzis. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * Machine independent part of TMS320AV110 driver. | | 33 | * Machine independent part of TMS320AV110 driver. |
34 | * | | 34 | * |
35 | * Currently, only minimum support for audio output. For audio/video | | 35 | * Currently, only minimum support for audio output. For audio/video |
36 | * synchronization, more is needed. | | 36 | * synchronization, more is needed. |
37 | */ | | 37 | */ |
38 | | | 38 | |
39 | #include <sys/cdefs.h> | | 39 | #include <sys/cdefs.h> |
40 | __KERNEL_RCSID(0, "$NetBSD: tms320av110.c,v 1.23 2012/10/27 17:18:23 chs Exp $"); | | 40 | __KERNEL_RCSID(0, "$NetBSD: tms320av110.c,v 1.23.12.1 2020/03/08 09:15:34 martin Exp $"); |
41 | | | 41 | |
42 | #include <sys/param.h> | | 42 | #include <sys/param.h> |
43 | #include <sys/systm.h> | | 43 | #include <sys/systm.h> |
44 | #include <sys/kernel.h> | | 44 | #include <sys/kernel.h> |
45 | #include <sys/device.h> | | 45 | #include <sys/device.h> |
46 | #include <sys/proc.h> | | 46 | #include <sys/proc.h> |
47 | | | 47 | |
48 | #include <sys/audioio.h> | | 48 | #include <sys/audioio.h> |
49 | #include <dev/audio_if.h> | | 49 | #include <dev/audio_if.h> |
50 | | | 50 | |
51 | #include <dev/ic/tms320av110reg.h> | | 51 | #include <dev/ic/tms320av110reg.h> |
52 | #include <dev/ic/tms320av110var.h> | | 52 | #include <dev/ic/tms320av110var.h> |
53 | | | 53 | |
54 | #include <sys/bus.h> | | 54 | #include <sys/bus.h> |
55 | | | 55 | |
56 | int tav_open(void *, int); | | 56 | int tav_open(void *, int); |
57 | void tav_close(void *); | | 57 | void tav_close(void *); |
58 | int tav_drain(void *); | | 58 | int tav_drain(void *); |
59 | int tav_query_encoding(void *, struct audio_encoding *); | | 59 | int tav_query_encoding(void *, struct audio_encoding *); |
60 | int tav_set_params(void *, int, int, audio_params_t *, audio_params_t *, | | 60 | int tav_set_params(void *, int, int, audio_params_t *, audio_params_t *, |
61 | stream_filter_list_t *, stream_filter_list_t *); | | 61 | stream_filter_list_t *, stream_filter_list_t *); |
62 | int tav_round_blocksize(void *, int, int, const audio_params_t *); | | 62 | int tav_round_blocksize(void *, int, int, const audio_params_t *); |
63 | int tav_init_output(void *, void *, int); | | 63 | int tav_init_output(void *, void *, int); |
64 | int tav_start_output(void *, void *, int, void (*)(void *), void *); | | 64 | int tav_start_output(void *, void *, int, void (*)(void *), void *); |
65 | int tav_start_input(void *, void *, int, void (*)(void *), void *); | | 65 | int tav_start_input(void *, void *, int, void (*)(void *), void *); |
66 | int tav_halt_output(void *); | | 66 | int tav_halt_output(void *); |
67 | int tav_halt_input(void *); | | 67 | int tav_halt_input(void *); |
68 | int tav_speaker_ctl(void *, int); | | 68 | int tav_speaker_ctl(void *, int); |
69 | int tav_getdev(void *, struct audio_device *); | | 69 | int tav_getdev(void *, struct audio_device *); |
70 | int tav_setfd(void *, int); | | 70 | int tav_setfd(void *, int); |
71 | int tav_set_port(void *, mixer_ctrl_t *); | | 71 | int tav_set_port(void *, mixer_ctrl_t *); |
72 | int tav_get_port(void *, mixer_ctrl_t *); | | 72 | int tav_get_port(void *, mixer_ctrl_t *); |
73 | int tav_query_devinfo(void *, mixer_devinfo_t *); | | 73 | int tav_query_devinfo(void *, mixer_devinfo_t *); |
74 | int tav_get_props(void *); | | 74 | int tav_get_props(void *); |
75 | void tav_get_locks(void *, kmutex_t **, kmutex_t **); | | 75 | void tav_get_locks(void *, kmutex_t **, kmutex_t **); |
76 | | | 76 | |
77 | const struct audio_hw_if tav_audio_if = { | | 77 | const struct audio_hw_if tav_audio_if = { |
78 | tav_open, | | 78 | tav_open, |
79 | tav_close, | | 79 | tav_close, |
80 | 0 /* tav_drain*/, /* optional */ | | 80 | 0 /* tav_drain*/, /* optional */ |
81 | tav_query_encoding, | | 81 | tav_query_encoding, |
82 | tav_set_params, | | 82 | tav_set_params, |
83 | tav_round_blocksize, | | 83 | tav_round_blocksize, |
84 | 0 /* commit_settings */, /* optional */ | | 84 | 0 /* commit_settings */, /* optional */ |
85 | tav_init_output, /* optional */ | | 85 | tav_init_output, /* optional */ |
86 | 0 /* tav_init_input */, /* optional */ | | 86 | 0 /* tav_init_input */, /* optional */ |
87 | tav_start_output, | | 87 | tav_start_output, |
88 | tav_start_input, | | 88 | tav_start_input, |
89 | tav_halt_output, | | 89 | tav_halt_output, |
90 | tav_halt_input, | | 90 | tav_halt_input, |
91 | tav_speaker_ctl, /* optional */ | | 91 | tav_speaker_ctl, /* optional */ |
92 | tav_getdev, | | 92 | tav_getdev, |
93 | 0 /* setfd */, /* optional */ | | 93 | 0 /* setfd */, /* optional */ |
94 | tav_set_port, | | 94 | tav_set_port, |
95 | tav_get_port, | | 95 | tav_get_port, |
96 | tav_query_devinfo, | | 96 | tav_query_devinfo, |
97 | 0 /* alloc */, /* optional */ | | 97 | 0 /* alloc */, /* optional */ |
98 | 0 /* free */, /* optional */ | | 98 | 0 /* free */, /* optional */ |
99 | 0 /* round_buffersize */, /* optional */ | | 99 | 0 /* round_buffersize */, /* optional */ |
100 | 0 /* mappage */, /* optional */ | | 100 | 0 /* mappage */, /* optional */ |
101 | tav_get_props, | | 101 | tav_get_props, |
102 | 0, /* trigger_output */ | | 102 | 0, /* trigger_output */ |
103 | 0, /* trigger_input */ | | 103 | 0, /* trigger_input */ |
104 | 0, /* dev_ioctl */ /* optional */ | | 104 | 0, /* dev_ioctl */ /* optional */ |
105 | tav_get_locks, | | 105 | tav_get_locks, |
106 | }; | | 106 | }; |
107 | | | 107 | |
108 | void | | 108 | void |
109 | tms320av110_attach_mi(struct tav_softc *sc) | | 109 | tms320av110_attach_mi(struct tav_softc *sc) |
110 | { | | 110 | { |
111 | bus_space_tag_t iot; | | 111 | bus_space_tag_t iot; |
112 | bus_space_handle_t ioh; | | 112 | bus_space_handle_t ioh; |
113 | | | 113 | |
114 | iot = sc->sc_iot; | | 114 | iot = sc->sc_iot; |
115 | ioh = sc->sc_ioh; | | 115 | ioh = sc->sc_ioh; |
116 | tav_write_byte(iot, ioh, TAV_RESET, 1); | | 116 | tav_write_byte(iot, ioh, TAV_RESET, 1); |
117 | while (tav_read_byte(iot, ioh, TAV_RESET)) | | 117 | while (tav_read_byte(iot, ioh, TAV_RESET)) |
118 | delay(250); | | 118 | delay(250); |
119 | | | 119 | |
120 | tav_write_byte(iot, ioh, TAV_PCM_ORD, sc->sc_pcm_ord); | | 120 | tav_write_byte(iot, ioh, TAV_PCM_ORD, sc->sc_pcm_ord); |
121 | tav_write_byte(iot, ioh, TAV_PCM_18, sc->sc_pcm_18); | | 121 | tav_write_byte(iot, ioh, TAV_PCM_18, sc->sc_pcm_18); |
122 | tav_write_byte(iot, ioh, TAV_DIF, sc->sc_dif); | | 122 | tav_write_byte(iot, ioh, TAV_DIF, sc->sc_dif); |
123 | tav_write_byte(iot, ioh, TAV_PCM_DIV, sc->sc_pcm_div); | | 123 | tav_write_byte(iot, ioh, TAV_PCM_DIV, sc->sc_pcm_div); |
124 | | | 124 | |
125 | printf(": chip rev. %d, %d bytes buffer\n", | | 125 | printf(": chip rev. %d, %d bytes buffer\n", |
126 | tav_read_byte(iot, ioh, TAV_VERSION), | | 126 | tav_read_byte(iot, ioh, TAV_VERSION), |
127 | TAV_DRAM_SIZE(tav_read_byte(iot, ioh, TAV_DRAM_EXT))); | | 127 | TAV_DRAM_SIZE(tav_read_byte(iot, ioh, TAV_DRAM_EXT))); |
128 | | | 128 | |
129 | tav_write_byte(iot, ioh, TAV_AUD_ID_EN, 0); | | 129 | tav_write_byte(iot, ioh, TAV_AUD_ID_EN, 0); |
130 | tav_write_byte(iot, ioh, TAV_SKIP, 0); | | 130 | tav_write_byte(iot, ioh, TAV_SKIP, 0); |
131 | tav_write_byte(iot, ioh, TAV_REPEAT, 0); | | 131 | tav_write_byte(iot, ioh, TAV_REPEAT, 0); |
132 | tav_write_byte(iot, ioh, TAV_MUTE, 0); | | 132 | tav_write_byte(iot, ioh, TAV_MUTE, 0); |
133 | tav_write_byte(iot, ioh, TAV_PLAY, 1); | | 133 | tav_write_byte(iot, ioh, TAV_PLAY, 1); |
134 | tav_write_byte(iot, ioh, TAV_SYNC_ECM, 0); | | 134 | tav_write_byte(iot, ioh, TAV_SYNC_ECM, 0); |
135 | tav_write_byte(iot, ioh, TAV_CRC_ECM, 0); | | 135 | tav_write_byte(iot, ioh, TAV_CRC_ECM, 0); |
136 | tav_write_byte(iot, ioh, TAV_ATTEN_L, 0); | | 136 | tav_write_byte(iot, ioh, TAV_ATTEN_L, 0); |
137 | tav_write_byte(iot, ioh, TAV_ATTEN_R, 0); | | 137 | tav_write_byte(iot, ioh, TAV_ATTEN_R, 0); |
138 | tav_write_short(iot, ioh, TAV_FREE_FORM, 0); | | 138 | tav_write_short(iot, ioh, TAV_FREE_FORM, 0); |
139 | tav_write_byte(iot, ioh, TAV_SIN_EN, 0); | | 139 | tav_write_byte(iot, ioh, TAV_SIN_EN, 0); |
140 | tav_write_byte(iot, ioh, TAV_SYNC_ECM, TAV_ECM_REPEAT); | | 140 | tav_write_byte(iot, ioh, TAV_SYNC_ECM, TAV_ECM_REPEAT); |
141 | tav_write_byte(iot, ioh, TAV_CRC_ECM, TAV_ECM_REPEAT); | | 141 | tav_write_byte(iot, ioh, TAV_CRC_ECM, TAV_ECM_REPEAT); |
142 | | | 142 | |
143 | audio_attach_mi(&tav_audio_if, sc, sc->sc_dev); | | 143 | audio_attach_mi(&tav_audio_if, sc, sc->sc_dev); |
144 | } | | 144 | } |
145 | | | 145 | |
146 | int | | 146 | int |
147 | tms320av110_intr(void *p) | | 147 | tms320av110_intr(void *p) |
148 | { | | 148 | { |
149 | struct tav_softc *sc; | | 149 | struct tav_softc *sc; |
150 | uint16_t intlist; | | 150 | uint16_t intlist; |
151 | | | 151 | |
152 | sc = p; | | 152 | sc = p; |
153 | | | 153 | |
154 | mutex_spin_enter(&sc->sc_intr_lock); | | 154 | mutex_spin_enter(&sc->sc_intr_lock); |
155 | | | 155 | |
156 | intlist = tav_read_short(sc->sc_iot, sc->sc_ioh, TAV_INTR) | | 156 | intlist = tav_read_short(sc->sc_iot, sc->sc_ioh, TAV_INTR) |
157 | /* & tav_read_short(sc->sc_iot, sc->sc_ioh, TAV_INTR_EN)*/; | | 157 | /* & tav_read_short(sc->sc_iot, sc->sc_ioh, TAV_INTR_EN)*/; |
158 | | | 158 | |
159 | if (!intlist) | | 159 | if (!intlist) |
160 | return 0; | | 160 | return 0; |
161 | | | 161 | |
162 | /* ack now, so that we don't miss later interrupts */ | | 162 | /* ack now, so that we don't miss later interrupts */ |
163 | if (sc->sc_intack) | | 163 | if (sc->sc_intack) |
164 | (sc->sc_intack)(sc); | | 164 | (sc->sc_intack)(sc); |
165 | | | 165 | |
166 | if (intlist & TAV_INTR_LOWWATER) { | | 166 | if (intlist & TAV_INTR_LOWWATER) { |
167 | (*sc->sc_intr)(sc->sc_intrarg); | | 167 | (*sc->sc_intr)(sc->sc_intrarg); |
168 | } | | 168 | } |
169 | | | 169 | |
170 | if (intlist & TAV_INTR_PCM_OUTPUT_UNDERFLOW) { | | 170 | if (intlist & TAV_INTR_PCM_OUTPUT_UNDERFLOW) { |
171 | cv_broadcast(&sc->sc_cv); | | 171 | cv_broadcast(&sc->sc_cv); |
172 | } | | 172 | } |
173 | | | 173 | |
174 | mutex_spin_exit(&sc->sc_intr_lock); | | 174 | mutex_spin_exit(&sc->sc_intr_lock); |
175 | | | 175 | |
176 | return 1; | | 176 | return 1; |
177 | } | | 177 | } |
178 | | | 178 | |
179 | struct audio_encoding tav_encodings[] = { | | 179 | struct audio_encoding tav_encodings[] = { |
180 | {0, AudioEmpeg_l2_stream, AUDIO_ENCODING_MPEG_L2_STREAM, 1, 0,}, | | 180 | {0, AudioEmpeg_l2_stream, AUDIO_ENCODING_MPEG_L2_STREAM, 1, 0,}, |
181 | {1, AudioEmpeg_l2_packets, AUDIO_ENCODING_MPEG_L2_PACKETS, 1, 0,}, | | 181 | {1, AudioEmpeg_l2_packets, AUDIO_ENCODING_MPEG_L2_PACKETS, 1, 0,}, |
182 | {2, AudioEmpeg_l2_system, AUDIO_ENCODING_MPEG_L2_SYSTEM, 1, 0,}, | | 182 | {2, AudioEmpeg_l2_system, AUDIO_ENCODING_MPEG_L2_SYSTEM, 1, 0,}, |
183 | {3, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 16, 0,}, | | 183 | {3, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 16, 0,}, |
184 | }; | | 184 | }; |
185 | | | 185 | |
186 | int | | 186 | int |
187 | tav_open(void *hdl, int flags) | | 187 | tav_open(void *hdl, int flags) |
188 | { | | 188 | { |
189 | | | 189 | |
190 | /* dummy */ | | 190 | /* dummy */ |
191 | return 0; | | 191 | return 0; |
192 | } | | 192 | } |
193 | | | 193 | |
194 | void | | 194 | void |
195 | tav_close(void *hdl) | | 195 | tav_close(void *hdl) |
196 | { | | 196 | { |
197 | struct tav_softc *sc; | | 197 | struct tav_softc *sc; |
198 | bus_space_tag_t iot; | | 198 | bus_space_tag_t iot; |
199 | bus_space_handle_t ioh; | | 199 | bus_space_handle_t ioh; |
200 | | | 200 | |
201 | sc = hdl; | | 201 | sc = hdl; |
202 | iot = sc->sc_iot; | | 202 | iot = sc->sc_iot; |
203 | ioh = sc->sc_ioh; | | 203 | ioh = sc->sc_ioh; |
204 | | | 204 | |
205 | /* re"start" chip, also clears interrupts and interrupt enable */ | | 205 | /* re"start" chip, also clears interrupts and interrupt enable */ |
206 | tav_write_short(iot, ioh, TAV_INTR_EN, 0); | | 206 | tav_write_short(iot, ioh, TAV_INTR_EN, 0); |
207 | if (sc->sc_intack) | | 207 | if (sc->sc_intack) |
208 | (*sc->sc_intack)(sc); | | 208 | (*sc->sc_intack)(sc); |
209 | } | | 209 | } |
210 | | | 210 | |
211 | int | | 211 | int |
212 | tav_drain(void *hdl) | | 212 | tav_drain(void *hdl) |
213 | { | | 213 | { |
214 | struct tav_softc *sc; | | 214 | struct tav_softc *sc; |
215 | bus_space_tag_t iot; | | 215 | bus_space_tag_t iot; |
216 | bus_space_handle_t ioh; | | 216 | bus_space_handle_t ioh; |
217 | u_int16_t mask; | | 217 | u_int16_t mask; |
218 | | | 218 | |
219 | sc = hdl; | | 219 | sc = hdl; |
220 | iot = sc->sc_iot; | | 220 | iot = sc->sc_iot; |
221 | ioh = sc->sc_ioh; | | 221 | ioh = sc->sc_ioh; |
222 | | | 222 | |
223 | mutex_spin_enter(&sc->sc_intr_lock); | | 223 | mutex_spin_enter(&sc->sc_intr_lock); |
224 | | | 224 | |
225 | /* | | 225 | /* |
226 | * wait for underflow interrupt. | | 226 | * wait for underflow interrupt. |
227 | */ | | 227 | */ |
228 | if (tav_read_short(iot, ioh, TAV_BUFF)) { | | 228 | if (tav_read_short(iot, ioh, TAV_BUFF)) { |
229 | mask = tav_read_short(iot, ioh, TAV_INTR_EN); | | 229 | mask = tav_read_short(iot, ioh, TAV_INTR_EN); |
230 | tav_write_short(iot, ioh, TAV_INTR_EN, | | 230 | tav_write_short(iot, ioh, TAV_INTR_EN, |
231 | mask|TAV_INTR_PCM_OUTPUT_UNDERFLOW); | | 231 | mask|TAV_INTR_PCM_OUTPUT_UNDERFLOW); |
232 | | | 232 | |
233 | /* still more than zero? */ | | 233 | /* still more than zero? */ |
234 | if (tav_read_short(iot, ioh, TAV_BUFF)) { | | 234 | if (tav_read_short(iot, ioh, TAV_BUFF)) { |
235 | (void)cv_timedwait_sig(&sc->sc_cv, | | 235 | (void)cv_timedwait_sig(&sc->sc_cv, |
236 | &sc->sc_intr_lock, 32*hz); | | 236 | &sc->sc_intr_lock, 32*hz); |
237 | } | | 237 | } |
238 | | | 238 | |
239 | /* can be really that long for mpeg */ | | 239 | /* can be really that long for mpeg */ |
240 | | | 240 | |
241 | mask = tav_read_short(iot, ioh, TAV_INTR_EN); | | 241 | mask = tav_read_short(iot, ioh, TAV_INTR_EN); |
242 | tav_write_short(iot, ioh, TAV_INTR_EN, | | 242 | tav_write_short(iot, ioh, TAV_INTR_EN, |
243 | mask & ~TAV_INTR_PCM_OUTPUT_UNDERFLOW); | | 243 | mask & ~TAV_INTR_PCM_OUTPUT_UNDERFLOW); |
244 | } | | 244 | } |
245 | | | 245 | |
246 | mutex_spin_exit(&sc->sc_intr_lock); | | 246 | mutex_spin_exit(&sc->sc_intr_lock); |
247 | | | 247 | |
248 | return 0; | | 248 | return 0; |
249 | } | | 249 | } |
250 | | | 250 | |
251 | int | | 251 | int |
252 | tav_query_encoding(void *hdl, struct audio_encoding *ae) | | 252 | tav_query_encoding(void *hdl, struct audio_encoding *ae) |
253 | { | | 253 | { |
254 | struct tav_softc *sc; | | | |
255 | | | 254 | |
256 | sc = hdl; | | | |
257 | if (ae->index >= sizeof(tav_encodings)/sizeof(*ae)) | | 255 | if (ae->index >= sizeof(tav_encodings)/sizeof(*ae)) |
258 | return EINVAL; | | 256 | return EINVAL; |
259 | | | 257 | |
260 | *ae = tav_encodings[ae->index]; | | 258 | *ae = tav_encodings[ae->index]; |
261 | | | 259 | |
262 | return 0; | | 260 | return 0; |
263 | } | | 261 | } |
264 | | | 262 | |
265 | int | | 263 | int |
266 | tav_start_input(void *hdl, void *block, int bsize, | | 264 | tav_start_input(void *hdl, void *block, int bsize, |
267 | void (*intr)(void *), void *intrarg) | | 265 | void (*intr)(void *), void *intrarg) |
268 | { | | 266 | { |
269 | | | 267 | |
270 | return ENOTTY; | | 268 | return ENOTTY; |
271 | } | | 269 | } |
272 | | | 270 | |
273 | int | | 271 | int |
274 | tav_halt_input(void *hdl) | | 272 | tav_halt_input(void *hdl) |
275 | { | | 273 | { |
276 | | | 274 | |
277 | return ENOTTY; | | 275 | return ENOTTY; |
278 | } | | 276 | } |
279 | | | 277 | |
280 | int | | 278 | int |
281 | tav_start_output(void *hdl, void *block, int bsize, | | 279 | tav_start_output(void *hdl, void *block, int bsize, |
282 | void (*intr)(void *), void *intrarg) | | 280 | void (*intr)(void *), void *intrarg) |
283 | { | | 281 | { |
284 | struct tav_softc *sc; | | 282 | struct tav_softc *sc; |
285 | bus_space_tag_t iot; | | 283 | bus_space_tag_t iot; |
286 | bus_space_handle_t ioh; | | 284 | bus_space_handle_t ioh; |
287 | uint8_t *ptr; | | 285 | uint8_t *ptr; |
288 | int count; | | 286 | int count; |
289 | | | 287 | |
290 | sc = hdl; | | 288 | sc = hdl; |
291 | iot = sc->sc_iot; | | 289 | iot = sc->sc_iot; |
292 | ioh = sc->sc_ioh; | | 290 | ioh = sc->sc_ioh; |
293 | ptr = block; | | 291 | ptr = block; |
294 | count = bsize; | | 292 | count = bsize; |
295 | | | 293 | |
296 | sc->sc_intr = intr; | | 294 | sc->sc_intr = intr; |
297 | sc->sc_intrarg = intrarg; | | 295 | sc->sc_intrarg = intrarg; |
298 | | | 296 | |
299 | bus_space_write_multi_1(iot, ioh, TAV_DATAIN, ptr, count); | | 297 | bus_space_write_multi_1(iot, ioh, TAV_DATAIN, ptr, count); |
300 | tav_write_short(iot, ioh, TAV_INTR_EN, TAV_INTR_LOWWATER); | | 298 | tav_write_short(iot, ioh, TAV_INTR_EN, TAV_INTR_LOWWATER); |
301 | | | 299 | |
302 | return 0; | | 300 | return 0; |
303 | } | | 301 | } |
304 | | | 302 | |
305 | int | | 303 | int |
306 | tav_init_output(void *hdl, void *buffer, int size) | | 304 | tav_init_output(void *hdl, void *buffer, int size) |
307 | { | | 305 | { |
308 | struct tav_softc *sc; | | 306 | struct tav_softc *sc; |
309 | bus_space_tag_t iot; | | 307 | bus_space_tag_t iot; |
310 | bus_space_handle_t ioh; | | 308 | bus_space_handle_t ioh; |
311 | | | 309 | |
312 | sc = hdl; | | 310 | sc = hdl; |
313 | iot = sc->sc_iot; | | 311 | iot = sc->sc_iot; |
314 | ioh = sc->sc_ioh; | | 312 | ioh = sc->sc_ioh; |
315 | | | 313 | |
316 | tav_write_byte(iot, ioh, TAV_PLAY, 1); | | 314 | tav_write_byte(iot, ioh, TAV_PLAY, 1); |
317 | tav_write_byte(iot, ioh, TAV_MUTE, 0); | | 315 | tav_write_byte(iot, ioh, TAV_MUTE, 0); |
318 | | | 316 | |
319 | return 0; | | 317 | return 0; |
320 | } | | 318 | } |
321 | | | 319 | |
322 | int | | 320 | int |
323 | tav_halt_output(void *hdl) | | 321 | tav_halt_output(void *hdl) |
324 | { | | 322 | { |
325 | struct tav_softc *sc; | | 323 | struct tav_softc *sc; |
326 | bus_space_tag_t iot; | | 324 | bus_space_tag_t iot; |
327 | bus_space_handle_t ioh; | | 325 | bus_space_handle_t ioh; |
328 | | | 326 | |
329 | sc = hdl; | | 327 | sc = hdl; |
330 | iot = sc->sc_iot; | | 328 | iot = sc->sc_iot; |
331 | ioh = sc->sc_ioh; | | 329 | ioh = sc->sc_ioh; |
332 | | | 330 | |
333 | tav_write_byte(iot, ioh, TAV_PLAY, 0); | | 331 | tav_write_byte(iot, ioh, TAV_PLAY, 0); |
334 | | | 332 | |
335 | return 0; | | 333 | return 0; |
336 | } | | 334 | } |
337 | | | 335 | |
338 | int | | 336 | int |
339 | tav_getdev(void *hdl, struct audio_device *ret) | | 337 | tav_getdev(void *hdl, struct audio_device *ret) |
340 | { | | 338 | { |
341 | struct tav_softc *sc; | | 339 | struct tav_softc *sc; |
342 | bus_space_tag_t iot; | | 340 | bus_space_tag_t iot; |
343 | bus_space_handle_t ioh; | | 341 | bus_space_handle_t ioh; |
344 | | | 342 | |
345 | sc = hdl; | | 343 | sc = hdl; |
346 | iot = sc->sc_iot; | | 344 | iot = sc->sc_iot; |
347 | ioh = sc->sc_ioh; | | 345 | ioh = sc->sc_ioh; |
348 | | | 346 | |
349 | strlcpy(ret->name, "tms320av110", sizeof(ret->name)); | | 347 | strlcpy(ret->name, "tms320av110", sizeof(ret->name)); |
350 | /* guaranteed to be <= 4 in length */ | | 348 | /* guaranteed to be <= 4 in length */ |
351 | snprintf(ret->version, sizeof(ret->version), "%u", | | 349 | snprintf(ret->version, sizeof(ret->version), "%u", |
352 | tav_read_byte(iot, ioh, TAV_VERSION)); | | 350 | tav_read_byte(iot, ioh, TAV_VERSION)); |
353 | strlcpy(ret->config, device_xname(sc->sc_dev), sizeof(ret->config)); | | 351 | strlcpy(ret->config, device_xname(sc->sc_dev), sizeof(ret->config)); |
354 | | | 352 | |
355 | return 0; | | 353 | return 0; |
356 | } | | 354 | } |
357 | | | 355 | |
358 | int | | 356 | int |
359 | tav_round_blocksize(void *hdl, int size, int mode, const audio_params_t *param) | | 357 | tav_round_blocksize(void *hdl, int size, int mode, const audio_params_t *param) |
360 | { | | 358 | { |
361 | struct tav_softc *sc; | | 359 | struct tav_softc *sc; |
362 | bus_space_tag_t iot; | | 360 | bus_space_tag_t iot; |
363 | bus_space_handle_t ioh; | | 361 | bus_space_handle_t ioh; |
364 | int maxhalf; | | 362 | int maxhalf; |
365 | | | 363 | |
366 | sc = hdl; | | 364 | sc = hdl; |
367 | iot = sc->sc_iot; | | 365 | iot = sc->sc_iot; |
368 | ioh = sc->sc_ioh; | | 366 | ioh = sc->sc_ioh; |
369 | | | 367 | |
370 | maxhalf = TAV_DRAM_HSIZE(tav_read_byte(iot, ioh, TAV_DRAM_EXT)); | | 368 | maxhalf = TAV_DRAM_HSIZE(tav_read_byte(iot, ioh, TAV_DRAM_EXT)); |
371 | if (size > maxhalf) | | 369 | if (size > maxhalf) |
372 | size = maxhalf; | | 370 | size = maxhalf; |
373 | | | 371 | |
374 | /* XXX should round to 128 bytes limits for audio bypass */ | | 372 | /* XXX should round to 128 bytes limits for audio bypass */ |
375 | size &= ~3; | | 373 | size &= ~3; |
376 | | | 374 | |
377 | tav_write_short(iot, ioh, TAV_BALE_LIM, size/8); | | 375 | tav_write_short(iot, ioh, TAV_BALE_LIM, size/8); |
378 | | | 376 | |
379 | /* the buffer limits are in units of 4 bytes */ | | 377 | /* the buffer limits are in units of 4 bytes */ |
380 | return (size); | | 378 | return (size); |
381 | } | | 379 | } |
382 | | | 380 | |
383 | int | | 381 | int |
384 | tav_get_props(void *hdl) | | 382 | tav_get_props(void *hdl) |
385 | { | | 383 | { |
386 | return 0; | | 384 | return 0; |
387 | } | | 385 | } |
388 | | | 386 | |
389 | void | | 387 | void |
390 | tav_get_locks(void *hdl, kmutex_t **intr, kmutex_t **thread) | | 388 | tav_get_locks(void *hdl, kmutex_t **intr, kmutex_t **thread) |
391 | { | | 389 | { |
392 | struct tav_softc *sc; | | 390 | struct tav_softc *sc; |
393 | | | 391 | |
394 | sc = hdl; | | 392 | sc = hdl; |
395 | *intr = &sc->sc_intr_lock; | | 393 | *intr = &sc->sc_intr_lock; |
396 | *thread = &sc->sc_lock; | | 394 | *thread = &sc->sc_lock; |
397 | } | | 395 | } |
398 | | | 396 | |
399 | int | | 397 | int |
400 | tav_set_params(void *hdl, int setmode, int usemode, audio_params_t *p, | | 398 | tav_set_params(void *hdl, int setmode, int usemode, audio_params_t *p, |
401 | audio_params_t *r, stream_filter_list_t *pfil, stream_filter_list_t *rfil) | | 399 | audio_params_t *r, stream_filter_list_t *pfil, stream_filter_list_t *rfil) |
402 | { | | 400 | { |
403 | struct tav_softc *sc; | | 401 | struct tav_softc *sc; |
404 | bus_space_tag_t iot; | | 402 | bus_space_tag_t iot; |
405 | bus_space_handle_t ioh; | | 403 | bus_space_handle_t ioh; |
406 | | | 404 | |
407 | sc = hdl; | | 405 | sc = hdl; |
408 | iot = sc->sc_iot; | | 406 | iot = sc->sc_iot; |
409 | ioh = sc->sc_ioh; | | 407 | ioh = sc->sc_ioh; |
410 | | | 408 | |
411 | if (!(setmode & AUMODE_PLAY)) | | 409 | if (!(setmode & AUMODE_PLAY)) |
412 | return 0; | | 410 | return 0; |
413 | | | 411 | |
414 | if (p->encoding == AUDIO_ENCODING_ULAW) | | 412 | if (p->encoding == AUDIO_ENCODING_ULAW) |
415 | p->encoding = AUDIO_ENCODING_MPEG_L2_STREAM; | | 413 | p->encoding = AUDIO_ENCODING_MPEG_L2_STREAM; |
416 | | | 414 | |
417 | switch(p->encoding) { | | 415 | switch(p->encoding) { |
418 | default: | | 416 | default: |
419 | return EINVAL; | | 417 | return EINVAL; |
420 | | | 418 | |
421 | case AUDIO_ENCODING_SLINEAR_BE: | | 419 | case AUDIO_ENCODING_SLINEAR_BE: |
422 | | | 420 | |
423 | /* XXX: todo: add 8bit and mono using software */ | | 421 | /* XXX: todo: add 8bit and mono using software */ |
424 | p->precision = 16; | | 422 | p->precision = 16; |
425 | p->channels = 2; | | 423 | p->channels = 2; |
426 | | | 424 | |
427 | /* XXX: this might depend on the specific board. | | 425 | /* XXX: this might depend on the specific board. |
428 | should be handled by the backend */ | | 426 | should be handled by the backend */ |
429 | | | 427 | |
430 | p->sample_rate = 44100; | | 428 | p->sample_rate = 44100; |
431 | | | 429 | |
432 | bus_space_write_1(iot, ioh, TAV_STR_SEL, | | 430 | bus_space_write_1(iot, ioh, TAV_STR_SEL, |
433 | TAV_STR_SEL_AUDIO_BYPASS); | | 431 | TAV_STR_SEL_AUDIO_BYPASS); |
434 | break; | | 432 | break; |
435 | | | 433 | |
436 | /* XXX: later: add ULINEAR, and LE using software encoding */ | | 434 | /* XXX: later: add ULINEAR, and LE using software encoding */ |
437 | | | 435 | |
438 | case AUDIO_ENCODING_MPEG_L1_STREAM: | | 436 | case AUDIO_ENCODING_MPEG_L1_STREAM: |
439 | /* FALLTHROUGH */ | | 437 | /* FALLTHROUGH */ |
440 | case AUDIO_ENCODING_MPEG_L2_STREAM: | | 438 | case AUDIO_ENCODING_MPEG_L2_STREAM: |
441 | bus_space_write_1(iot, ioh, TAV_STR_SEL, | | 439 | bus_space_write_1(iot, ioh, TAV_STR_SEL, |
442 | TAV_STR_SEL_MPEG_AUDIO_STREAM); | | 440 | TAV_STR_SEL_MPEG_AUDIO_STREAM); |
443 | p->sample_rate = 44100; | | 441 | p->sample_rate = 44100; |
444 | p->precision = 1; | | 442 | p->precision = 1; |
445 | break; | | 443 | break; |
446 | | | 444 | |
447 | case AUDIO_ENCODING_MPEG_L1_PACKETS: | | 445 | case AUDIO_ENCODING_MPEG_L1_PACKETS: |
448 | /* FALLTHROUGH */ | | 446 | /* FALLTHROUGH */ |
449 | case AUDIO_ENCODING_MPEG_L2_PACKETS: | | 447 | case AUDIO_ENCODING_MPEG_L2_PACKETS: |
450 | bus_space_write_1(iot, ioh, TAV_STR_SEL, | | 448 | bus_space_write_1(iot, ioh, TAV_STR_SEL, |
451 | TAV_STR_SEL_MPEG_AUDIO_PACKETS); | | 449 | TAV_STR_SEL_MPEG_AUDIO_PACKETS); |
452 | p->sample_rate = 44100; | | 450 | p->sample_rate = 44100; |
453 | p->precision = 1; | | 451 | p->precision = 1; |
454 | break; | | 452 | break; |
455 | | | 453 | |
456 | case AUDIO_ENCODING_MPEG_L1_SYSTEM: | | 454 | case AUDIO_ENCODING_MPEG_L1_SYSTEM: |
457 | /* FALLTHROUGH */ | | 455 | /* FALLTHROUGH */ |
458 | case AUDIO_ENCODING_MPEG_L2_SYSTEM: | | 456 | case AUDIO_ENCODING_MPEG_L2_SYSTEM: |
459 | bus_space_write_1(iot, ioh, TAV_STR_SEL, | | 457 | bus_space_write_1(iot, ioh, TAV_STR_SEL, |
460 | TAV_STR_SEL_MPEG_SYSTEM_STREAM); | | 458 | TAV_STR_SEL_MPEG_SYSTEM_STREAM); |
461 | p->sample_rate = 44100; | | 459 | p->sample_rate = 44100; |
462 | p->precision = 1; | | 460 | p->precision = 1; |
463 | break; | | 461 | break; |
464 | } | | 462 | } |
465 | tav_write_byte(iot, ioh, TAV_RESTART, 1); | | 463 | tav_write_byte(iot, ioh, TAV_RESTART, 1); |
466 | do { | | 464 | do { |
467 | delay(10); | | 465 | delay(10); |
468 | } while (tav_read_byte(iot, ioh, TAV_RESTART)); | | 466 | } while (tav_read_byte(iot, ioh, TAV_RESTART)); |
469 | | | 467 | |
470 | return 0; | | 468 | return 0; |
471 | } | | 469 | } |
472 | | | 470 | |
473 | int | | 471 | int |
474 | tav_set_port(void *hdl, mixer_ctrl_t *mc) | | 472 | tav_set_port(void *hdl, mixer_ctrl_t *mc) |
475 | { | | 473 | { |
476 | struct tav_softc *sc; | | | |
477 | | | 474 | |
478 | sc = hdl; | | | |
479 | /* dummy */ | | 475 | /* dummy */ |
480 | return 0; | | 476 | return 0; |
481 | } | | 477 | } |
482 | | | 478 | |
483 | int | | 479 | int |
484 | tav_get_port(void *hdl, mixer_ctrl_t *mc) | | 480 | tav_get_port(void *hdl, mixer_ctrl_t *mc) |
485 | { | | 481 | { |
486 | struct tav_softc *sc; | | | |
487 | | | 482 | |
488 | sc = hdl; | | | |
489 | /* dummy */ | | 483 | /* dummy */ |
490 | return 0; | | 484 | return 0; |
491 | } | | 485 | } |
492 | | | 486 | |
493 | int | | 487 | int |
494 | tav_query_devinfo(void *hdl, mixer_devinfo_t *di) | | 488 | tav_query_devinfo(void *hdl, mixer_devinfo_t *di) |
495 | { | | 489 | { |
496 | return ENXIO; | | 490 | return ENXIO; |
497 | } | | 491 | } |
498 | | | 492 | |
499 | int | | 493 | int |
500 | tav_speaker_ctl(void *hdl, int value) | | 494 | tav_speaker_ctl(void *hdl, int value) |
501 | { | | 495 | { |
502 | struct tav_softc *sc; | | 496 | struct tav_softc *sc; |
503 | bus_space_tag_t iot; | | 497 | bus_space_tag_t iot; |
504 | bus_space_handle_t ioh; | | 498 | bus_space_handle_t ioh; |
505 | | | 499 | |
506 | sc = hdl; | | 500 | sc = hdl; |
507 | iot = sc->sc_iot; | | 501 | iot = sc->sc_iot; |
508 | ioh = sc->sc_ioh; | | 502 | ioh = sc->sc_ioh; |
509 | | | 503 | |
510 | tav_write_byte(iot, ioh, TAV_MUTE, !value); | | 504 | tav_write_byte(iot, ioh, TAV_MUTE, !value); |
511 | | | 505 | |
512 | return 0; | | 506 | return 0; |
513 | } | | 507 | } |