1 /* $NetBSD: cs428x.c,v 1.2 2001/04/18 01:35:07 tacha Exp $ */ 2 3 /* 4 * Copyright (c) 2000 Tatoku Ogaito. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Tatoku Ogaito 17 * for the NetBSD Project. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* Common functions for CS4280 and CS4281 */ 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/types.h> 38 #include <sys/kernel.h> 39 #include <sys/malloc.h> 40 #include <sys/device.h> 41 42 #include <dev/pci/pcidevs.h> 43 #include <dev/pci/pcivar.h> 44 45 #include <sys/audioio.h> 46 #include <dev/audio_if.h> 47 #include <dev/midi_if.h> 48 #include <dev/mulaw.h> 49 #include <dev/auconv.h> 50 51 #include <dev/ic/ac97reg.h> 52 #include <dev/ic/ac97var.h> 53 54 #include <machine/bus.h> 55 56 #include <dev/pci/cs428xreg.h> 57 #include <dev/pci/cs428x.h> 58 59 #if defined(CS4280_DEBUG) || defined(CS4281_DEBUG) 60 int cs428x_debug = 0; 61 #endif 62 63 int 64 cs428x_open(void *addr, int flags) 65 { 66 return 0; 67 } 68 69 void 70 cs428x_close(void *addr) 71 { 72 struct cs428x_softc *sc; 73 74 sc = addr; 75 76 (*sc->halt_output)(sc); 77 (*sc->halt_input)(sc); 78 79 sc->sc_pintr = 0; 80 sc->sc_rintr = 0; 81 } 82 83 int 84 cs428x_round_blocksize(void *addr, int blk) 85 { 86 struct cs428x_softc *sc; 87 int retval; 88 89 DPRINTFN(5,("cs428x_round_blocksize blk=%d -> ", blk)); 90 91 sc = addr; 92 if (blk < sc->hw_blocksize) 93 retval = sc->hw_blocksize; 94 else 95 retval = blk & -(sc->hw_blocksize); 96 97 DPRINTFN(5,("%d\n", retval)); 98 99 return retval; 100 } 101 102 int 103 cs428x_mixer_set_port(void *addr, mixer_ctrl_t *cp) 104 { 105 struct cs428x_softc *sc; 106 int val; 107 108 sc = addr; 109 val = sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp); 110 DPRINTFN(3,("mixer_set_port: val=%d\n", val)); 111 return (val); 112 } 113 114 int 115 cs428x_mixer_get_port(void *addr, mixer_ctrl_t *cp) 116 { 117 struct cs428x_softc *sc; 118 119 sc = addr; 120 return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp)); 121 } 122 123 int 124 cs428x_query_devinfo(void *addr, mixer_devinfo_t *dip) 125 { 126 struct cs428x_softc *sc; 127 128 sc = addr; 129 return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip)); 130 } 131 132 void * 133 cs428x_malloc(void *addr, int direction, size_t size, int pool, int flags) 134 { 135 struct cs428x_softc *sc; 136 struct cs428x_dma *p; 137 int error; 138 139 sc = addr; 140 141 p = malloc(sizeof(*p), pool, flags); 142 if (p == NULL) 143 return 0; 144 145 error = cs428x_allocmem(sc, size, pool, flags, p); 146 147 if (error) { 148 free(p, pool); 149 return 0; 150 } 151 152 p->next = sc->sc_dmas; 153 sc->sc_dmas = p; 154 return BUFADDR(p); 155 } 156 157 void 158 cs428x_free(void *addr, void *ptr, int pool) 159 { 160 struct cs428x_softc *sc; 161 struct cs428x_dma **pp, *p; 162 163 sc = addr; 164 for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) { 165 if (BUFADDR(p) == ptr) { 166 bus_dmamap_unload(sc->sc_dmatag, p->map); 167 bus_dmamap_destroy(sc->sc_dmatag, p->map); 168 bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size); 169 bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs); 170 free(p->dum, pool); 171 *pp = p->next; 172 free(p, pool); 173 return; 174 } 175 } 176 } 177 178 size_t 179 cs428x_round_buffersize(void *addr, int direction, size_t size) 180 { 181 /* The real dma buffersize are 4KB for CS4280 182 * and 64kB/MAX_CHANNELS for CS4281. 183 * But they are too small for high quality audio, 184 * let the upper layer(audio) use a larger buffer. 185 * (originally suggested by Lennart Augustsson.) 186 */ 187 return size; 188 } 189 190 paddr_t 191 cs428x_mappage(void *addr, void *mem, off_t off, int prot) 192 { 193 struct cs428x_softc *sc; 194 struct cs428x_dma *p; 195 196 sc = addr; 197 198 if (off < 0) 199 return -1; 200 201 for (p = sc->sc_dmas; p && BUFADDR(p) != mem; p = p->next) 202 ; 203 204 if (p == NULL) { 205 DPRINTF(("cs428x_mappage: bad buffer address\n")); 206 return -1; 207 } 208 209 return (bus_dmamem_mmap(sc->sc_dmatag, p->segs, p->nsegs, 210 off, prot, BUS_DMA_WAITOK)); 211 } 212 213 int 214 cs428x_get_props(void *addr) 215 { 216 int retval; 217 218 retval = AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX; 219 #ifdef MMAP_READY 220 /* How can I mmap ? */ 221 retval |= AUDIO_PROP_MMAP; 222 #endif 223 return retval; 224 } 225 226 /* AC97 */ 227 int 228 cs428x_attach_codec(void *addr, struct ac97_codec_if *codec_if) 229 { 230 struct cs428x_softc *sc; 231 232 DPRINTF(("cs428x_attach_codec:\n")); 233 sc = addr; 234 sc->codec_if = codec_if; 235 return 0; 236 } 237 238 int 239 cs428x_read_codec(void *addr, u_int8_t ac97_addr, u_int16_t *ac97_data) 240 { 241 struct cs428x_softc *sc; 242 u_int32_t acctl; 243 int n; 244 245 sc = addr; 246 247 DPRINTFN(5,("read_codec: add=0x%02x ", ac97_addr)); 248 /* 249 * Make sure that there is not data sitting around from a preivous 250 * uncompleted access. 251 */ 252 BA0READ4(sc, CS428X_ACSDA); 253 254 /* Set up AC97 control registers. */ 255 BA0WRITE4(sc, CS428X_ACCAD, ac97_addr); 256 BA0WRITE4(sc, CS428X_ACCDA, 0); 257 258 acctl = ACCTL_ESYN | ACCTL_VFRM | ACCTL_CRW | ACCTL_DCV; 259 if (sc->type == TYPE_CS4280) 260 acctl |= ACCTL_RSTN; 261 BA0WRITE4(sc, CS428X_ACCTL, acctl); 262 263 if (cs428x_src_wait(sc) < 0) { 264 printf("%s: AC97 read prob. (DCV!=0) for add=0x%0x\n", 265 sc->sc_dev.dv_xname, ac97_addr); 266 return 1; 267 } 268 269 /* wait for valid status bit is active */ 270 n = 0; 271 while ((BA0READ4(sc, CS428X_ACSTS) & ACSTS_VSTS) == 0) { 272 delay(1); 273 while (++n > 1000) { 274 printf("%s: AC97 read fail (VSTS==0) for add=0x%0x\n", 275 sc->sc_dev.dv_xname, ac97_addr); 276 return 1; 277 } 278 } 279 *ac97_data = BA0READ4(sc, CS428X_ACSDA); 280 DPRINTFN(5,("data=0x%04x\n", *ac97_data)); 281 return 0; 282 } 283 284 int 285 cs428x_write_codec(void *addr, u_int8_t ac97_addr, u_int16_t ac97_data) 286 { 287 struct cs428x_softc *sc; 288 u_int32_t acctl; 289 290 sc = addr; 291 292 DPRINTFN(5,("write_codec: add=0x%02x data=0x%04x\n", ac97_addr, ac97_data)); 293 BA0WRITE4(sc, CS428X_ACCAD, ac97_addr); 294 BA0WRITE4(sc, CS428X_ACCDA, ac97_data); 295 296 acctl = ACCTL_ESYN | ACCTL_VFRM | ACCTL_DCV; 297 if (sc->type == TYPE_CS4280) 298 acctl |= ACCTL_RSTN; 299 BA0WRITE4(sc, CS428X_ACCTL, acctl); 300 301 if (cs428x_src_wait(sc) < 0) { 302 printf("%s: AC97 write fail (DCV!=0) for add=0x%02x data=" 303 "0x%04x\n", sc->sc_dev.dv_xname, ac97_addr, ac97_data); 304 return 1; 305 } 306 return 0; 307 } 308 309 /* Internal functions */ 310 int 311 cs428x_allocmem(struct cs428x_softc *sc, 312 size_t size, int pool, int flags, 313 struct cs428x_dma *p) 314 { 315 int error; 316 size_t align; 317 318 align = sc->dma_align; 319 p->size = sc->dma_size; 320 /* allocate memory for upper audio driver */ 321 p->dum = malloc(size, pool, flags); 322 if (p->dum == NULL) 323 return 1; 324 325 error = bus_dmamem_alloc(sc->sc_dmatag, p->size, align, 0, 326 p->segs, sizeof(p->segs)/sizeof(p->segs[0]), 327 &p->nsegs, BUS_DMA_NOWAIT); 328 if (error) { 329 printf("%s: unable to allocate dma. error=%d\n", 330 sc->sc_dev.dv_xname, error); 331 goto allfree; 332 } 333 334 error = bus_dmamem_map(sc->sc_dmatag, p->segs, p->nsegs, p->size, 335 &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); 336 if (error) { 337 printf("%s: unable to map dma, error=%d\n", 338 sc->sc_dev.dv_xname, error); 339 goto free; 340 } 341 342 error = bus_dmamap_create(sc->sc_dmatag, p->size, 1, p->size, 343 0, BUS_DMA_NOWAIT, &p->map); 344 if (error) { 345 printf("%s: unable to create dma map, error=%d\n", 346 sc->sc_dev.dv_xname, error); 347 goto unmap; 348 } 349 350 error = bus_dmamap_load(sc->sc_dmatag, p->map, p->addr, p->size, NULL, 351 BUS_DMA_NOWAIT); 352 if (error) { 353 printf("%s: unable to load dma map, error=%d\n", 354 sc->sc_dev.dv_xname, error); 355 goto destroy; 356 } 357 return 0; 358 359 destroy: 360 bus_dmamap_destroy(sc->sc_dmatag, p->map); 361 unmap: 362 bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size); 363 free: 364 bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs); 365 allfree: 366 free(p->dum, pool); 367 368 return error; 369 } 370 371 int 372 cs428x_src_wait(sc) 373 struct cs428x_softc *sc; 374 { 375 int n; 376 377 n = 0; 378 while ((BA0READ4(sc, CS428X_ACCTL) & ACCTL_DCV)) { 379 delay(1000); 380 while (++n > 1000) { 381 printf("cs428x_src_wait: 0x%08x\n", 382 BA0READ4(sc, CS428X_ACCTL)); 383 return -1; 384 } 385 } 386 return 0; 387 } 388