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