1 1.11 gutterid /* $NetBSD: harmony.c,v 1.11 2022/05/15 00:25:15 gutteridge Exp $ */ 2 1.1 skrll 3 1.1 skrll /* $OpenBSD: harmony.c,v 1.23 2004/02/13 21:28:19 mickey Exp $ */ 4 1.1 skrll 5 1.1 skrll /*- 6 1.1 skrll * Copyright (c) 2009 The NetBSD Foundation, Inc. 7 1.1 skrll * All rights reserved. 8 1.1 skrll * 9 1.1 skrll * This code is derived from software contributed to The NetBSD Foundation 10 1.1 skrll * by Matt Fleming. 11 1.1 skrll * 12 1.1 skrll * Redistribution and use in source and binary forms, with or without 13 1.1 skrll * modification, are permitted provided that the following conditions 14 1.1 skrll * are met: 15 1.1 skrll * 1. Redistributions of source code must retain the above copyright 16 1.1 skrll * notice, this list of conditions and the following disclaimer. 17 1.1 skrll * 2. Redistributions in binary form must reproduce the above copyright 18 1.1 skrll * notice, this list of conditions and the following disclaimer in the 19 1.1 skrll * documentation and/or other materials provided with the distribution. 20 1.1 skrll * 21 1.1 skrll * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 1.1 skrll * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 1.1 skrll * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 1.1 skrll * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 1.1 skrll * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 1.1 skrll * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 1.1 skrll * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 1.1 skrll * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 1.1 skrll * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 1.1 skrll * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 1.1 skrll * POSSIBILITY OF SUCH DAMAGE. 32 1.1 skrll */ 33 1.1 skrll 34 1.1 skrll /* 35 1.1 skrll * Copyright (c) 2003 Jason L. Wright (jason (at) thought.net) 36 1.1 skrll * All rights reserved. 37 1.1 skrll * 38 1.1 skrll * Redistribution and use in source and binary forms, with or without 39 1.1 skrll * modification, are permitted provided that the following conditions 40 1.1 skrll * are met: 41 1.1 skrll * 1. Redistributions of source code must retain the above copyright 42 1.1 skrll * notice, this list of conditions and the following disclaimer. 43 1.1 skrll * 2. Redistributions in binary form must reproduce the above copyright 44 1.1 skrll * notice, this list of conditions and the following disclaimer in the 45 1.1 skrll * documentation and/or other materials provided with the distribution. 46 1.1 skrll * 47 1.1 skrll * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 48 1.1 skrll * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 49 1.1 skrll * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 50 1.1 skrll * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 51 1.1 skrll * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 52 1.1 skrll * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 53 1.1 skrll * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 54 1.1 skrll * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 55 1.1 skrll * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 56 1.1 skrll * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 57 1.1 skrll * POSSIBILITY OF SUCH DAMAGE. 58 1.1 skrll */ 59 1.1 skrll 60 1.1 skrll /* 61 1.1 skrll * Harmony (CS4215/AD1849 LASI) audio interface. 62 1.1 skrll */ 63 1.1 skrll 64 1.1 skrll 65 1.1 skrll 66 1.1 skrll #include <sys/param.h> 67 1.1 skrll #include <sys/kernel.h> 68 1.1 skrll #include <sys/systm.h> 69 1.1 skrll #include <sys/errno.h> 70 1.1 skrll #include <sys/ioctl.h> 71 1.1 skrll #include <sys/device.h> 72 1.1 skrll #include <sys/proc.h> 73 1.1 skrll #include <sys/kmem.h> 74 1.1 skrll #include <uvm/uvm_extern.h> 75 1.1 skrll 76 1.3 riastrad #include <sys/rndsource.h> 77 1.1 skrll 78 1.1 skrll #include <sys/audioio.h> 79 1.6 isaki #include <dev/audio/audio_if.h> 80 1.1 skrll 81 1.1 skrll #include <machine/cpu.h> 82 1.1 skrll #include <machine/intr.h> 83 1.1 skrll #include <machine/iomod.h> 84 1.1 skrll #include <machine/autoconf.h> 85 1.1 skrll #include <sys/bus.h> 86 1.1 skrll 87 1.1 skrll #include <hppa/dev/cpudevs.h> 88 1.1 skrll #include <hppa/gsc/gscbusvar.h> 89 1.1 skrll #include <hppa/gsc/harmonyreg.h> 90 1.1 skrll #include <hppa/gsc/harmonyvar.h> 91 1.1 skrll 92 1.1 skrll void harmony_close(void *); 93 1.6 isaki int harmony_query_format(void *, audio_format_query_t *); 94 1.6 isaki int harmony_set_format(void *, int, 95 1.6 isaki const audio_params_t *, const audio_params_t *, 96 1.6 isaki audio_filter_reg_t *, audio_filter_reg_t *); 97 1.1 skrll int harmony_round_blocksize(void *, int, int, const audio_params_t *); 98 1.1 skrll 99 1.1 skrll int harmony_control_wait(struct harmony_softc *); 100 1.1 skrll int harmony_commit_settings(void *); 101 1.1 skrll 102 1.1 skrll int harmony_halt_output(void *); 103 1.1 skrll int harmony_halt_input(void *); 104 1.1 skrll int harmony_getdev(void *, struct audio_device *); 105 1.1 skrll int harmony_set_port(void *, mixer_ctrl_t *); 106 1.1 skrll int harmony_get_port(void *, mixer_ctrl_t *); 107 1.1 skrll int harmony_query_devinfo(void *, mixer_devinfo_t *); 108 1.1 skrll void * harmony_allocm(void *, int, size_t); 109 1.1 skrll void harmony_freem(void *, void *, size_t); 110 1.1 skrll size_t harmony_round_buffersize(void *, int, size_t); 111 1.1 skrll int harmony_get_props(void *); 112 1.1 skrll int harmony_trigger_output(void *, void *, void *, int, 113 1.1 skrll void (*)(void *), void *, const audio_params_t *); 114 1.1 skrll int harmony_trigger_input(void *, void *, void *, int, 115 1.1 skrll void (*)(void *), void *, const audio_params_t *); 116 1.1 skrll void harmony_get_locks(void *, kmutex_t **, kmutex_t **); 117 1.1 skrll 118 1.1 skrll const struct audio_hw_if harmony_sa_hw_if = { 119 1.5 isaki .close = harmony_close, 120 1.6 isaki .query_format = harmony_query_format, 121 1.6 isaki .set_format = harmony_set_format, 122 1.5 isaki .round_blocksize = harmony_round_blocksize, 123 1.5 isaki .commit_settings = harmony_commit_settings, 124 1.5 isaki .halt_output = harmony_halt_output, 125 1.5 isaki .halt_input = harmony_halt_input, 126 1.5 isaki .getdev = harmony_getdev, 127 1.5 isaki .set_port = harmony_set_port, 128 1.5 isaki .get_port = harmony_get_port, 129 1.5 isaki .query_devinfo = harmony_query_devinfo, 130 1.5 isaki .allocm = harmony_allocm, 131 1.5 isaki .freem = harmony_freem, 132 1.5 isaki .round_buffersize = harmony_round_buffersize, 133 1.5 isaki .get_props = harmony_get_props, 134 1.5 isaki .trigger_output = harmony_trigger_output, 135 1.5 isaki .trigger_input = harmony_trigger_input, 136 1.5 isaki .get_locks = harmony_get_locks, 137 1.1 skrll }; 138 1.1 skrll 139 1.11 gutterid /* 140 1.11 gutterid * The HW actually supports more frequencies, but these are the standard ones. 141 1.11 gutterid * For the full list, see the definition of harmony_speeds below. 142 1.11 gutterid */ 143 1.6 isaki #define HARMONY_FORMAT(enc, prec) \ 144 1.6 isaki { \ 145 1.6 isaki .mode = AUMODE_PLAY | AUMODE_RECORD, \ 146 1.6 isaki .encoding = (enc), \ 147 1.6 isaki .validbits = (prec), \ 148 1.6 isaki .precision = (prec), \ 149 1.6 isaki .channels = 2, \ 150 1.6 isaki .channel_mask = AUFMT_STEREO, \ 151 1.6 isaki .frequency_type = 4, \ 152 1.6 isaki .frequency = { 16000, 32000, 44100, 48000 }, \ 153 1.6 isaki } 154 1.6 isaki static struct audio_format harmony_formats[] = { 155 1.6 isaki HARMONY_FORMAT(AUDIO_ENCODING_ULAW, 8), 156 1.6 isaki HARMONY_FORMAT(AUDIO_ENCODING_ALAW, 8), 157 1.6 isaki HARMONY_FORMAT(AUDIO_ENCODING_SLINEAR_BE, 16), 158 1.6 isaki }; 159 1.6 isaki #define HARMONY_NFORMATS __arraycount(harmony_formats) 160 1.6 isaki 161 1.1 skrll int harmony_match(device_t, struct cfdata *, void *); 162 1.1 skrll void harmony_attach(device_t, device_t, void *); 163 1.1 skrll 164 1.1 skrll 165 1.1 skrll CFATTACH_DECL_NEW(harmony, sizeof(struct harmony_softc), 166 1.1 skrll harmony_match, harmony_attach, NULL, NULL); 167 1.1 skrll 168 1.1 skrll int harmony_intr(void *); 169 1.1 skrll void harmony_intr_enable(struct harmony_softc *); 170 1.1 skrll void harmony_intr_disable(struct harmony_softc *); 171 1.10 isaki uint32_t harmony_speed_bits(struct harmony_softc *, u_int); 172 1.1 skrll int harmony_set_gainctl(struct harmony_softc *); 173 1.1 skrll void harmony_reset_codec(struct harmony_softc *); 174 1.1 skrll void harmony_start_cp(struct harmony_softc *, int); 175 1.1 skrll void harmony_start_pp(struct harmony_softc *, int); 176 1.1 skrll void harmony_tick_pb(void *); 177 1.1 skrll void harmony_tick_cp(void *); 178 1.1 skrll void harmony_try_more(struct harmony_softc *, int, int, 179 1.1 skrll struct harmony_channel *); 180 1.1 skrll static void harmony_empty_input(struct harmony_softc *); 181 1.1 skrll static void harmony_empty_output(struct harmony_softc *); 182 1.1 skrll 183 1.1 skrll void harmony_acc_tmo(void *); 184 1.1 skrll #define ADD_CLKALLICA(sc) do { \ 185 1.1 skrll (sc)->sc_acc <<= 1; \ 186 1.1 skrll (sc)->sc_acc |= READ_REG((sc), HARMONY_DIAG) & DIAG_CO; \ 187 1.1 skrll if ((sc)->sc_acc_cnt++ && !((sc)->sc_acc_cnt % 32)) \ 188 1.1 skrll rnd_add_uint32(&(sc)->sc_rnd_source, \ 189 1.1 skrll (sc)->sc_acc_num ^= (sc)->sc_acc); \ 190 1.1 skrll } while(0) 191 1.1 skrll 192 1.1 skrll int 193 1.1 skrll harmony_match(device_t parent, struct cfdata *match, void *aux) 194 1.1 skrll { 195 1.1 skrll struct gsc_attach_args *ga; 196 1.1 skrll 197 1.1 skrll ga = aux; 198 1.1 skrll if (ga->ga_type.iodc_type == HPPA_TYPE_FIO) { 199 1.1 skrll if (ga->ga_type.iodc_sv_model == HPPA_FIO_A1 || 200 1.1 skrll ga->ga_type.iodc_sv_model == HPPA_FIO_A2NB || 201 1.1 skrll ga->ga_type.iodc_sv_model == HPPA_FIO_A1NB || 202 1.1 skrll ga->ga_type.iodc_sv_model == HPPA_FIO_A2) 203 1.1 skrll return 1; 204 1.1 skrll } 205 1.1 skrll return 0; 206 1.1 skrll } 207 1.1 skrll 208 1.1 skrll void 209 1.1 skrll harmony_attach(device_t parent, device_t self, void *aux) 210 1.1 skrll { 211 1.1 skrll struct harmony_softc *sc = device_private(self); 212 1.1 skrll struct gsc_attach_args *ga; 213 1.1 skrll uint8_t rev; 214 1.1 skrll uint32_t cntl; 215 1.1 skrll int i; 216 1.1 skrll 217 1.1 skrll sc->sc_dv = self; 218 1.1 skrll ga = aux; 219 1.1 skrll sc->sc_bt = ga->ga_iot; 220 1.1 skrll sc->sc_dmat = ga->ga_dmatag; 221 1.1 skrll 222 1.1 skrll mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 223 1.1 skrll mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO); 224 1.1 skrll 225 1.1 skrll if (bus_space_map(sc->sc_bt, ga->ga_hpa, HARMONY_NREGS, 0, 226 1.1 skrll &sc->sc_bh) != 0) { 227 1.1 skrll aprint_error(": couldn't map registers\n"); 228 1.1 skrll return; 229 1.1 skrll } 230 1.1 skrll 231 1.1 skrll cntl = READ_REG(sc, HARMONY_ID); 232 1.1 skrll switch ((cntl & ID_REV_MASK)) { 233 1.1 skrll case ID_REV_TS: 234 1.1 skrll sc->sc_teleshare = 1; 235 1.1 skrll case ID_REV_NOTS: 236 1.1 skrll break; 237 1.1 skrll default: 238 1.1 skrll aprint_error(": unknown id == 0x%02x\n", 239 1.1 skrll (cntl & ID_REV_MASK) >> ID_REV_SHIFT); 240 1.1 skrll bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS); 241 1.1 skrll return; 242 1.1 skrll } 243 1.1 skrll 244 1.1 skrll if (bus_dmamem_alloc(sc->sc_dmat, sizeof(struct harmony_empty), 245 1.1 skrll PAGE_SIZE, 0, &sc->sc_empty_seg, 1, &sc->sc_empty_rseg, 246 1.1 skrll BUS_DMA_WAITOK) != 0) { 247 1.1 skrll aprint_error(": could not alloc DMA memory\n"); 248 1.1 skrll bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS); 249 1.1 skrll return; 250 1.1 skrll } 251 1.1 skrll if (bus_dmamem_map(sc->sc_dmat, &sc->sc_empty_seg, 1, 252 1.1 skrll sizeof(struct harmony_empty), (void **)&sc->sc_empty_kva, 253 1.1 skrll BUS_DMA_WAITOK) != 0) { 254 1.1 skrll aprint_error(": couldn't map DMA memory\n"); 255 1.1 skrll bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg, 256 1.1 skrll sc->sc_empty_rseg); 257 1.1 skrll bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS); 258 1.1 skrll return; 259 1.1 skrll } 260 1.1 skrll if (bus_dmamap_create(sc->sc_dmat, sizeof(struct harmony_empty), 1, 261 1.1 skrll sizeof(struct harmony_empty), 0, BUS_DMA_WAITOK, 262 1.1 skrll &sc->sc_empty_map) != 0) { 263 1.1 skrll aprint_error(": can't create DMA map\n"); 264 1.1 skrll bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_empty_kva, 265 1.1 skrll sizeof(struct harmony_empty)); 266 1.1 skrll bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg, 267 1.1 skrll sc->sc_empty_rseg); 268 1.1 skrll bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS); 269 1.1 skrll return; 270 1.1 skrll } 271 1.1 skrll if (bus_dmamap_load(sc->sc_dmat, sc->sc_empty_map, sc->sc_empty_kva, 272 1.1 skrll sizeof(struct harmony_empty), NULL, BUS_DMA_WAITOK) != 0) { 273 1.1 skrll aprint_error(": can't load DMA map\n"); 274 1.1 skrll bus_dmamap_destroy(sc->sc_dmat, sc->sc_empty_map); 275 1.1 skrll bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_empty_kva, 276 1.1 skrll sizeof(struct harmony_empty)); 277 1.1 skrll bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg, 278 1.1 skrll sc->sc_empty_rseg); 279 1.1 skrll bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS); 280 1.1 skrll return; 281 1.1 skrll } 282 1.1 skrll 283 1.1 skrll sc->sc_playback_empty = 0; 284 1.1 skrll for (i = 0; i < PLAYBACK_EMPTYS; i++) 285 1.1 skrll sc->sc_playback_paddrs[i] = 286 1.1 skrll sc->sc_empty_map->dm_segs[0].ds_addr + 287 1.1 skrll offsetof(struct harmony_empty, playback[i][0]); 288 1.1 skrll 289 1.1 skrll sc->sc_capture_empty = 0; 290 1.1 skrll for (i = 0; i < CAPTURE_EMPTYS; i++) 291 1.1 skrll sc->sc_capture_paddrs[i] = 292 1.1 skrll sc->sc_empty_map->dm_segs[0].ds_addr + 293 1.1 skrll offsetof(struct harmony_empty, capture[i][0]); 294 1.1 skrll 295 1.1 skrll bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map, 296 1.1 skrll offsetof(struct harmony_empty, playback[0][0]), 297 1.1 skrll PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE); 298 1.1 skrll 299 1.1 skrll (void) hppa_intr_establish(IPL_AUDIO, harmony_intr, sc, ga->ga_ir, 300 1.1 skrll ga->ga_irq); 301 1.1 skrll 302 1.1 skrll /* set defaults */ 303 1.1 skrll sc->sc_in_port = HARMONY_IN_LINE; 304 1.1 skrll sc->sc_out_port = HARMONY_OUT_SPEAKER; 305 1.1 skrll sc->sc_input_lvl.left = sc->sc_input_lvl.right = 240; 306 1.1 skrll sc->sc_output_lvl.left = sc->sc_output_lvl.right = 244; 307 1.1 skrll sc->sc_monitor_lvl.left = sc->sc_monitor_lvl.right = 208; 308 1.1 skrll sc->sc_outputgain = 0; 309 1.1 skrll 310 1.1 skrll /* reset chip, and push default gain controls */ 311 1.1 skrll harmony_reset_codec(sc); 312 1.1 skrll 313 1.1 skrll cntl = READ_REG(sc, HARMONY_CNTL); 314 1.1 skrll rev = (cntl & CNTL_CODEC_REV_MASK) >> CNTL_CODEC_REV_SHIFT; 315 1.1 skrll aprint_normal(": rev %u", rev); 316 1.1 skrll 317 1.1 skrll if (sc->sc_teleshare) 318 1.1 skrll printf(", teleshare"); 319 1.1 skrll aprint_normal("\n"); 320 1.1 skrll 321 1.1 skrll strlcpy(sc->sc_audev.name, ga->ga_name, sizeof(sc->sc_audev.name)); 322 1.1 skrll snprintf(sc->sc_audev.version, sizeof sc->sc_audev.version, 323 1.1 skrll "%u.%u;%u", ga->ga_type.iodc_sv_rev, 324 1.1 skrll ga->ga_type.iodc_model, ga->ga_type.iodc_revision); 325 1.1 skrll strlcpy(sc->sc_audev.config, device_xname(sc->sc_dv), 326 1.1 skrll sizeof(sc->sc_audev.config)); 327 1.1 skrll 328 1.1 skrll audio_attach_mi(&harmony_sa_hw_if, sc, sc->sc_dv); 329 1.1 skrll 330 1.1 skrll rnd_attach_source(&sc->sc_rnd_source, device_xname(sc->sc_dv), 331 1.2 tls RND_TYPE_UNKNOWN, RND_FLAG_DEFAULT); 332 1.1 skrll 333 1.1 skrll callout_init(&sc->sc_acc_tmo, 0); 334 1.1 skrll callout_setfunc(&sc->sc_acc_tmo, harmony_acc_tmo, sc); 335 1.1 skrll sc->sc_acc_num = 0xa5a5a5a5; 336 1.1 skrll } 337 1.1 skrll 338 1.1 skrll void 339 1.1 skrll harmony_reset_codec(struct harmony_softc *sc) 340 1.1 skrll { 341 1.1 skrll 342 1.1 skrll /* silence */ 343 1.1 skrll WRITE_REG(sc, HARMONY_GAINCTL, GAINCTL_OUTPUT_LEFT_M | 344 1.1 skrll GAINCTL_OUTPUT_RIGHT_M | GAINCTL_MONITOR_M); 345 1.1 skrll 346 1.1 skrll /* start reset */ 347 1.1 skrll WRITE_REG(sc, HARMONY_RESET, RESET_RST); 348 1.1 skrll 349 1.11 gutterid DELAY(100000); /* wait at least 0.1 sec */ 350 1.1 skrll 351 1.1 skrll harmony_set_gainctl(sc); 352 1.1 skrll WRITE_REG(sc, HARMONY_RESET, 0); 353 1.1 skrll } 354 1.1 skrll 355 1.1 skrll void 356 1.1 skrll harmony_acc_tmo(void *v) 357 1.1 skrll { 358 1.1 skrll struct harmony_softc *sc; 359 1.1 skrll 360 1.1 skrll sc = v; 361 1.1 skrll ADD_CLKALLICA(sc); 362 1.1 skrll callout_schedule(&sc->sc_acc_tmo, 1); 363 1.1 skrll } 364 1.1 skrll 365 1.1 skrll /* 366 1.1 skrll * interrupt handler 367 1.1 skrll */ 368 1.1 skrll int 369 1.1 skrll harmony_intr(void *vsc) 370 1.1 skrll { 371 1.1 skrll struct harmony_softc *sc; 372 1.1 skrll uint32_t dstatus; 373 1.1 skrll int r; 374 1.1 skrll 375 1.1 skrll sc = vsc; 376 1.1 skrll r = 0; 377 1.1 skrll ADD_CLKALLICA(sc); 378 1.1 skrll 379 1.1 skrll mutex_spin_enter(&sc->sc_intr_lock); 380 1.1 skrll 381 1.1 skrll harmony_intr_disable(sc); 382 1.1 skrll 383 1.1 skrll dstatus = READ_REG(sc, HARMONY_DSTATUS); 384 1.1 skrll 385 1.1 skrll if (dstatus & DSTATUS_PN) { 386 1.1 skrll r = 1; 387 1.1 skrll harmony_start_pp(sc, 0); 388 1.1 skrll } 389 1.1 skrll 390 1.1 skrll if (dstatus & DSTATUS_RN) { 391 1.1 skrll r = 1; 392 1.1 skrll harmony_start_cp(sc, 0); 393 1.1 skrll } 394 1.1 skrll 395 1.1 skrll if (READ_REG(sc, HARMONY_OV) & OV_OV) { 396 1.1 skrll sc->sc_ov = 1; 397 1.1 skrll WRITE_REG(sc, HARMONY_OV, 0); 398 1.1 skrll } else 399 1.1 skrll sc->sc_ov = 0; 400 1.1 skrll 401 1.1 skrll harmony_intr_enable(sc); 402 1.1 skrll 403 1.1 skrll mutex_spin_exit(&sc->sc_intr_lock); 404 1.1 skrll 405 1.1 skrll return r; 406 1.1 skrll } 407 1.1 skrll 408 1.1 skrll void 409 1.1 skrll harmony_intr_enable(struct harmony_softc *sc) 410 1.1 skrll { 411 1.1 skrll 412 1.1 skrll WRITE_REG(sc, HARMONY_DSTATUS, DSTATUS_IE); 413 1.1 skrll SYNC_REG(sc, HARMONY_DSTATUS, BUS_SPACE_BARRIER_WRITE); 414 1.1 skrll } 415 1.1 skrll 416 1.1 skrll void 417 1.1 skrll harmony_intr_disable(struct harmony_softc *sc) 418 1.1 skrll { 419 1.1 skrll 420 1.1 skrll WRITE_REG(sc, HARMONY_DSTATUS, 0); 421 1.1 skrll SYNC_REG(sc, HARMONY_DSTATUS, BUS_SPACE_BARRIER_WRITE); 422 1.1 skrll } 423 1.1 skrll 424 1.1 skrll void 425 1.1 skrll harmony_close(void *vsc) 426 1.1 skrll { 427 1.1 skrll struct harmony_softc *sc; 428 1.1 skrll 429 1.1 skrll sc = vsc; 430 1.1 skrll harmony_intr_disable(sc); 431 1.1 skrll } 432 1.1 skrll 433 1.1 skrll int 434 1.6 isaki harmony_query_format(void *vsc, audio_format_query_t *afp) 435 1.1 skrll { 436 1.1 skrll 437 1.6 isaki return audio_query_format(harmony_formats, HARMONY_NFORMATS, afp); 438 1.1 skrll } 439 1.1 skrll 440 1.1 skrll int 441 1.6 isaki harmony_set_format(void *vsc, int setmode, 442 1.6 isaki const audio_params_t *play, const audio_params_t *rec, 443 1.9 isaki audio_filter_reg_t *pfil, audio_filter_reg_t *rfil) 444 1.1 skrll { 445 1.1 skrll struct harmony_softc *sc; 446 1.1 skrll uint32_t bits; 447 1.1 skrll 448 1.1 skrll sc = vsc; 449 1.6 isaki 450 1.6 isaki /* *play and *rec are the identical because !AUDIO_PROP_INDEPENDENT. */ 451 1.6 isaki switch (play->encoding) { 452 1.1 skrll case AUDIO_ENCODING_ULAW: 453 1.1 skrll bits = CNTL_FORMAT_ULAW; 454 1.1 skrll break; 455 1.1 skrll case AUDIO_ENCODING_ALAW: 456 1.1 skrll bits = CNTL_FORMAT_ALAW; 457 1.1 skrll break; 458 1.1 skrll case AUDIO_ENCODING_SLINEAR_BE: 459 1.6 isaki bits = CNTL_FORMAT_SLINEAR16BE; 460 1.6 isaki break; 461 1.1 skrll default: 462 1.1 skrll return EINVAL; 463 1.1 skrll } 464 1.1 skrll 465 1.1 skrll if (sc->sc_outputgain) 466 1.1 skrll bits |= CNTL_OLB; 467 1.1 skrll 468 1.6 isaki bits |= CNTL_CHANS_STEREO; 469 1.10 isaki bits |= harmony_speed_bits(sc, play->sample_rate); 470 1.9 isaki sc->sc_cntlbits = bits; 471 1.1 skrll sc->sc_need_commit = 1; 472 1.1 skrll 473 1.1 skrll return 0; 474 1.1 skrll } 475 1.1 skrll 476 1.1 skrll int 477 1.1 skrll harmony_round_blocksize(void *vsc, int blk, 478 1.1 skrll int mode, const audio_params_t *param) 479 1.1 skrll { 480 1.1 skrll 481 1.1 skrll return HARMONY_BUFSIZE; 482 1.1 skrll } 483 1.1 skrll 484 1.1 skrll int 485 1.1 skrll harmony_control_wait(struct harmony_softc *sc) 486 1.1 skrll { 487 1.1 skrll uint32_t reg; 488 1.1 skrll int j = 0; 489 1.1 skrll 490 1.1 skrll while (j < 10) { 491 1.1 skrll /* Wait for it to come out of control mode */ 492 1.1 skrll reg = READ_REG(sc, HARMONY_CNTL); 493 1.1 skrll if ((reg & CNTL_C) == 0) 494 1.1 skrll return 0; 495 1.1 skrll DELAY(50000); /* wait 0.05 */ 496 1.1 skrll j++; 497 1.1 skrll } 498 1.1 skrll 499 1.1 skrll return 1; 500 1.1 skrll } 501 1.1 skrll 502 1.1 skrll int 503 1.1 skrll harmony_commit_settings(void *vsc) 504 1.1 skrll { 505 1.1 skrll struct harmony_softc *sc; 506 1.1 skrll uint32_t reg; 507 1.1 skrll uint8_t quietchar; 508 1.1 skrll int i; 509 1.1 skrll 510 1.1 skrll sc = vsc; 511 1.1 skrll if (sc->sc_need_commit == 0) 512 1.1 skrll return 0; 513 1.1 skrll 514 1.1 skrll harmony_intr_disable(sc); 515 1.1 skrll 516 1.1 skrll for (;;) { 517 1.1 skrll reg = READ_REG(sc, HARMONY_DSTATUS); 518 1.1 skrll if ((reg & (DSTATUS_PC | DSTATUS_RC)) == 0) 519 1.1 skrll break; 520 1.1 skrll } 521 1.1 skrll 522 1.1 skrll /* Setting some bits in gainctl requires a reset */ 523 1.1 skrll harmony_reset_codec(sc); 524 1.1 skrll 525 1.1 skrll /* set the silence character based on the encoding type */ 526 1.1 skrll bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map, 527 1.1 skrll offsetof(struct harmony_empty, playback[0][0]), 528 1.1 skrll PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_POSTWRITE); 529 1.1 skrll switch (sc->sc_cntlbits & CNTL_FORMAT_MASK) { 530 1.1 skrll case CNTL_FORMAT_ULAW: 531 1.1 skrll quietchar = 0x7f; 532 1.1 skrll break; 533 1.1 skrll case CNTL_FORMAT_ALAW: 534 1.1 skrll quietchar = 0x55; 535 1.1 skrll break; 536 1.1 skrll case CNTL_FORMAT_SLINEAR16BE: 537 1.1 skrll case CNTL_FORMAT_ULINEAR8: 538 1.1 skrll default: 539 1.1 skrll quietchar = 0; 540 1.1 skrll break; 541 1.1 skrll } 542 1.1 skrll for (i = 0; i < PLAYBACK_EMPTYS; i++) 543 1.1 skrll memset(&sc->sc_empty_kva->playback[i][0], 544 1.1 skrll quietchar, HARMONY_BUFSIZE); 545 1.1 skrll bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map, 546 1.1 skrll offsetof(struct harmony_empty, playback[0][0]), 547 1.1 skrll PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE); 548 1.1 skrll 549 1.1 skrll harmony_control_wait(sc); 550 1.1 skrll 551 1.1 skrll bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_CNTL, 552 1.1 skrll sc->sc_cntlbits | CNTL_C); 553 1.1 skrll 554 1.1 skrll harmony_control_wait(sc); 555 1.1 skrll 556 1.1 skrll sc->sc_need_commit = 0; 557 1.1 skrll 558 1.1 skrll if (sc->sc_playing || sc->sc_capturing) 559 1.1 skrll harmony_intr_enable(sc); 560 1.1 skrll 561 1.1 skrll return 0; 562 1.1 skrll } 563 1.1 skrll 564 1.1 skrll static void 565 1.1 skrll harmony_empty_output(struct harmony_softc *sc) 566 1.1 skrll { 567 1.1 skrll 568 1.1 skrll WRITE_REG(sc, HARMONY_PNXTADD, 569 1.1 skrll sc->sc_playback_paddrs[sc->sc_playback_empty]); 570 1.1 skrll SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE); 571 1.1 skrll 572 1.1 skrll if (++sc->sc_playback_empty == PLAYBACK_EMPTYS) 573 1.1 skrll sc->sc_playback_empty = 0; 574 1.1 skrll } 575 1.1 skrll 576 1.1 skrll int 577 1.1 skrll harmony_halt_output(void *vsc) 578 1.1 skrll { 579 1.1 skrll struct harmony_softc *sc; 580 1.1 skrll 581 1.1 skrll sc = vsc; 582 1.1 skrll sc->sc_playing = 0; 583 1.1 skrll 584 1.1 skrll harmony_empty_output(sc); 585 1.1 skrll return 0; 586 1.1 skrll } 587 1.1 skrll 588 1.1 skrll static void 589 1.1 skrll harmony_empty_input(struct harmony_softc *sc) 590 1.1 skrll { 591 1.1 skrll 592 1.1 skrll WRITE_REG(sc, HARMONY_RNXTADD, 593 1.1 skrll sc->sc_capture_paddrs[sc->sc_capture_empty]); 594 1.1 skrll SYNC_REG(sc, HARMONY_RNXTADD, BUS_SPACE_BARRIER_WRITE); 595 1.1 skrll 596 1.1 skrll if (++sc->sc_capture_empty == CAPTURE_EMPTYS) 597 1.1 skrll sc->sc_capture_empty = 0; 598 1.1 skrll } 599 1.1 skrll 600 1.1 skrll int 601 1.1 skrll harmony_halt_input(void *vsc) 602 1.1 skrll { 603 1.1 skrll struct harmony_softc *sc; 604 1.1 skrll 605 1.1 skrll sc = vsc; 606 1.1 skrll sc->sc_capturing = 0; 607 1.1 skrll 608 1.1 skrll harmony_empty_input(sc); 609 1.1 skrll return 0; 610 1.1 skrll } 611 1.1 skrll 612 1.1 skrll int 613 1.1 skrll harmony_getdev(void *vsc, struct audio_device *retp) 614 1.1 skrll { 615 1.1 skrll struct harmony_softc *sc; 616 1.1 skrll 617 1.1 skrll sc = vsc; 618 1.1 skrll *retp = sc->sc_audev; 619 1.1 skrll return 0; 620 1.1 skrll } 621 1.1 skrll 622 1.1 skrll int 623 1.1 skrll harmony_set_port(void *vsc, mixer_ctrl_t *cp) 624 1.1 skrll { 625 1.1 skrll struct harmony_softc *sc; 626 1.1 skrll int err; 627 1.1 skrll 628 1.1 skrll sc = vsc; 629 1.1 skrll err = EINVAL; 630 1.1 skrll switch (cp->dev) { 631 1.1 skrll case HARMONY_PORT_INPUT_LVL: 632 1.1 skrll if (cp->type != AUDIO_MIXER_VALUE) 633 1.1 skrll break; 634 1.1 skrll if (cp->un.value.num_channels == 1) 635 1.1 skrll sc->sc_input_lvl.left = sc->sc_input_lvl.right = 636 1.1 skrll cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 637 1.1 skrll else if (cp->un.value.num_channels == 2) { 638 1.1 skrll sc->sc_input_lvl.left = 639 1.1 skrll cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 640 1.1 skrll sc->sc_input_lvl.right = 641 1.1 skrll cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 642 1.1 skrll } else 643 1.1 skrll break; 644 1.1 skrll sc->sc_need_commit = 1; 645 1.1 skrll err = 0; 646 1.1 skrll break; 647 1.1 skrll case HARMONY_PORT_OUTPUT_LVL: 648 1.1 skrll if (cp->type != AUDIO_MIXER_VALUE) 649 1.1 skrll break; 650 1.1 skrll if (cp->un.value.num_channels == 1) 651 1.1 skrll sc->sc_output_lvl.left = sc->sc_output_lvl.right = 652 1.1 skrll cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 653 1.1 skrll else if (cp->un.value.num_channels == 2) { 654 1.1 skrll sc->sc_output_lvl.left = 655 1.1 skrll cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 656 1.1 skrll sc->sc_output_lvl.right = 657 1.1 skrll cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 658 1.1 skrll } else 659 1.1 skrll break; 660 1.1 skrll sc->sc_need_commit = 1; 661 1.1 skrll err = 0; 662 1.1 skrll break; 663 1.1 skrll case HARMONY_PORT_OUTPUT_GAIN: 664 1.1 skrll if (cp->type != AUDIO_MIXER_ENUM) 665 1.1 skrll break; 666 1.1 skrll sc->sc_outputgain = cp->un.ord ? 1 : 0; 667 1.1 skrll err = 0; 668 1.1 skrll break; 669 1.1 skrll case HARMONY_PORT_MONITOR_LVL: 670 1.1 skrll if (cp->type != AUDIO_MIXER_VALUE) 671 1.1 skrll break; 672 1.1 skrll if (cp->un.value.num_channels != 1) 673 1.1 skrll break; 674 1.1 skrll sc->sc_monitor_lvl.left = sc->sc_input_lvl.right = 675 1.1 skrll cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 676 1.1 skrll sc->sc_need_commit = 1; 677 1.1 skrll err = 0; 678 1.1 skrll break; 679 1.1 skrll case HARMONY_PORT_RECORD_SOURCE: 680 1.1 skrll if (cp->type != AUDIO_MIXER_ENUM) 681 1.1 skrll break; 682 1.1 skrll if (cp->un.ord != HARMONY_IN_LINE && 683 1.1 skrll cp->un.ord != HARMONY_IN_MIC) 684 1.1 skrll break; 685 1.1 skrll sc->sc_in_port = cp->un.ord; 686 1.1 skrll err = 0; 687 1.1 skrll sc->sc_need_commit = 1; 688 1.1 skrll break; 689 1.1 skrll case HARMONY_PORT_OUTPUT_SOURCE: 690 1.1 skrll if (cp->type != AUDIO_MIXER_ENUM) 691 1.1 skrll break; 692 1.1 skrll if (cp->un.ord != HARMONY_OUT_LINE && 693 1.1 skrll cp->un.ord != HARMONY_OUT_SPEAKER && 694 1.1 skrll cp->un.ord != HARMONY_OUT_HEADPHONE) 695 1.1 skrll break; 696 1.1 skrll sc->sc_out_port = cp->un.ord; 697 1.1 skrll err = 0; 698 1.1 skrll sc->sc_need_commit = 1; 699 1.1 skrll break; 700 1.1 skrll } 701 1.1 skrll 702 1.1 skrll return err; 703 1.1 skrll } 704 1.1 skrll 705 1.1 skrll int 706 1.1 skrll harmony_get_port(void *vsc, mixer_ctrl_t *cp) 707 1.1 skrll { 708 1.1 skrll struct harmony_softc *sc; 709 1.1 skrll int err; 710 1.1 skrll 711 1.1 skrll sc = vsc; 712 1.1 skrll err = EINVAL; 713 1.1 skrll switch (cp->dev) { 714 1.1 skrll case HARMONY_PORT_INPUT_LVL: 715 1.1 skrll if (cp->type != AUDIO_MIXER_VALUE) 716 1.1 skrll break; 717 1.1 skrll if (cp->un.value.num_channels == 1) { 718 1.1 skrll cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = 719 1.1 skrll sc->sc_input_lvl.left; 720 1.1 skrll } else if (cp->un.value.num_channels == 2) { 721 1.1 skrll cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 722 1.1 skrll sc->sc_input_lvl.left; 723 1.1 skrll cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 724 1.1 skrll sc->sc_input_lvl.right; 725 1.1 skrll } else 726 1.1 skrll break; 727 1.1 skrll err = 0; 728 1.1 skrll break; 729 1.1 skrll case HARMONY_PORT_INPUT_OV: 730 1.1 skrll if (cp->type != AUDIO_MIXER_ENUM) 731 1.1 skrll break; 732 1.1 skrll cp->un.ord = sc->sc_ov ? 1 : 0; 733 1.1 skrll err = 0; 734 1.1 skrll break; 735 1.1 skrll case HARMONY_PORT_OUTPUT_LVL: 736 1.1 skrll if (cp->type != AUDIO_MIXER_VALUE) 737 1.1 skrll break; 738 1.1 skrll if (cp->un.value.num_channels == 1) { 739 1.1 skrll cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = 740 1.1 skrll sc->sc_output_lvl.left; 741 1.1 skrll } else if (cp->un.value.num_channels == 2) { 742 1.1 skrll cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 743 1.1 skrll sc->sc_output_lvl.left; 744 1.1 skrll cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 745 1.1 skrll sc->sc_output_lvl.right; 746 1.1 skrll } else 747 1.1 skrll break; 748 1.1 skrll err = 0; 749 1.1 skrll break; 750 1.1 skrll case HARMONY_PORT_OUTPUT_GAIN: 751 1.1 skrll if (cp->type != AUDIO_MIXER_ENUM) 752 1.1 skrll break; 753 1.1 skrll cp->un.ord = sc->sc_outputgain ? 1 : 0; 754 1.1 skrll err = 0; 755 1.1 skrll break; 756 1.1 skrll case HARMONY_PORT_MONITOR_LVL: 757 1.1 skrll if (cp->type != AUDIO_MIXER_VALUE) 758 1.1 skrll break; 759 1.1 skrll if (cp->un.value.num_channels != 1) 760 1.1 skrll break; 761 1.1 skrll cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = 762 1.1 skrll sc->sc_monitor_lvl.left; 763 1.1 skrll err = 0; 764 1.1 skrll break; 765 1.1 skrll case HARMONY_PORT_RECORD_SOURCE: 766 1.1 skrll if (cp->type != AUDIO_MIXER_ENUM) 767 1.1 skrll break; 768 1.1 skrll cp->un.ord = sc->sc_in_port; 769 1.1 skrll err = 0; 770 1.1 skrll break; 771 1.1 skrll case HARMONY_PORT_OUTPUT_SOURCE: 772 1.1 skrll if (cp->type != AUDIO_MIXER_ENUM) 773 1.1 skrll break; 774 1.1 skrll cp->un.ord = sc->sc_out_port; 775 1.1 skrll err = 0; 776 1.1 skrll break; 777 1.1 skrll } 778 1.1 skrll return err; 779 1.1 skrll } 780 1.1 skrll 781 1.1 skrll int 782 1.1 skrll harmony_query_devinfo(void *vsc, mixer_devinfo_t *dip) 783 1.1 skrll { 784 1.1 skrll int err; 785 1.1 skrll 786 1.1 skrll err = 0; 787 1.1 skrll switch (dip->index) { 788 1.1 skrll case HARMONY_PORT_INPUT_LVL: 789 1.1 skrll dip->type = AUDIO_MIXER_VALUE; 790 1.1 skrll dip->mixer_class = HARMONY_PORT_INPUT_CLASS; 791 1.1 skrll dip->prev = dip->next = AUDIO_MIXER_LAST; 792 1.1 skrll strlcpy(dip->label.name, AudioNinput, sizeof dip->label.name); 793 1.1 skrll dip->un.v.num_channels = 2; 794 1.1 skrll strlcpy(dip->un.v.units.name, AudioNvolume, 795 1.1 skrll sizeof dip->un.v.units.name); 796 1.1 skrll break; 797 1.1 skrll case HARMONY_PORT_INPUT_OV: 798 1.1 skrll dip->type = AUDIO_MIXER_ENUM; 799 1.1 skrll dip->mixer_class = HARMONY_PORT_INPUT_CLASS; 800 1.1 skrll dip->prev = dip->next = AUDIO_MIXER_LAST; 801 1.1 skrll strlcpy(dip->label.name, "overrange", sizeof dip->label.name); 802 1.1 skrll dip->un.e.num_mem = 2; 803 1.1 skrll strlcpy(dip->un.e.member[0].label.name, AudioNoff, 804 1.1 skrll sizeof dip->un.e.member[0].label.name); 805 1.1 skrll dip->un.e.member[0].ord = 0; 806 1.1 skrll strlcpy(dip->un.e.member[1].label.name, AudioNon, 807 1.1 skrll sizeof dip->un.e.member[1].label.name); 808 1.1 skrll dip->un.e.member[1].ord = 1; 809 1.1 skrll break; 810 1.1 skrll case HARMONY_PORT_OUTPUT_LVL: 811 1.1 skrll dip->type = AUDIO_MIXER_VALUE; 812 1.1 skrll dip->mixer_class = HARMONY_PORT_OUTPUT_CLASS; 813 1.1 skrll dip->prev = dip->next = AUDIO_MIXER_LAST; 814 1.1 skrll strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name); 815 1.1 skrll dip->un.v.num_channels = 2; 816 1.1 skrll strlcpy(dip->un.v.units.name, AudioNvolume, 817 1.1 skrll sizeof dip->un.v.units.name); 818 1.1 skrll break; 819 1.1 skrll case HARMONY_PORT_OUTPUT_GAIN: 820 1.1 skrll dip->type = AUDIO_MIXER_ENUM; 821 1.1 skrll dip->mixer_class = HARMONY_PORT_OUTPUT_CLASS; 822 1.1 skrll dip->prev = dip->next = AUDIO_MIXER_LAST; 823 1.1 skrll strlcpy(dip->label.name, "gain", sizeof dip->label.name); 824 1.1 skrll dip->un.e.num_mem = 2; 825 1.1 skrll strlcpy(dip->un.e.member[0].label.name, AudioNoff, 826 1.1 skrll sizeof dip->un.e.member[0].label.name); 827 1.1 skrll dip->un.e.member[0].ord = 0; 828 1.1 skrll strlcpy(dip->un.e.member[1].label.name, AudioNon, 829 1.1 skrll sizeof dip->un.e.member[1].label.name); 830 1.1 skrll dip->un.e.member[1].ord = 1; 831 1.1 skrll break; 832 1.1 skrll case HARMONY_PORT_MONITOR_LVL: 833 1.1 skrll dip->type = AUDIO_MIXER_VALUE; 834 1.1 skrll dip->mixer_class = HARMONY_PORT_MONITOR_CLASS; 835 1.1 skrll dip->prev = dip->next = AUDIO_MIXER_LAST; 836 1.1 skrll strlcpy(dip->label.name, AudioNmonitor, sizeof dip->label.name); 837 1.1 skrll dip->un.v.num_channels = 1; 838 1.1 skrll strlcpy(dip->un.v.units.name, AudioNvolume, 839 1.1 skrll sizeof dip->un.v.units.name); 840 1.1 skrll break; 841 1.1 skrll case HARMONY_PORT_RECORD_SOURCE: 842 1.1 skrll dip->type = AUDIO_MIXER_ENUM; 843 1.1 skrll dip->mixer_class = HARMONY_PORT_RECORD_CLASS; 844 1.1 skrll dip->prev = dip->next = AUDIO_MIXER_LAST; 845 1.1 skrll strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name); 846 1.1 skrll dip->un.e.num_mem = 2; 847 1.1 skrll strlcpy(dip->un.e.member[0].label.name, AudioNmicrophone, 848 1.1 skrll sizeof dip->un.e.member[0].label.name); 849 1.1 skrll dip->un.e.member[0].ord = HARMONY_IN_MIC; 850 1.1 skrll strlcpy(dip->un.e.member[1].label.name, AudioNline, 851 1.1 skrll sizeof dip->un.e.member[1].label.name); 852 1.1 skrll dip->un.e.member[1].ord = HARMONY_IN_LINE; 853 1.1 skrll break; 854 1.1 skrll case HARMONY_PORT_OUTPUT_SOURCE: 855 1.1 skrll dip->type = AUDIO_MIXER_ENUM; 856 1.1 skrll dip->mixer_class = HARMONY_PORT_MONITOR_CLASS; 857 1.1 skrll dip->prev = dip->next = AUDIO_MIXER_LAST; 858 1.1 skrll strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name); 859 1.1 skrll dip->un.e.num_mem = 3; 860 1.1 skrll strlcpy(dip->un.e.member[0].label.name, AudioNline, 861 1.1 skrll sizeof dip->un.e.member[0].label.name); 862 1.1 skrll dip->un.e.member[0].ord = HARMONY_OUT_LINE; 863 1.1 skrll strlcpy(dip->un.e.member[1].label.name, AudioNspeaker, 864 1.1 skrll sizeof dip->un.e.member[1].label.name); 865 1.1 skrll dip->un.e.member[1].ord = HARMONY_OUT_SPEAKER; 866 1.1 skrll strlcpy(dip->un.e.member[2].label.name, AudioNheadphone, 867 1.1 skrll sizeof dip->un.e.member[2].label.name); 868 1.1 skrll dip->un.e.member[2].ord = HARMONY_OUT_HEADPHONE; 869 1.1 skrll break; 870 1.1 skrll case HARMONY_PORT_INPUT_CLASS: 871 1.1 skrll dip->type = AUDIO_MIXER_CLASS; 872 1.1 skrll dip->mixer_class = HARMONY_PORT_INPUT_CLASS; 873 1.1 skrll dip->prev = dip->next = AUDIO_MIXER_LAST; 874 1.1 skrll strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name); 875 1.1 skrll break; 876 1.1 skrll case HARMONY_PORT_OUTPUT_CLASS: 877 1.1 skrll dip->type = AUDIO_MIXER_CLASS; 878 1.1 skrll dip->mixer_class = HARMONY_PORT_INPUT_CLASS; 879 1.1 skrll dip->prev = dip->next = AUDIO_MIXER_LAST; 880 1.1 skrll strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name); 881 1.1 skrll break; 882 1.1 skrll case HARMONY_PORT_MONITOR_CLASS: 883 1.1 skrll dip->type = AUDIO_MIXER_CLASS; 884 1.1 skrll dip->mixer_class = HARMONY_PORT_INPUT_CLASS; 885 1.1 skrll dip->prev = dip->next = AUDIO_MIXER_LAST; 886 1.1 skrll strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name); 887 1.1 skrll break; 888 1.1 skrll case HARMONY_PORT_RECORD_CLASS: 889 1.1 skrll dip->type = AUDIO_MIXER_CLASS; 890 1.1 skrll dip->mixer_class = HARMONY_PORT_RECORD_CLASS; 891 1.1 skrll dip->prev = dip->next = AUDIO_MIXER_LAST; 892 1.1 skrll strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name); 893 1.1 skrll break; 894 1.1 skrll default: 895 1.1 skrll err = ENXIO; 896 1.1 skrll break; 897 1.1 skrll } 898 1.1 skrll 899 1.1 skrll return err; 900 1.1 skrll } 901 1.1 skrll 902 1.1 skrll void * 903 1.1 skrll harmony_allocm(void *vsc, int dir, size_t size) 904 1.1 skrll { 905 1.1 skrll struct harmony_softc *sc; 906 1.1 skrll struct harmony_dma *d; 907 1.1 skrll int rseg; 908 1.1 skrll 909 1.1 skrll sc = vsc; 910 1.1 skrll d = kmem_alloc(sizeof(*d), KM_SLEEP); 911 1.1 skrll 912 1.1 skrll if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, BUS_DMA_WAITOK, 913 1.1 skrll &d->d_map) != 0) 914 1.1 skrll goto fail1; 915 1.1 skrll 916 1.1 skrll if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &d->d_seg, 1, 917 1.1 skrll &rseg, BUS_DMA_WAITOK) != 0) 918 1.1 skrll goto fail2; 919 1.1 skrll 920 1.1 skrll if (bus_dmamem_map(sc->sc_dmat, &d->d_seg, 1, size, &d->d_kva, 921 1.1 skrll BUS_DMA_WAITOK) != 0) 922 1.1 skrll goto fail3; 923 1.1 skrll 924 1.1 skrll if (bus_dmamap_load(sc->sc_dmat, d->d_map, d->d_kva, size, NULL, 925 1.1 skrll BUS_DMA_WAITOK) != 0) 926 1.1 skrll goto fail4; 927 1.1 skrll 928 1.1 skrll d->d_next = sc->sc_dmas; 929 1.1 skrll sc->sc_dmas = d; 930 1.1 skrll d->d_size = size; 931 1.1 skrll return (d->d_kva); 932 1.1 skrll 933 1.1 skrll fail4: 934 1.1 skrll bus_dmamem_unmap(sc->sc_dmat, d->d_kva, size); 935 1.1 skrll fail3: 936 1.1 skrll bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1); 937 1.1 skrll fail2: 938 1.1 skrll bus_dmamap_destroy(sc->sc_dmat, d->d_map); 939 1.1 skrll fail1: 940 1.1 skrll kmem_free(d, sizeof(*d)); 941 1.1 skrll return (NULL); 942 1.1 skrll } 943 1.1 skrll 944 1.1 skrll void 945 1.1 skrll harmony_freem(void *vsc, void *ptr, size_t size) 946 1.1 skrll { 947 1.1 skrll struct harmony_softc *sc; 948 1.1 skrll struct harmony_dma *d, **dd; 949 1.1 skrll 950 1.1 skrll sc = vsc; 951 1.1 skrll for (dd = &sc->sc_dmas; (d = *dd) != NULL; dd = &(*dd)->d_next) { 952 1.1 skrll if (d->d_kva != ptr) 953 1.1 skrll continue; 954 1.1 skrll bus_dmamap_unload(sc->sc_dmat, d->d_map); 955 1.1 skrll bus_dmamem_unmap(sc->sc_dmat, d->d_kva, d->d_size); 956 1.1 skrll bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1); 957 1.1 skrll bus_dmamap_destroy(sc->sc_dmat, d->d_map); 958 1.1 skrll kmem_free(d, sizeof(*d)); 959 1.1 skrll return; 960 1.1 skrll } 961 1.1 skrll printf("%s: free rogue pointer\n", device_xname(sc->sc_dv)); 962 1.1 skrll } 963 1.1 skrll 964 1.1 skrll size_t 965 1.1 skrll harmony_round_buffersize(void *vsc, int direction, size_t size) 966 1.1 skrll { 967 1.1 skrll 968 1.1 skrll return ((size + HARMONY_BUFSIZE - 1) & (size_t)(-HARMONY_BUFSIZE)); 969 1.1 skrll } 970 1.1 skrll 971 1.1 skrll int 972 1.1 skrll harmony_get_props(void *vsc) 973 1.1 skrll { 974 1.1 skrll 975 1.7 isaki return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE | 976 1.7 isaki AUDIO_PROP_FULLDUPLEX; 977 1.1 skrll } 978 1.1 skrll 979 1.1 skrll void 980 1.1 skrll harmony_get_locks(void *vsc, kmutex_t **intr, kmutex_t **thread) 981 1.1 skrll { 982 1.1 skrll struct harmony_softc *sc; 983 1.1 skrll 984 1.1 skrll sc = vsc; 985 1.1 skrll *intr = &sc->sc_intr_lock; 986 1.1 skrll *thread = &sc->sc_lock; 987 1.1 skrll } 988 1.1 skrll 989 1.1 skrll int 990 1.1 skrll harmony_trigger_output(void *vsc, void *start, void *end, int blksize, 991 1.1 skrll void (*intr)(void *), void *intrarg, const audio_params_t *param) 992 1.1 skrll { 993 1.1 skrll struct harmony_softc *sc; 994 1.1 skrll struct harmony_channel *c; 995 1.1 skrll struct harmony_dma *d; 996 1.1 skrll 997 1.1 skrll sc = vsc; 998 1.1 skrll c = &sc->sc_playback; 999 1.1 skrll for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next) 1000 1.1 skrll continue; 1001 1.1 skrll if (d == NULL) { 1002 1.1 skrll printf("%s: trigger_output: bad addr: %p\n", 1003 1.1 skrll device_xname(sc->sc_dv), start); 1004 1.1 skrll return EINVAL; 1005 1.1 skrll } 1006 1.1 skrll 1007 1.1 skrll c->c_intr = intr; 1008 1.1 skrll c->c_intrarg = intrarg; 1009 1.1 skrll c->c_blksz = blksize; 1010 1.1 skrll c->c_current = d; 1011 1.1 skrll c->c_segsz = (char *)end - (char *)start; 1012 1.1 skrll c->c_cnt = 0; 1013 1.1 skrll c->c_lastaddr = d->d_map->dm_segs[0].ds_addr; 1014 1.1 skrll 1015 1.1 skrll sc->sc_playing = 1; 1016 1.1 skrll 1017 1.1 skrll harmony_start_pp(sc, 1); 1018 1.1 skrll harmony_start_cp(sc, 0); 1019 1.1 skrll harmony_intr_enable(sc); 1020 1.1 skrll 1021 1.1 skrll return 0; 1022 1.1 skrll } 1023 1.1 skrll 1024 1.1 skrll void 1025 1.1 skrll harmony_start_cp(struct harmony_softc *sc, int start) 1026 1.1 skrll { 1027 1.1 skrll struct harmony_channel *c; 1028 1.1 skrll struct harmony_dma *d; 1029 1.1 skrll bus_addr_t nextaddr; 1030 1.1 skrll bus_size_t togo; 1031 1.1 skrll 1032 1.1 skrll KASSERT(mutex_owned(&sc->sc_intr_lock)); 1033 1.1 skrll 1034 1.1 skrll c = &sc->sc_capture; 1035 1.1 skrll if (sc->sc_capturing == 0) 1036 1.1 skrll harmony_empty_input(sc); 1037 1.1 skrll else { 1038 1.1 skrll d = c->c_current; 1039 1.1 skrll togo = c->c_segsz - c->c_cnt; 1040 1.1 skrll if (togo == 0) { 1041 1.1 skrll nextaddr = d->d_map->dm_segs[0].ds_addr; 1042 1.1 skrll c->c_cnt = togo = c->c_blksz; 1043 1.1 skrll } else { 1044 1.1 skrll nextaddr = c->c_lastaddr; 1045 1.1 skrll if (togo > c->c_blksz) 1046 1.1 skrll togo = c->c_blksz; 1047 1.1 skrll c->c_cnt += togo; 1048 1.1 skrll } 1049 1.1 skrll 1050 1.1 skrll bus_dmamap_sync(sc->sc_dmat, d->d_map, 1051 1.1 skrll nextaddr - d->d_map->dm_segs[0].ds_addr, 1052 1.1 skrll c->c_blksz, BUS_DMASYNC_PREWRITE); 1053 1.1 skrll 1054 1.1 skrll WRITE_REG(sc, HARMONY_RNXTADD, nextaddr); 1055 1.1 skrll if (start) 1056 1.1 skrll c->c_theaddr = nextaddr; 1057 1.1 skrll SYNC_REG(sc, HARMONY_RNXTADD, BUS_SPACE_BARRIER_WRITE); 1058 1.1 skrll c->c_lastaddr = nextaddr + togo; 1059 1.1 skrll 1060 1.1 skrll harmony_try_more(sc, HARMONY_RCURADD, 1061 1.1 skrll RCURADD_BUFMASK, &sc->sc_capture); 1062 1.1 skrll } 1063 1.1 skrll 1064 1.1 skrll callout_schedule(&sc->sc_acc_tmo, 1); 1065 1.1 skrll } 1066 1.1 skrll 1067 1.1 skrll void 1068 1.1 skrll harmony_start_pp(struct harmony_softc *sc, int start) 1069 1.1 skrll { 1070 1.1 skrll struct harmony_channel *c; 1071 1.1 skrll struct harmony_dma *d; 1072 1.1 skrll bus_addr_t nextaddr; 1073 1.1 skrll bus_size_t togo; 1074 1.1 skrll 1075 1.1 skrll KASSERT(mutex_owned(&sc->sc_intr_lock)); 1076 1.1 skrll 1077 1.1 skrll c = &sc->sc_playback; 1078 1.1 skrll if (sc->sc_playing == 0) 1079 1.1 skrll harmony_empty_output(sc); 1080 1.1 skrll else { 1081 1.1 skrll d = c->c_current; 1082 1.1 skrll togo = c->c_segsz - c->c_cnt; 1083 1.1 skrll if (togo == 0) { 1084 1.1 skrll nextaddr = d->d_map->dm_segs[0].ds_addr; 1085 1.1 skrll c->c_cnt = togo = c->c_blksz; 1086 1.1 skrll } else { 1087 1.1 skrll nextaddr = c->c_lastaddr; 1088 1.1 skrll if (togo > c->c_blksz) 1089 1.1 skrll togo = c->c_blksz; 1090 1.1 skrll c->c_cnt += togo; 1091 1.1 skrll } 1092 1.1 skrll 1093 1.1 skrll bus_dmamap_sync(sc->sc_dmat, d->d_map, 1094 1.1 skrll nextaddr - d->d_map->dm_segs[0].ds_addr, 1095 1.1 skrll c->c_blksz, BUS_DMASYNC_PREWRITE); 1096 1.1 skrll 1097 1.1 skrll WRITE_REG(sc, HARMONY_PNXTADD, nextaddr); 1098 1.1 skrll if (start) 1099 1.1 skrll c->c_theaddr = nextaddr; 1100 1.1 skrll SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE); 1101 1.1 skrll c->c_lastaddr = nextaddr + togo; 1102 1.1 skrll 1103 1.1 skrll harmony_try_more(sc, HARMONY_PCURADD, 1104 1.1 skrll PCURADD_BUFMASK, &sc->sc_playback); 1105 1.1 skrll } 1106 1.1 skrll } 1107 1.1 skrll 1108 1.1 skrll int 1109 1.1 skrll harmony_trigger_input(void *vsc, void *start, void *end, int blksize, 1110 1.1 skrll void (*intr)(void *), void *intrarg, const audio_params_t *param) 1111 1.1 skrll { 1112 1.1 skrll struct harmony_softc *sc = vsc; 1113 1.1 skrll struct harmony_channel *c = &sc->sc_capture; 1114 1.1 skrll struct harmony_dma *d; 1115 1.1 skrll 1116 1.1 skrll KASSERT(mutex_owned(&sc->sc_intr_lock)); 1117 1.1 skrll 1118 1.1 skrll for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next) 1119 1.1 skrll continue; 1120 1.1 skrll if (d == NULL) { 1121 1.1 skrll printf("%s: trigger_input: bad addr: %p\n", 1122 1.1 skrll device_xname(sc->sc_dv), start); 1123 1.1 skrll return EINVAL; 1124 1.1 skrll } 1125 1.1 skrll 1126 1.1 skrll c->c_intr = intr; 1127 1.1 skrll c->c_intrarg = intrarg; 1128 1.1 skrll c->c_blksz = blksize; 1129 1.1 skrll c->c_current = d; 1130 1.1 skrll c->c_segsz = (char *)end - (char *)start; 1131 1.1 skrll c->c_cnt = 0; 1132 1.1 skrll c->c_lastaddr = d->d_map->dm_segs[0].ds_addr; 1133 1.1 skrll 1134 1.1 skrll sc->sc_capturing = 1; 1135 1.1 skrll 1136 1.1 skrll harmony_start_cp(sc, 1); 1137 1.1 skrll harmony_intr_enable(sc); 1138 1.1 skrll 1139 1.1 skrll return 0; 1140 1.1 skrll } 1141 1.1 skrll 1142 1.1 skrll static const struct speed_struct { 1143 1.1 skrll uint32_t speed; 1144 1.1 skrll uint32_t bits; 1145 1.1 skrll } harmony_speeds[] = { 1146 1.1 skrll { 5125, CNTL_RATE_5125 }, 1147 1.1 skrll { 6615, CNTL_RATE_6615 }, 1148 1.1 skrll { 8000, CNTL_RATE_8000 }, 1149 1.1 skrll { 9600, CNTL_RATE_9600 }, 1150 1.1 skrll { 11025, CNTL_RATE_11025 }, 1151 1.1 skrll { 16000, CNTL_RATE_16000 }, 1152 1.1 skrll { 18900, CNTL_RATE_18900 }, 1153 1.1 skrll { 22050, CNTL_RATE_22050 }, 1154 1.1 skrll { 27428, CNTL_RATE_27428 }, 1155 1.1 skrll { 32000, CNTL_RATE_32000 }, 1156 1.1 skrll { 33075, CNTL_RATE_33075 }, 1157 1.1 skrll { 37800, CNTL_RATE_37800 }, 1158 1.1 skrll { 44100, CNTL_RATE_44100 }, 1159 1.1 skrll { 48000, CNTL_RATE_48000 }, 1160 1.1 skrll }; 1161 1.1 skrll 1162 1.1 skrll uint32_t 1163 1.10 isaki harmony_speed_bits(struct harmony_softc *sc, u_int speed) 1164 1.1 skrll { 1165 1.10 isaki int i; 1166 1.1 skrll 1167 1.10 isaki for (i = 0; i < __arraycount(harmony_speeds); i++) { 1168 1.10 isaki if (speed == harmony_speeds[i].speed) { 1169 1.10 isaki return harmony_speeds[i].bits; 1170 1.1 skrll } 1171 1.1 skrll } 1172 1.10 isaki /* If this happens, harmony_formats[] is wrong */ 1173 1.10 isaki panic("speed %u not supported", speed); 1174 1.1 skrll } 1175 1.1 skrll 1176 1.1 skrll int 1177 1.1 skrll harmony_set_gainctl(struct harmony_softc *sc) 1178 1.1 skrll { 1179 1.1 skrll uint32_t bits, mask, val, old; 1180 1.1 skrll 1181 1.1 skrll /* XXX leave these bits alone or the chip will not come out of CNTL */ 1182 1.1 skrll bits = GAINCTL_LE | GAINCTL_HE | GAINCTL_SE | GAINCTL_IS_MASK; 1183 1.1 skrll 1184 1.1 skrll /* input level */ 1185 1.1 skrll bits |= ((sc->sc_input_lvl.left >> (8 - GAINCTL_INPUT_BITS)) << 1186 1.1 skrll GAINCTL_INPUT_LEFT_S) & GAINCTL_INPUT_LEFT_M; 1187 1.1 skrll bits |= ((sc->sc_input_lvl.right >> (8 - GAINCTL_INPUT_BITS)) << 1188 1.1 skrll GAINCTL_INPUT_RIGHT_S) & GAINCTL_INPUT_RIGHT_M; 1189 1.1 skrll 1190 1.1 skrll /* output level (inverted) */ 1191 1.1 skrll mask = (1 << GAINCTL_OUTPUT_BITS) - 1; 1192 1.1 skrll val = mask - (sc->sc_output_lvl.left >> (8 - GAINCTL_OUTPUT_BITS)); 1193 1.1 skrll bits |= (val << GAINCTL_OUTPUT_LEFT_S) & GAINCTL_OUTPUT_LEFT_M; 1194 1.1 skrll val = mask - (sc->sc_output_lvl.right >> (8 - GAINCTL_OUTPUT_BITS)); 1195 1.1 skrll bits |= (val << GAINCTL_OUTPUT_RIGHT_S) & GAINCTL_OUTPUT_RIGHT_M; 1196 1.1 skrll 1197 1.1 skrll /* monitor level (inverted) */ 1198 1.1 skrll mask = (1 << GAINCTL_MONITOR_BITS) - 1; 1199 1.1 skrll val = mask - (sc->sc_monitor_lvl.left >> (8 - GAINCTL_MONITOR_BITS)); 1200 1.1 skrll bits |= (val << GAINCTL_MONITOR_S) & GAINCTL_MONITOR_M; 1201 1.1 skrll 1202 1.1 skrll /* XXX messing with these causes CNTL_C to get stuck... grr. */ 1203 1.1 skrll bits &= ~GAINCTL_IS_MASK; 1204 1.1 skrll if (sc->sc_in_port == HARMONY_IN_MIC) 1205 1.1 skrll bits |= GAINCTL_IS_LINE; 1206 1.1 skrll else 1207 1.1 skrll bits |= GAINCTL_IS_MICROPHONE; 1208 1.1 skrll 1209 1.1 skrll /* XXX messing with these causes CNTL_C to get stuck... grr. */ 1210 1.1 skrll bits &= ~(GAINCTL_LE | GAINCTL_HE | GAINCTL_SE); 1211 1.1 skrll if (sc->sc_out_port == HARMONY_OUT_LINE) 1212 1.1 skrll bits |= GAINCTL_LE; 1213 1.1 skrll else if (sc->sc_out_port == HARMONY_OUT_SPEAKER) 1214 1.1 skrll bits |= GAINCTL_SE; 1215 1.1 skrll else 1216 1.1 skrll bits |= GAINCTL_HE; 1217 1.1 skrll 1218 1.1 skrll mask = GAINCTL_LE | GAINCTL_HE | GAINCTL_SE | GAINCTL_IS_MASK; 1219 1.1 skrll old = bus_space_read_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL); 1220 1.1 skrll bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL, bits); 1221 1.1 skrll if ((old & mask) != (bits & mask)) 1222 1.1 skrll return 1; 1223 1.1 skrll return 0; 1224 1.1 skrll } 1225 1.1 skrll 1226 1.1 skrll void 1227 1.1 skrll harmony_try_more(struct harmony_softc *sc, int curadd, int bufmask, 1228 1.1 skrll struct harmony_channel *c) 1229 1.1 skrll { 1230 1.1 skrll struct harmony_dma *d; 1231 1.1 skrll uint32_t cur; 1232 1.1 skrll int i, nsegs; 1233 1.1 skrll 1234 1.1 skrll d = c->c_current; 1235 1.1 skrll cur = bus_space_read_4(sc->sc_bt, sc->sc_bh, curadd); 1236 1.1 skrll cur &= bufmask; 1237 1.1 skrll nsegs = 0; 1238 1.1 skrll 1239 1.1 skrll #ifdef DIAGNOSTIC 1240 1.1 skrll if (cur < d->d_map->dm_segs[0].ds_addr || 1241 1.1 skrll cur >= (d->d_map->dm_segs[0].ds_addr + c->c_segsz)) 1242 1.1 skrll panic("%s: bad current %x < %lx || %x > %lx", 1243 1.1 skrll device_xname(sc->sc_dv), cur, 1244 1.1 skrll d->d_map->dm_segs[0].ds_addr, cur, 1245 1.1 skrll d->d_map->dm_segs[0].ds_addr + c->c_segsz); 1246 1.1 skrll #endif /* DIAGNOSTIC */ 1247 1.1 skrll 1248 1.1 skrll if (cur > c->c_theaddr) { 1249 1.1 skrll nsegs = (cur - c->c_theaddr) / HARMONY_BUFSIZE; 1250 1.1 skrll } else if (cur < c->c_theaddr) { 1251 1.1 skrll nsegs = (d->d_map->dm_segs[0].ds_addr + c->c_segsz - 1252 1.1 skrll c->c_theaddr) / HARMONY_BUFSIZE; 1253 1.1 skrll nsegs += (cur - d->d_map->dm_segs[0].ds_addr) / 1254 1.1 skrll HARMONY_BUFSIZE; 1255 1.1 skrll } 1256 1.1 skrll 1257 1.1 skrll if (nsegs != 0 && c->c_intr != NULL) { 1258 1.1 skrll for (i = 0; i < nsegs; i++) 1259 1.1 skrll (*c->c_intr)(c->c_intrarg); 1260 1.1 skrll c->c_theaddr = cur; 1261 1.1 skrll } 1262 1.1 skrll } 1263