1e4afd792SAlexander Motin /*- 2e4afd792SAlexander Motin * Copyright (c) 2012 Ruslan Bukin <br@bsdpad.com> 3e4afd792SAlexander Motin * All rights reserved. 4e4afd792SAlexander Motin * 5e4afd792SAlexander Motin * Redistribution and use in source and binary forms, with or without 6e4afd792SAlexander Motin * modification, are permitted provided that the following conditions 7e4afd792SAlexander Motin * are met: 8e4afd792SAlexander Motin * 1. Redistributions of source code must retain the above copyright 9e4afd792SAlexander Motin * notice, this list of conditions and the following disclaimer. 10e4afd792SAlexander Motin * 2. Redistributions in binary form must reproduce the above copyright 11e4afd792SAlexander Motin * notice, this list of conditions and the following disclaimer in the 12e4afd792SAlexander Motin * documentation and/or other materials provided with the distribution. 13e4afd792SAlexander Motin * 14e4afd792SAlexander Motin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15e4afd792SAlexander Motin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16e4afd792SAlexander Motin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17e4afd792SAlexander Motin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18e4afd792SAlexander Motin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19e4afd792SAlexander Motin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20e4afd792SAlexander Motin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21e4afd792SAlexander Motin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22e4afd792SAlexander Motin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23e4afd792SAlexander Motin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24e4afd792SAlexander Motin * SUCH DAMAGE. 25e4afd792SAlexander Motin */ 26e4afd792SAlexander Motin 27e4afd792SAlexander Motin /* 28e4afd792SAlexander Motin * RME HDSPe driver for FreeBSD. 29e4afd792SAlexander Motin * Supported cards: AIO, RayDAT. 30e4afd792SAlexander Motin */ 31e4afd792SAlexander Motin 32e4afd792SAlexander Motin #include <dev/sound/pcm/sound.h> 33e4afd792SAlexander Motin #include <dev/sound/pci/hdspe.h> 34e4afd792SAlexander Motin #include <dev/sound/chip.h> 35e4afd792SAlexander Motin 36e4afd792SAlexander Motin #include <dev/pci/pcireg.h> 37e4afd792SAlexander Motin #include <dev/pci/pcivar.h> 38e4afd792SAlexander Motin 39e4afd792SAlexander Motin #include <mixer_if.h> 40e4afd792SAlexander Motin 41e4afd792SAlexander Motin SND_DECLARE_FILE("$FreeBSD$"); 42e4afd792SAlexander Motin 43e4afd792SAlexander Motin static struct hdspe_channel chan_map_aio[] = { 44e4afd792SAlexander Motin { 0, 1, "line", 1, 1 }, 45e4afd792SAlexander Motin { 6, 7, "phone", 1, 0 }, 46e4afd792SAlexander Motin { 8, 9, "aes", 1, 1 }, 47e4afd792SAlexander Motin { 10, 11, "s/pdif", 1, 1 }, 48e4afd792SAlexander Motin { 12, 16, "adat", 1, 1 }, 49e4afd792SAlexander Motin 50e4afd792SAlexander Motin /* Single or double speed. */ 51e4afd792SAlexander Motin { 14, 18, "adat", 1, 1 }, 52e4afd792SAlexander Motin 53e4afd792SAlexander Motin /* Single speed only. */ 54e4afd792SAlexander Motin { 13, 15, "adat", 1, 1 }, 55e4afd792SAlexander Motin { 17, 19, "adat", 1, 1 }, 56e4afd792SAlexander Motin 57e4afd792SAlexander Motin { 0, 0, NULL, 0, 0 }, 58e4afd792SAlexander Motin }; 59e4afd792SAlexander Motin 60e4afd792SAlexander Motin static struct hdspe_channel chan_map_rd[] = { 61e4afd792SAlexander Motin { 0, 1, "aes", 1, 1 }, 62e4afd792SAlexander Motin { 2, 3, "s/pdif", 1, 1 }, 63e4afd792SAlexander Motin { 4, 5, "adat", 1, 1 }, 64e4afd792SAlexander Motin { 6, 7, "adat", 1, 1 }, 65e4afd792SAlexander Motin { 8, 9, "adat", 1, 1 }, 66e4afd792SAlexander Motin { 10, 11, "adat", 1, 1 }, 67e4afd792SAlexander Motin 68e4afd792SAlexander Motin /* Single or double speed. */ 69e4afd792SAlexander Motin { 12, 13, "adat", 1, 1 }, 70e4afd792SAlexander Motin { 14, 15, "adat", 1, 1 }, 71e4afd792SAlexander Motin { 16, 17, "adat", 1, 1 }, 72e4afd792SAlexander Motin { 18, 19, "adat", 1, 1 }, 73e4afd792SAlexander Motin 74e4afd792SAlexander Motin /* Single speed only. */ 75e4afd792SAlexander Motin { 20, 21, "adat", 1, 1 }, 76e4afd792SAlexander Motin { 22, 23, "adat", 1, 1 }, 77e4afd792SAlexander Motin { 24, 25, "adat", 1, 1 }, 78e4afd792SAlexander Motin { 26, 27, "adat", 1, 1 }, 79e4afd792SAlexander Motin { 28, 29, "adat", 1, 1 }, 80e4afd792SAlexander Motin { 30, 31, "adat", 1, 1 }, 81e4afd792SAlexander Motin { 32, 33, "adat", 1, 1 }, 82e4afd792SAlexander Motin { 34, 35, "adat", 1, 1 }, 83e4afd792SAlexander Motin 84e4afd792SAlexander Motin { 0, 0, NULL, 0, 0 }, 85e4afd792SAlexander Motin }; 86e4afd792SAlexander Motin 87e4afd792SAlexander Motin static void 88e4afd792SAlexander Motin hdspe_intr(void *p) 89e4afd792SAlexander Motin { 90e4afd792SAlexander Motin struct sc_info *sc = (struct sc_info *)p; 91e4afd792SAlexander Motin struct sc_pcminfo *scp; 92e4afd792SAlexander Motin device_t *devlist; 93e4afd792SAlexander Motin int devcount, status; 94e4afd792SAlexander Motin int i, err; 95e4afd792SAlexander Motin 96e4afd792SAlexander Motin snd_mtxlock(sc->lock); 97e4afd792SAlexander Motin 98e4afd792SAlexander Motin status = hdspe_read_1(sc, HDSPE_STATUS_REG); 99e4afd792SAlexander Motin if (status & HDSPE_AUDIO_IRQ_PENDING) { 100e4afd792SAlexander Motin if ((err = device_get_children(sc->dev, &devlist, &devcount)) != 0) 101e4afd792SAlexander Motin return; 102e4afd792SAlexander Motin 103e4afd792SAlexander Motin for (i = 0; i < devcount; i++) { 104e4afd792SAlexander Motin scp = device_get_ivars(devlist[i]); 105e4afd792SAlexander Motin if (scp->ih != NULL) 106e4afd792SAlexander Motin scp->ih(scp); 107e4afd792SAlexander Motin } 108e4afd792SAlexander Motin 109e4afd792SAlexander Motin hdspe_write_1(sc, HDSPE_INTERRUPT_ACK, 0); 110b5db12bfSKevin Lo free(devlist, M_TEMP); 111e4afd792SAlexander Motin } 112e4afd792SAlexander Motin 113e4afd792SAlexander Motin snd_mtxunlock(sc->lock); 114e4afd792SAlexander Motin } 115e4afd792SAlexander Motin 116e4afd792SAlexander Motin static void 117e4afd792SAlexander Motin hdspe_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 118e4afd792SAlexander Motin { 119e4afd792SAlexander Motin #if 0 120e4afd792SAlexander Motin struct sc_info *sc = (struct sc_info *)arg; 121e4afd792SAlexander Motin device_printf(sc->dev, "hdspe_dmapsetmap()\n"); 122e4afd792SAlexander Motin #endif 123e4afd792SAlexander Motin } 124e4afd792SAlexander Motin 125e4afd792SAlexander Motin static int 126e4afd792SAlexander Motin hdspe_alloc_resources(struct sc_info *sc) 127e4afd792SAlexander Motin { 128e4afd792SAlexander Motin 129e4afd792SAlexander Motin /* Allocate resource. */ 130e4afd792SAlexander Motin sc->csid = PCIR_BAR(0); 131e4afd792SAlexander Motin sc->cs = bus_alloc_resource(sc->dev, SYS_RES_MEMORY, 132e4afd792SAlexander Motin &sc->csid, 0, ~0, 1, RF_ACTIVE); 133e4afd792SAlexander Motin 134e4afd792SAlexander Motin if (!sc->cs) { 135e4afd792SAlexander Motin device_printf(sc->dev, "Unable to map SYS_RES_MEMORY.\n"); 136e4afd792SAlexander Motin return (ENXIO); 137e4afd792SAlexander Motin } 138e4afd792SAlexander Motin sc->cst = rman_get_bustag(sc->cs); 139e4afd792SAlexander Motin sc->csh = rman_get_bushandle(sc->cs); 140e4afd792SAlexander Motin 141e4afd792SAlexander Motin 142e4afd792SAlexander Motin /* Allocate interrupt resource. */ 143e4afd792SAlexander Motin sc->irqid = 0; 144e4afd792SAlexander Motin sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid, 145e4afd792SAlexander Motin 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 146e4afd792SAlexander Motin 147e4afd792SAlexander Motin if (!sc->irq || 148e4afd792SAlexander Motin bus_setup_intr(sc->dev, sc->irq, INTR_MPSAFE | INTR_TYPE_AV, 149e4afd792SAlexander Motin NULL, hdspe_intr, sc, &sc->ih)) { 150e4afd792SAlexander Motin device_printf(sc->dev, "Unable to alloc interrupt resource.\n"); 151e4afd792SAlexander Motin return (ENXIO); 152e4afd792SAlexander Motin } 153e4afd792SAlexander Motin 154e4afd792SAlexander Motin /* Allocate DMA resources. */ 155e4afd792SAlexander Motin if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev), 156e4afd792SAlexander Motin /*alignment*/4, 157e4afd792SAlexander Motin /*boundary*/0, 158e4afd792SAlexander Motin /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 159e4afd792SAlexander Motin /*highaddr*/BUS_SPACE_MAXADDR, 160e4afd792SAlexander Motin /*filter*/NULL, 161e4afd792SAlexander Motin /*filterarg*/NULL, 162e4afd792SAlexander Motin /*maxsize*/2 * HDSPE_DMASEGSIZE, 163e4afd792SAlexander Motin /*nsegments*/2, 164e4afd792SAlexander Motin /*maxsegsz*/HDSPE_DMASEGSIZE, 165e4afd792SAlexander Motin /*flags*/0, 166e4afd792SAlexander Motin /*lockfunc*/busdma_lock_mutex, 167e4afd792SAlexander Motin /*lockarg*/&Giant, 168e4afd792SAlexander Motin /*dmatag*/&sc->dmat) != 0) { 169e4afd792SAlexander Motin device_printf(sc->dev, "Unable to create dma tag.\n"); 170e4afd792SAlexander Motin return (ENXIO); 171e4afd792SAlexander Motin } 172e4afd792SAlexander Motin 173e4afd792SAlexander Motin sc->bufsize = HDSPE_DMASEGSIZE; 174e4afd792SAlexander Motin 175e4afd792SAlexander Motin /* pbuf (play buffer). */ 176e4afd792SAlexander Motin if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, 177e4afd792SAlexander Motin BUS_DMA_NOWAIT, &sc->pmap)) { 178e4afd792SAlexander Motin device_printf(sc->dev, "Can't alloc pbuf.\n"); 179e4afd792SAlexander Motin return (ENXIO); 180e4afd792SAlexander Motin } 181e4afd792SAlexander Motin 182e4afd792SAlexander Motin if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->bufsize, 183e4afd792SAlexander Motin hdspe_dmapsetmap, sc, 0)) { 184e4afd792SAlexander Motin device_printf(sc->dev, "Can't load pbuf.\n"); 185e4afd792SAlexander Motin return (ENXIO); 186e4afd792SAlexander Motin } 187e4afd792SAlexander Motin 188e4afd792SAlexander Motin /* rbuf (rec buffer). */ 189e4afd792SAlexander Motin if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, 190e4afd792SAlexander Motin BUS_DMA_NOWAIT, &sc->rmap)) { 191e4afd792SAlexander Motin device_printf(sc->dev, "Can't alloc rbuf.\n"); 192e4afd792SAlexander Motin return (ENXIO); 193e4afd792SAlexander Motin } 194e4afd792SAlexander Motin 195e4afd792SAlexander Motin if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->bufsize, 196e4afd792SAlexander Motin hdspe_dmapsetmap, sc, 0)) { 197e4afd792SAlexander Motin device_printf(sc->dev, "Can't load rbuf.\n"); 198e4afd792SAlexander Motin return (ENXIO); 199e4afd792SAlexander Motin } 200e4afd792SAlexander Motin 201e4afd792SAlexander Motin bzero(sc->pbuf, sc->bufsize); 202e4afd792SAlexander Motin bzero(sc->rbuf, sc->bufsize); 203e4afd792SAlexander Motin 204e4afd792SAlexander Motin return (0); 205e4afd792SAlexander Motin } 206e4afd792SAlexander Motin 207e4afd792SAlexander Motin static void 208e4afd792SAlexander Motin hdspe_map_dmabuf(struct sc_info *sc) 209e4afd792SAlexander Motin { 210e4afd792SAlexander Motin uint32_t paddr,raddr; 211e4afd792SAlexander Motin int i; 212e4afd792SAlexander Motin 213e4afd792SAlexander Motin paddr = vtophys(sc->pbuf); 214e4afd792SAlexander Motin raddr = vtophys(sc->rbuf); 215e4afd792SAlexander Motin 216e4afd792SAlexander Motin for (i = 0; i < HDSPE_MAX_SLOTS * 16; i++) { 217e4afd792SAlexander Motin hdspe_write_4(sc, HDSPE_PAGE_ADDR_BUF_OUT + 4 * i, 218e4afd792SAlexander Motin paddr + i * 4096); 219e4afd792SAlexander Motin hdspe_write_4(sc, HDSPE_PAGE_ADDR_BUF_IN + 4 * i, 220e4afd792SAlexander Motin raddr + i * 4096); 221e4afd792SAlexander Motin } 222e4afd792SAlexander Motin } 223e4afd792SAlexander Motin 224e4afd792SAlexander Motin static int 225e4afd792SAlexander Motin hdspe_probe(device_t dev) 226e4afd792SAlexander Motin { 227e4afd792SAlexander Motin uint32_t rev; 228e4afd792SAlexander Motin 229e4afd792SAlexander Motin if (pci_get_vendor(dev) == PCI_VENDOR_XILINX && 230e4afd792SAlexander Motin pci_get_device(dev) == PCI_DEVICE_XILINX_HDSPE) { 231e4afd792SAlexander Motin rev = pci_get_revid(dev); 232e4afd792SAlexander Motin switch (rev) { 233e4afd792SAlexander Motin case PCI_REVISION_AIO: 234e4afd792SAlexander Motin device_set_desc(dev, "RME HDSPe AIO"); 235e4afd792SAlexander Motin return 0; 236e4afd792SAlexander Motin case PCI_REVISION_RAYDAT: 237e4afd792SAlexander Motin device_set_desc(dev, "RME HDSPe RayDAT"); 238e4afd792SAlexander Motin return 0; 239e4afd792SAlexander Motin } 240e4afd792SAlexander Motin } 241e4afd792SAlexander Motin 242e4afd792SAlexander Motin return (ENXIO); 243e4afd792SAlexander Motin } 244e4afd792SAlexander Motin 245e4afd792SAlexander Motin static int 246e4afd792SAlexander Motin hdspe_init(struct sc_info *sc) 247e4afd792SAlexander Motin { 248e4afd792SAlexander Motin long long period; 249e4afd792SAlexander Motin 250e4afd792SAlexander Motin /* Set defaults. */ 251e4afd792SAlexander Motin sc->ctrl_register |= HDSPM_CLOCK_MODE_MASTER; 252e4afd792SAlexander Motin 253e4afd792SAlexander Motin /* Set latency. */ 254e4afd792SAlexander Motin sc->period = 32; 255e4afd792SAlexander Motin sc->ctrl_register = hdspe_encode_latency(7); 256e4afd792SAlexander Motin 257e4afd792SAlexander Motin /* Set rate. */ 258e4afd792SAlexander Motin sc->speed = HDSPE_SPEED_DEFAULT; 259e4afd792SAlexander Motin sc->ctrl_register &= ~HDSPE_FREQ_MASK; 260e4afd792SAlexander Motin sc->ctrl_register |= HDSPE_FREQ_MASK_DEFAULT; 261e4afd792SAlexander Motin hdspe_write_4(sc, HDSPE_CONTROL_REG, sc->ctrl_register); 262e4afd792SAlexander Motin 263e4afd792SAlexander Motin switch (sc->type) { 264e4afd792SAlexander Motin case RAYDAT: 265e4afd792SAlexander Motin case AIO: 266e4afd792SAlexander Motin period = HDSPE_FREQ_AIO; 267e4afd792SAlexander Motin break; 268e4afd792SAlexander Motin default: 269e4afd792SAlexander Motin return (ENXIO); 270e4afd792SAlexander Motin } 271e4afd792SAlexander Motin 272e4afd792SAlexander Motin /* Set DDS value. */ 273e4afd792SAlexander Motin period /= sc->speed; 274e4afd792SAlexander Motin hdspe_write_4(sc, HDSPE_FREQ_REG, period); 275e4afd792SAlexander Motin 276e4afd792SAlexander Motin /* Other settings. */ 277e4afd792SAlexander Motin sc->settings_register = 0; 278e4afd792SAlexander Motin hdspe_write_4(sc, HDSPE_SETTINGS_REG, sc->settings_register); 279e4afd792SAlexander Motin 280e4afd792SAlexander Motin return 0; 281e4afd792SAlexander Motin } 282e4afd792SAlexander Motin 283e4afd792SAlexander Motin static int 284e4afd792SAlexander Motin hdspe_attach(device_t dev) 285e4afd792SAlexander Motin { 286e4afd792SAlexander Motin struct sc_info *sc; 287e4afd792SAlexander Motin struct sc_pcminfo *scp; 288e4afd792SAlexander Motin struct hdspe_channel *chan_map; 289e4afd792SAlexander Motin uint32_t rev; 290e4afd792SAlexander Motin int i, err; 291e4afd792SAlexander Motin 292e4afd792SAlexander Motin #if 0 293e4afd792SAlexander Motin device_printf(dev, "hdspe_attach()\n"); 294e4afd792SAlexander Motin #endif 295e4afd792SAlexander Motin 296e4afd792SAlexander Motin sc = device_get_softc(dev); 297e4afd792SAlexander Motin sc->lock = snd_mtxcreate(device_get_nameunit(dev), 298e4afd792SAlexander Motin "snd_hdspe softc"); 299e4afd792SAlexander Motin sc->dev = dev; 300e4afd792SAlexander Motin 301*c68534f1SScott Long pci_enable_busmaster(dev); 302e4afd792SAlexander Motin rev = pci_get_revid(dev); 303e4afd792SAlexander Motin switch (rev) { 304e4afd792SAlexander Motin case PCI_REVISION_AIO: 305e4afd792SAlexander Motin sc->type = AIO; 306e4afd792SAlexander Motin chan_map = chan_map_aio; 307e4afd792SAlexander Motin break; 308e4afd792SAlexander Motin case PCI_REVISION_RAYDAT: 309e4afd792SAlexander Motin sc->type = RAYDAT; 310e4afd792SAlexander Motin chan_map = chan_map_rd; 311e4afd792SAlexander Motin break; 312e4afd792SAlexander Motin default: 313e4afd792SAlexander Motin return ENXIO; 314e4afd792SAlexander Motin } 315e4afd792SAlexander Motin 316e4afd792SAlexander Motin /* Allocate resources. */ 317e4afd792SAlexander Motin err = hdspe_alloc_resources(sc); 318e4afd792SAlexander Motin if (err) { 319e4afd792SAlexander Motin device_printf(dev, "Unable to allocate system resources.\n"); 320e4afd792SAlexander Motin return ENXIO; 321e4afd792SAlexander Motin } 322e4afd792SAlexander Motin 323e4afd792SAlexander Motin if (hdspe_init(sc) != 0) 324e4afd792SAlexander Motin return ENXIO; 325e4afd792SAlexander Motin 326e4afd792SAlexander Motin for (i = 0; i < HDSPE_MAX_CHANS && chan_map[i].descr != NULL; i++) { 327e4afd792SAlexander Motin scp = malloc(sizeof(struct sc_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO); 328e4afd792SAlexander Motin scp->hc = &chan_map[i]; 329e4afd792SAlexander Motin scp->sc = sc; 330e4afd792SAlexander Motin scp->dev = device_add_child(dev, "pcm", -1); 331e4afd792SAlexander Motin device_set_ivars(scp->dev, scp); 332e4afd792SAlexander Motin } 333e4afd792SAlexander Motin 334e4afd792SAlexander Motin hdspe_map_dmabuf(sc); 335e4afd792SAlexander Motin 33635d393bfSGleb Smirnoff return (bus_generic_attach(dev)); 337e4afd792SAlexander Motin } 338e4afd792SAlexander Motin 339e4afd792SAlexander Motin static void 340e4afd792SAlexander Motin hdspe_dmafree(struct sc_info *sc) 341e4afd792SAlexander Motin { 342e4afd792SAlexander Motin 343e4afd792SAlexander Motin bus_dmamap_unload(sc->dmat, sc->rmap); 344e4afd792SAlexander Motin bus_dmamap_unload(sc->dmat, sc->pmap); 345e4afd792SAlexander Motin bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 346e4afd792SAlexander Motin bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 347e4afd792SAlexander Motin sc->rmap = sc->pmap = NULL; 348e4afd792SAlexander Motin sc->rbuf = sc->pbuf = NULL; 349e4afd792SAlexander Motin } 350e4afd792SAlexander Motin 351e4afd792SAlexander Motin static int 352e4afd792SAlexander Motin hdspe_detach(device_t dev) 353e4afd792SAlexander Motin { 354e4afd792SAlexander Motin struct sc_info *sc; 355e4afd792SAlexander Motin int err; 356e4afd792SAlexander Motin 357e4afd792SAlexander Motin sc = device_get_softc(dev); 358e4afd792SAlexander Motin if (sc == NULL) { 359e4afd792SAlexander Motin device_printf(dev,"Can't detach: softc is null.\n"); 360e4afd792SAlexander Motin return 0; 361e4afd792SAlexander Motin } 362e4afd792SAlexander Motin 363e4afd792SAlexander Motin err = device_delete_children(dev); 364e4afd792SAlexander Motin if (err) 365e4afd792SAlexander Motin return (err); 366e4afd792SAlexander Motin 367e4afd792SAlexander Motin hdspe_dmafree(sc); 368e4afd792SAlexander Motin 369e4afd792SAlexander Motin if (sc->ih) 370e4afd792SAlexander Motin bus_teardown_intr(dev, sc->irq, sc->ih); 371e4afd792SAlexander Motin if (sc->dmat) 372e4afd792SAlexander Motin bus_dma_tag_destroy(sc->dmat); 373e4afd792SAlexander Motin if (sc->irq) 374e4afd792SAlexander Motin bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); 375e4afd792SAlexander Motin if (sc->cs) 376e4afd792SAlexander Motin bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), sc->cs); 377e4afd792SAlexander Motin if (sc->lock) 378e4afd792SAlexander Motin snd_mtxfree(sc->lock); 379e4afd792SAlexander Motin 380e4afd792SAlexander Motin return 0; 381e4afd792SAlexander Motin } 382e4afd792SAlexander Motin 383e4afd792SAlexander Motin static device_method_t hdspe_methods[] = { 384e4afd792SAlexander Motin DEVMETHOD(device_probe, hdspe_probe), 385e4afd792SAlexander Motin DEVMETHOD(device_attach, hdspe_attach), 386e4afd792SAlexander Motin DEVMETHOD(device_detach, hdspe_detach), 387e4afd792SAlexander Motin { 0, 0 } 388e4afd792SAlexander Motin }; 389e4afd792SAlexander Motin 390e4afd792SAlexander Motin static driver_t hdspe_driver = { 391e4afd792SAlexander Motin "hdspe", 392e4afd792SAlexander Motin hdspe_methods, 393e4afd792SAlexander Motin PCM_SOFTC_SIZE, 394e4afd792SAlexander Motin }; 395e4afd792SAlexander Motin 39635d393bfSGleb Smirnoff static devclass_t hdspe_devclass; 39735d393bfSGleb Smirnoff 39835d393bfSGleb Smirnoff DRIVER_MODULE(snd_hdspe, pci, hdspe_driver, hdspe_devclass, 0, 0); 399