| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: harmony.c,v 1.12 2008/07/04 11:18:02 skrll Exp $ */ | | 1 | /* $NetBSD: harmony.c,v 1.13 2008/09/23 14:07:11 mjf Exp $ */ |
2 | | | 2 | |
3 | /* $OpenBSD: harmony.c,v 1.23 2004/02/13 21:28:19 mickey Exp $ */ | | 3 | /* $OpenBSD: harmony.c,v 1.23 2004/02/13 21:28:19 mickey Exp $ */ |
4 | | | 4 | |
5 | /* | | 5 | /* |
6 | * Copyright (c) 2003 Jason L. Wright (jason@thought.net) | | 6 | * Copyright (c) 2003 Jason L. Wright (jason@thought.net) |
7 | * All rights reserved. | | 7 | * All rights reserved. |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
| @@ -117,30 +117,32 @@ const struct audio_hw_if harmony_sa_hw_i | | | @@ -117,30 +117,32 @@ const struct audio_hw_if harmony_sa_hw_i |
117 | int harmony_match(device_t, struct cfdata *, void *); | | 117 | int harmony_match(device_t, struct cfdata *, void *); |
118 | void harmony_attach(device_t, device_t, void *); | | 118 | void harmony_attach(device_t, device_t, void *); |
119 | | | 119 | |
120 | | | 120 | |
121 | CFATTACH_DECL_NEW(harmony, sizeof(struct harmony_softc), | | 121 | CFATTACH_DECL_NEW(harmony, sizeof(struct harmony_softc), |
122 | harmony_match, harmony_attach, NULL, NULL); | | 122 | harmony_match, harmony_attach, NULL, NULL); |
123 | | | 123 | |
124 | int harmony_intr(void *); | | 124 | int harmony_intr(void *); |
125 | void harmony_intr_enable(struct harmony_softc *); | | 125 | void harmony_intr_enable(struct harmony_softc *); |
126 | void harmony_intr_disable(struct harmony_softc *); | | 126 | void harmony_intr_disable(struct harmony_softc *); |
127 | uint32_t harmony_speed_bits(struct harmony_softc *, u_int *); | | 127 | uint32_t harmony_speed_bits(struct harmony_softc *, u_int *); |
128 | int harmony_set_gainctl(struct harmony_softc *); | | 128 | int harmony_set_gainctl(struct harmony_softc *); |
129 | void harmony_reset_codec(struct harmony_softc *); | | 129 | void harmony_reset_codec(struct harmony_softc *); |
130 | void harmony_start_cp(struct harmony_softc *); | | 130 | void harmony_start_cp(struct harmony_softc *, int); |
| | | 131 | void harmony_start_pp(struct harmony_softc *, int); |
131 | void harmony_tick_pb(void *); | | 132 | void harmony_tick_pb(void *); |
132 | void harmony_tick_cp(void *); | | 133 | void harmony_tick_cp(void *); |
133 | void harmony_try_more(struct harmony_softc *); | | 134 | void harmony_try_more(struct harmony_softc *, int, int, |
| | | 135 | struct harmony_channel *); |
134 | | | 136 | |
135 | #if NRND > 0 | | 137 | #if NRND > 0 |
136 | void harmony_acc_tmo(void *); | | 138 | void harmony_acc_tmo(void *); |
137 | #define ADD_CLKALLICA(sc) do { \ | | 139 | #define ADD_CLKALLICA(sc) do { \ |
138 | (sc)->sc_acc <<= 1; \ | | 140 | (sc)->sc_acc <<= 1; \ |
139 | (sc)->sc_acc |= READ_REG((sc), HARMONY_DIAG) & DIAG_CO; \ | | 141 | (sc)->sc_acc |= READ_REG((sc), HARMONY_DIAG) & DIAG_CO; \ |
140 | if ((sc)->sc_acc_cnt++ && !((sc)->sc_acc_cnt % 32)) \ | | 142 | if ((sc)->sc_acc_cnt++ && !((sc)->sc_acc_cnt % 32)) \ |
141 | rnd_add_uint32(&(sc)->sc_rnd_source, \ | | 143 | rnd_add_uint32(&(sc)->sc_rnd_source, \ |
142 | (sc)->sc_acc_num ^= (sc)->sc_acc); \ | | 144 | (sc)->sc_acc_num ^= (sc)->sc_acc); \ |
143 | } while(0) | | 145 | } while(0) |
144 | #endif | | 146 | #endif |
145 | | | 147 | |
146 | int | | 148 | int |
| @@ -317,75 +319,47 @@ harmony_acc_tmo(void *v) | | | @@ -317,75 +319,47 @@ harmony_acc_tmo(void *v) |
317 | sc = v; | | 319 | sc = v; |
318 | ADD_CLKALLICA(sc); | | 320 | ADD_CLKALLICA(sc); |
319 | callout_schedule(&sc->sc_acc_tmo, 1); | | 321 | callout_schedule(&sc->sc_acc_tmo, 1); |
320 | } | | 322 | } |
321 | #endif | | 323 | #endif |
322 | | | 324 | |
323 | /* | | 325 | /* |
324 | * interrupt handler | | 326 | * interrupt handler |
325 | */ | | 327 | */ |
326 | int | | 328 | int |
327 | harmony_intr(void *vsc) | | 329 | harmony_intr(void *vsc) |
328 | { | | 330 | { |
329 | struct harmony_softc *sc; | | 331 | struct harmony_softc *sc; |
330 | struct harmony_channel *c; | | | |
331 | uint32_t dstatus; | | 332 | uint32_t dstatus; |
332 | int r; | | 333 | int r; |
333 | | | 334 | |
334 | sc = vsc; | | 335 | sc = vsc; |
335 | r = 0; | | 336 | r = 0; |
336 | #if NRND > 0 | | 337 | #if NRND > 0 |
337 | ADD_CLKALLICA(sc); | | 338 | ADD_CLKALLICA(sc); |
338 | #endif | | 339 | #endif |
339 | | | 340 | |
340 | harmony_intr_disable(sc); | | 341 | harmony_intr_disable(sc); |
341 | | | 342 | |
342 | dstatus = READ_REG(sc, HARMONY_DSTATUS); | | 343 | dstatus = READ_REG(sc, HARMONY_DSTATUS); |
343 | | | 344 | |
344 | if (sc->sc_playing && (dstatus & DSTATUS_PN)) { | | 345 | if (dstatus & DSTATUS_PN) { |
345 | struct harmony_dma *d; | | | |
346 | bus_addr_t nextaddr; | | | |
347 | bus_size_t togo; | | | |
348 | | | | |
349 | r = 1; | | 346 | r = 1; |
350 | c = &sc->sc_playback; | | 347 | harmony_start_pp(sc, 0); |
351 | d = c->c_current; | | | |
352 | togo = c->c_segsz - c->c_cnt; | | | |
353 | if (togo == 0) { | | | |
354 | nextaddr = d->d_map->dm_segs[0].ds_addr; | | | |
355 | c->c_cnt = togo = c->c_blksz; | | | |
356 | } else { | | | |
357 | nextaddr = c->c_lastaddr; | | | |
358 | if (togo > c->c_blksz) | | | |
359 | togo = c->c_blksz; | | | |
360 | c->c_cnt += togo; | | | |
361 | } | | | |
362 | | | | |
363 | bus_dmamap_sync(sc->sc_dmat, d->d_map, | | | |
364 | nextaddr - d->d_map->dm_segs[0].ds_addr, | | | |
365 | c->c_blksz, BUS_DMASYNC_PREWRITE); | | | |
366 | | | | |
367 | WRITE_REG(sc, HARMONY_PNXTADD, nextaddr); | | | |
368 | SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE); | | | |
369 | c->c_lastaddr = nextaddr + togo; | | | |
370 | harmony_try_more(sc); | | | |
371 | } | | 348 | } |
372 | | | 349 | |
373 | if (dstatus & DSTATUS_RN) { | | 350 | if (dstatus & DSTATUS_RN) { |
374 | c = &sc->sc_capture; | | | |
375 | r = 1; | | 351 | r = 1; |
376 | harmony_start_cp(sc); | | 352 | harmony_start_cp(sc, 0); |
377 | if (sc->sc_capturing && c->c_intr != NULL) | | | |
378 | (*c->c_intr)(c->c_intrarg); | | | |
379 | } | | 353 | } |
380 | | | 354 | |
381 | if (READ_REG(sc, HARMONY_OV) & OV_OV) { | | 355 | if (READ_REG(sc, HARMONY_OV) & OV_OV) { |
382 | sc->sc_ov = 1; | | 356 | sc->sc_ov = 1; |
383 | WRITE_REG(sc, HARMONY_OV, 0); | | 357 | WRITE_REG(sc, HARMONY_OV, 0); |
384 | } else | | 358 | } else |
385 | sc->sc_ov = 0; | | 359 | sc->sc_ov = 0; |
386 | | | 360 | |
387 | harmony_intr_enable(sc); | | 361 | harmony_intr_enable(sc); |
388 | | | 362 | |
389 | return r; | | 363 | return r; |
390 | } | | 364 | } |
391 | | | 365 | |
| @@ -1076,77 +1050,56 @@ int | | | @@ -1076,77 +1050,56 @@ int |
1076 | harmony_get_props(void *vsc) | | 1050 | harmony_get_props(void *vsc) |
1077 | { | | 1051 | { |
1078 | | | 1052 | |
1079 | return AUDIO_PROP_FULLDUPLEX; | | 1053 | return AUDIO_PROP_FULLDUPLEX; |
1080 | } | | 1054 | } |
1081 | | | 1055 | |
1082 | int | | 1056 | int |
1083 | harmony_trigger_output(void *vsc, void *start, void *end, int blksize, | | 1057 | harmony_trigger_output(void *vsc, void *start, void *end, int blksize, |
1084 | void (*intr)(void *), void *intrarg, const audio_params_t *param) | | 1058 | void (*intr)(void *), void *intrarg, const audio_params_t *param) |
1085 | { | | 1059 | { |
1086 | struct harmony_softc *sc; | | 1060 | struct harmony_softc *sc; |
1087 | struct harmony_channel *c; | | 1061 | struct harmony_channel *c; |
1088 | struct harmony_dma *d; | | 1062 | struct harmony_dma *d; |
1089 | bus_addr_t nextaddr; | | | |
1090 | bus_size_t togo; | | | |
1091 | | | 1063 | |
1092 | sc = vsc; | | 1064 | sc = vsc; |
1093 | c = &sc->sc_playback; | | 1065 | c = &sc->sc_playback; |
1094 | for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next) | | 1066 | for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next) |
1095 | continue; | | 1067 | continue; |
1096 | if (d == NULL) { | | 1068 | if (d == NULL) { |
1097 | printf("%s: trigger_output: bad addr: %p\n", | | 1069 | printf("%s: trigger_output: bad addr: %p\n", |
1098 | device_xname(sc->sc_dv), start); | | 1070 | device_xname(sc->sc_dv), start); |
1099 | return EINVAL; | | 1071 | return EINVAL; |
1100 | } | | 1072 | } |
1101 | | | 1073 | |
1102 | c->c_intr = intr; | | 1074 | c->c_intr = intr; |
1103 | c->c_intrarg = intrarg; | | 1075 | c->c_intrarg = intrarg; |
1104 | c->c_blksz = blksize; | | 1076 | c->c_blksz = blksize; |
1105 | c->c_current = d; | | 1077 | c->c_current = d; |
1106 | c->c_segsz = (char *)end - (char *)start; | | 1078 | c->c_segsz = (char *)end - (char *)start; |
1107 | c->c_cnt = 0; | | 1079 | c->c_cnt = 0; |
1108 | c->c_lastaddr = d->d_map->dm_segs[0].ds_addr; | | 1080 | c->c_lastaddr = d->d_map->dm_segs[0].ds_addr; |
1109 | | | 1081 | |
1110 | sc->sc_playing = 1; | | 1082 | sc->sc_playing = 1; |
1111 | | | 1083 | |
1112 | togo = c->c_segsz - c->c_cnt; | | 1084 | harmony_start_pp(sc, 1); |
1113 | if (togo == 0) { | | 1085 | harmony_start_cp(sc, 0); |
1114 | nextaddr = d->d_map->dm_segs[0].ds_addr; | | | |
1115 | c->c_cnt = togo = c->c_blksz; | | | |
1116 | } else { | | | |
1117 | nextaddr = c->c_lastaddr; | | | |
1118 | if (togo > c->c_blksz) | | | |
1119 | togo = c->c_blksz; | | | |
1120 | c->c_cnt += togo; | | | |
1121 | } | | | |
1122 | | | | |
1123 | bus_dmamap_sync(sc->sc_dmat, d->d_map, | | | |
1124 | nextaddr - d->d_map->dm_segs[0].ds_addr, | | | |
1125 | c->c_blksz, BUS_DMASYNC_PREWRITE); | | | |
1126 | | | | |
1127 | WRITE_REG(sc, HARMONY_PNXTADD, nextaddr); | | | |
1128 | c->c_theaddr = nextaddr; | | | |
1129 | SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE); | | | |
1130 | c->c_lastaddr = nextaddr + togo; | | | |
1131 | | | | |
1132 | harmony_start_cp(sc); | | | |
1133 | harmony_intr_enable(sc); | | 1086 | harmony_intr_enable(sc); |
1134 | | | 1087 | |
1135 | return 0; | | 1088 | return 0; |
1136 | } | | 1089 | } |
1137 | | | 1090 | |
1138 | void | | 1091 | void |
1139 | harmony_start_cp(struct harmony_softc *sc) | | 1092 | harmony_start_cp(struct harmony_softc *sc, int start) |
1140 | { | | 1093 | { |
1141 | struct harmony_channel *c; | | 1094 | struct harmony_channel *c; |
1142 | struct harmony_dma *d; | | 1095 | struct harmony_dma *d; |
1143 | bus_addr_t nextaddr; | | 1096 | bus_addr_t nextaddr; |
1144 | bus_size_t togo; | | 1097 | bus_size_t togo; |
1145 | | | 1098 | |
1146 | c = &sc->sc_capture; | | 1099 | c = &sc->sc_capture; |
1147 | if (sc->sc_capturing == 0) { | | 1100 | if (sc->sc_capturing == 0) { |
1148 | WRITE_REG(sc, HARMONY_RNXTADD, | | 1101 | WRITE_REG(sc, HARMONY_RNXTADD, |
1149 | sc->sc_capture_paddrs[sc->sc_capture_empty]); | | 1102 | sc->sc_capture_paddrs[sc->sc_capture_empty]); |
1150 | if (++sc->sc_capture_empty == CAPTURE_EMPTYS) | | 1103 | if (++sc->sc_capture_empty == CAPTURE_EMPTYS) |
1151 | sc->sc_capture_empty = 0; | | 1104 | sc->sc_capture_empty = 0; |
1152 | } else { | | 1105 | } else { |
| @@ -1157,35 +1110,82 @@ harmony_start_cp(struct harmony_softc *s | | | @@ -1157,35 +1110,82 @@ harmony_start_cp(struct harmony_softc *s |
1157 | c->c_cnt = togo = c->c_blksz; | | 1110 | c->c_cnt = togo = c->c_blksz; |
1158 | } else { | | 1111 | } else { |
1159 | nextaddr = c->c_lastaddr; | | 1112 | nextaddr = c->c_lastaddr; |
1160 | if (togo > c->c_blksz) | | 1113 | if (togo > c->c_blksz) |
1161 | togo = c->c_blksz; | | 1114 | togo = c->c_blksz; |
1162 | c->c_cnt += togo; | | 1115 | c->c_cnt += togo; |
1163 | } | | 1116 | } |
1164 | | | 1117 | |
1165 | bus_dmamap_sync(sc->sc_dmat, d->d_map, | | 1118 | bus_dmamap_sync(sc->sc_dmat, d->d_map, |
1166 | nextaddr - d->d_map->dm_segs[0].ds_addr, | | 1119 | nextaddr - d->d_map->dm_segs[0].ds_addr, |
1167 | c->c_blksz, BUS_DMASYNC_PREWRITE); | | 1120 | c->c_blksz, BUS_DMASYNC_PREWRITE); |
1168 | | | 1121 | |
1169 | WRITE_REG(sc, HARMONY_RNXTADD, nextaddr); | | 1122 | WRITE_REG(sc, HARMONY_RNXTADD, nextaddr); |
| | | 1123 | if (start) |
| | | 1124 | c->c_theaddr = nextaddr; |
1170 | SYNC_REG(sc, HARMONY_RNXTADD, BUS_SPACE_BARRIER_WRITE); | | 1125 | SYNC_REG(sc, HARMONY_RNXTADD, BUS_SPACE_BARRIER_WRITE); |
1171 | c->c_lastaddr = nextaddr + togo; | | 1126 | c->c_lastaddr = nextaddr + togo; |
| | | 1127 | |
| | | 1128 | harmony_try_more(sc, HARMONY_RCURADD, |
| | | 1129 | RCURADD_BUFMASK, &sc->sc_capture); |
1172 | } | | 1130 | } |
1173 | | | 1131 | |
1174 | #if NRND > 0 | | 1132 | #if NRND > 0 |
1175 | callout_schedule(&sc->sc_acc_tmo, 1); | | 1133 | callout_schedule(&sc->sc_acc_tmo, 1); |
1176 | #endif | | 1134 | #endif |
1177 | } | | 1135 | } |
1178 | | | 1136 | |
| | | 1137 | void |
| | | 1138 | harmony_start_pp(struct harmony_softc *sc, int start) |
| | | 1139 | { |
| | | 1140 | struct harmony_channel *c; |
| | | 1141 | struct harmony_dma *d; |
| | | 1142 | bus_addr_t nextaddr; |
| | | 1143 | bus_size_t togo; |
| | | 1144 | |
| | | 1145 | c = &sc->sc_playback; |
| | | 1146 | if (sc->sc_playing == 0) { |
| | | 1147 | WRITE_REG(sc, HARMONY_PNXTADD, |
| | | 1148 | sc->sc_playback_paddrs[sc->sc_playback_empty]); |
| | | 1149 | if (++sc->sc_playback_empty == PLAYBACK_EMPTYS) |
| | | 1150 | sc->sc_playback_empty = 0; |
| | | 1151 | } else { |
| | | 1152 | d = c->c_current; |
| | | 1153 | togo = c->c_segsz - c->c_cnt; |
| | | 1154 | if (togo == 0) { |
| | | 1155 | nextaddr = d->d_map->dm_segs[0].ds_addr; |
| | | 1156 | c->c_cnt = togo = c->c_blksz; |
| | | 1157 | } else { |
| | | 1158 | nextaddr = c->c_lastaddr; |
| | | 1159 | if (togo > c->c_blksz) |
| | | 1160 | togo = c->c_blksz; |
| | | 1161 | c->c_cnt += togo; |
| | | 1162 | } |
| | | 1163 | |
| | | 1164 | bus_dmamap_sync(sc->sc_dmat, d->d_map, |
| | | 1165 | nextaddr - d->d_map->dm_segs[0].ds_addr, |
| | | 1166 | c->c_blksz, BUS_DMASYNC_PREWRITE); |
| | | 1167 | |
| | | 1168 | WRITE_REG(sc, HARMONY_PNXTADD, nextaddr); |
| | | 1169 | if (start) |
| | | 1170 | c->c_theaddr = nextaddr; |
| | | 1171 | SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE); |
| | | 1172 | c->c_lastaddr = nextaddr + togo; |
| | | 1173 | |
| | | 1174 | harmony_try_more(sc, HARMONY_PCURADD, |
| | | 1175 | PCURADD_BUFMASK, &sc->sc_playback); |
| | | 1176 | } |
| | | 1177 | } |
| | | 1178 | |
1179 | int | | 1179 | int |
1180 | harmony_trigger_input(void *vsc, void *start, void *end, int blksize, | | 1180 | harmony_trigger_input(void *vsc, void *start, void *end, int blksize, |
1181 | void (*intr)(void *), void *intrarg, const audio_params_t *param) | | 1181 | void (*intr)(void *), void *intrarg, const audio_params_t *param) |
1182 | { | | 1182 | { |
1183 | struct harmony_softc *sc; | | 1183 | struct harmony_softc *sc; |
1184 | struct harmony_channel *c; | | 1184 | struct harmony_channel *c; |
1185 | struct harmony_dma *d; | | 1185 | struct harmony_dma *d; |
1186 | | | 1186 | |
1187 | sc = vsc; | | 1187 | sc = vsc; |
1188 | c = &sc->sc_capture; | | 1188 | c = &sc->sc_capture; |
1189 | for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next) | | 1189 | for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next) |
1190 | continue; | | 1190 | continue; |
1191 | if (d == NULL) { | | 1191 | if (d == NULL) { |
| @@ -1193,28 +1193,31 @@ harmony_trigger_input(void *vsc, void *s | | | @@ -1193,28 +1193,31 @@ harmony_trigger_input(void *vsc, void *s |
1193 | device_xname(sc->sc_dv), start); | | 1193 | device_xname(sc->sc_dv), start); |
1194 | return EINVAL; | | 1194 | return EINVAL; |
1195 | } | | 1195 | } |
1196 | | | 1196 | |
1197 | c->c_intr = intr; | | 1197 | c->c_intr = intr; |
1198 | c->c_intrarg = intrarg; | | 1198 | c->c_intrarg = intrarg; |
1199 | c->c_blksz = blksize; | | 1199 | c->c_blksz = blksize; |
1200 | c->c_current = d; | | 1200 | c->c_current = d; |
1201 | c->c_segsz = (char *)end - (char *)start; | | 1201 | c->c_segsz = (char *)end - (char *)start; |
1202 | c->c_cnt = 0; | | 1202 | c->c_cnt = 0; |
1203 | c->c_lastaddr = d->d_map->dm_segs[0].ds_addr; | | 1203 | c->c_lastaddr = d->d_map->dm_segs[0].ds_addr; |
1204 | | | 1204 | |
1205 | sc->sc_capturing = 1; | | 1205 | sc->sc_capturing = 1; |
1206 | harmony_start_cp(sc); | | 1206 | |
| | | 1207 | harmony_start_pp(sc, 0); |
| | | 1208 | harmony_start_cp(sc, 1); |
1207 | harmony_intr_enable(sc); | | 1209 | harmony_intr_enable(sc); |
| | | 1210 | |
1208 | return 0; | | 1211 | return 0; |
1209 | } | | 1212 | } |
1210 | | | 1213 | |
1211 | static const struct speed_struct { | | 1214 | static const struct speed_struct { |
1212 | uint32_t speed; | | 1215 | uint32_t speed; |
1213 | uint32_t bits; | | 1216 | uint32_t bits; |
1214 | } harmony_speeds[] = { | | 1217 | } harmony_speeds[] = { |
1215 | { 5125, CNTL_RATE_5125 }, | | 1218 | { 5125, CNTL_RATE_5125 }, |
1216 | { 6615, CNTL_RATE_6615 }, | | 1219 | { 6615, CNTL_RATE_6615 }, |
1217 | { 8000, CNTL_RATE_8000 }, | | 1220 | { 8000, CNTL_RATE_8000 }, |
1218 | { 9600, CNTL_RATE_9600 }, | | 1221 | { 9600, CNTL_RATE_9600 }, |
1219 | { 11025, CNTL_RATE_11025 }, | | 1222 | { 11025, CNTL_RATE_11025 }, |
1220 | { 16000, CNTL_RATE_16000 }, | | 1223 | { 16000, CNTL_RATE_16000 }, |
| @@ -1305,37 +1308,36 @@ harmony_set_gainctl(struct harmony_softc | | | @@ -1305,37 +1308,36 @@ harmony_set_gainctl(struct harmony_softc |
1305 | bits |= GAINCTL_SE; | | 1308 | bits |= GAINCTL_SE; |
1306 | else | | 1309 | else |
1307 | bits |= GAINCTL_HE; | | 1310 | bits |= GAINCTL_HE; |
1308 | | | 1311 | |
1309 | mask = GAINCTL_LE | GAINCTL_HE | GAINCTL_SE | GAINCTL_IS_MASK; | | 1312 | mask = GAINCTL_LE | GAINCTL_HE | GAINCTL_SE | GAINCTL_IS_MASK; |
1310 | old = bus_space_read_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL); | | 1313 | old = bus_space_read_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL); |
1311 | bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL, bits); | | 1314 | bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL, bits); |
1312 | if ((old & mask) != (bits & mask)) | | 1315 | if ((old & mask) != (bits & mask)) |
1313 | return 1; | | 1316 | return 1; |
1314 | return 0; | | 1317 | return 0; |
1315 | } | | 1318 | } |
1316 | | | 1319 | |
1317 | void | | 1320 | void |
1318 | harmony_try_more(struct harmony_softc *sc) | | 1321 | harmony_try_more(struct harmony_softc *sc, int curadd, int bufmask, |
| | | 1322 | struct harmony_channel *c) |
1319 | { | | 1323 | { |
1320 | struct harmony_channel *c; | | | |
1321 | struct harmony_dma *d; | | 1324 | struct harmony_dma *d; |
1322 | uint32_t cur; | | 1325 | uint32_t cur; |
1323 | int i, nsegs; | | 1326 | int i, nsegs; |
1324 | | | 1327 | |
1325 | c = &sc->sc_playback; | | | |
1326 | d = c->c_current; | | 1328 | d = c->c_current; |
1327 | cur = bus_space_read_4(sc->sc_bt, sc->sc_bh, HARMONY_PCURADD); | | 1329 | cur = bus_space_read_4(sc->sc_bt, sc->sc_bh, curadd); |
1328 | cur &= PCURADD_BUFMASK; | | 1330 | cur &= bufmask; |
1329 | nsegs = 0; | | 1331 | nsegs = 0; |
1330 | | | 1332 | |
1331 | #ifdef DIAGNOSTIC | | 1333 | #ifdef DIAGNOSTIC |
1332 | if (cur < d->d_map->dm_segs[0].ds_addr || | | 1334 | if (cur < d->d_map->dm_segs[0].ds_addr || |
1333 | cur >= (d->d_map->dm_segs[0].ds_addr + c->c_segsz)) | | 1335 | cur >= (d->d_map->dm_segs[0].ds_addr + c->c_segsz)) |
1334 | panic("%s: bad current %x < %lx || %x > %lx", | | 1336 | panic("%s: bad current %x < %lx || %x > %lx", |
1335 | device_xname(sc->sc_dv), cur, | | 1337 | device_xname(sc->sc_dv), cur, |
1336 | d->d_map->dm_segs[0].ds_addr, cur, | | 1338 | d->d_map->dm_segs[0].ds_addr, cur, |
1337 | d->d_map->dm_segs[0].ds_addr + c->c_segsz); | | 1339 | d->d_map->dm_segs[0].ds_addr + c->c_segsz); |
1338 | #endif /* DIAGNOSTIC */ | | 1340 | #endif /* DIAGNOSTIC */ |
1339 | | | 1341 | |
1340 | if (cur > c->c_theaddr) { | | 1342 | if (cur > c->c_theaddr) { |
1341 | nsegs = (cur - c->c_theaddr) / HARMONY_BUFSIZE; | | 1343 | nsegs = (cur - c->c_theaddr) / HARMONY_BUFSIZE; |