12a1ad637SFrançois Tigeot /*- 22a1ad637SFrançois Tigeot * Copyright (c) 2012 Ruslan Bukin <br@bsdpad.com> 32a1ad637SFrançois Tigeot * All rights reserved. 42a1ad637SFrançois Tigeot * 52a1ad637SFrançois Tigeot * Redistribution and use in source and binary forms, with or without 62a1ad637SFrançois Tigeot * modification, are permitted provided that the following conditions 72a1ad637SFrançois Tigeot * are met: 82a1ad637SFrançois Tigeot * 1. Redistributions of source code must retain the above copyright 92a1ad637SFrançois Tigeot * notice, this list of conditions and the following disclaimer. 102a1ad637SFrançois Tigeot * 2. Redistributions in binary form must reproduce the above copyright 112a1ad637SFrançois Tigeot * notice, this list of conditions and the following disclaimer in the 122a1ad637SFrançois Tigeot * documentation and/or other materials provided with the distribution. 132a1ad637SFrançois Tigeot * 142a1ad637SFrançois Tigeot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 152a1ad637SFrançois Tigeot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 162a1ad637SFrançois Tigeot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 172a1ad637SFrançois Tigeot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 182a1ad637SFrançois Tigeot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 192a1ad637SFrançois Tigeot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 202a1ad637SFrançois Tigeot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 212a1ad637SFrançois Tigeot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 222a1ad637SFrançois Tigeot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 232a1ad637SFrançois Tigeot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 242a1ad637SFrançois Tigeot * SUCH DAMAGE. 252a1ad637SFrançois Tigeot */ 262a1ad637SFrançois Tigeot 272a1ad637SFrançois Tigeot /* 282a1ad637SFrançois Tigeot * RME HDSPe driver for FreeBSD. 292a1ad637SFrançois Tigeot * Supported cards: AIO, RayDAT. 302a1ad637SFrançois Tigeot */ 312a1ad637SFrançois Tigeot 322a1ad637SFrançois Tigeot #include <dev/sound/pcm/sound.h> 332a1ad637SFrançois Tigeot #include <dev/sound/pci/hdspe.h> 342a1ad637SFrançois Tigeot #include <dev/sound/chip.h> 352a1ad637SFrançois Tigeot 36*67931cc4SFrançois Tigeot #include <bus/pci/pcireg.h> 37*67931cc4SFrançois Tigeot #include <bus/pci/pcivar.h> 382a1ad637SFrançois Tigeot 392a1ad637SFrançois Tigeot #include <mixer_if.h> 402a1ad637SFrançois Tigeot 412a1ad637SFrançois Tigeot SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/hdspe.c 267581 2014-06-17 16:07:57Z jhb $"); 422a1ad637SFrançois Tigeot 432a1ad637SFrançois Tigeot static struct hdspe_channel chan_map_aio[] = { 442a1ad637SFrançois Tigeot { 0, 1, "line", 1, 1 }, 452a1ad637SFrançois Tigeot { 6, 7, "phone", 1, 0 }, 462a1ad637SFrançois Tigeot { 8, 9, "aes", 1, 1 }, 472a1ad637SFrançois Tigeot { 10, 11, "s/pdif", 1, 1 }, 482a1ad637SFrançois Tigeot { 12, 16, "adat", 1, 1 }, 492a1ad637SFrançois Tigeot 502a1ad637SFrançois Tigeot /* Single or double speed. */ 512a1ad637SFrançois Tigeot { 14, 18, "adat", 1, 1 }, 522a1ad637SFrançois Tigeot 532a1ad637SFrançois Tigeot /* Single speed only. */ 542a1ad637SFrançois Tigeot { 13, 15, "adat", 1, 1 }, 552a1ad637SFrançois Tigeot { 17, 19, "adat", 1, 1 }, 562a1ad637SFrançois Tigeot 572a1ad637SFrançois Tigeot { 0, 0, NULL, 0, 0 }, 582a1ad637SFrançois Tigeot }; 592a1ad637SFrançois Tigeot 602a1ad637SFrançois Tigeot static struct hdspe_channel chan_map_rd[] = { 612a1ad637SFrançois Tigeot { 0, 1, "aes", 1, 1 }, 622a1ad637SFrançois Tigeot { 2, 3, "s/pdif", 1, 1 }, 632a1ad637SFrançois Tigeot { 4, 5, "adat", 1, 1 }, 642a1ad637SFrançois Tigeot { 6, 7, "adat", 1, 1 }, 652a1ad637SFrançois Tigeot { 8, 9, "adat", 1, 1 }, 662a1ad637SFrançois Tigeot { 10, 11, "adat", 1, 1 }, 672a1ad637SFrançois Tigeot 682a1ad637SFrançois Tigeot /* Single or double speed. */ 692a1ad637SFrançois Tigeot { 12, 13, "adat", 1, 1 }, 702a1ad637SFrançois Tigeot { 14, 15, "adat", 1, 1 }, 712a1ad637SFrançois Tigeot { 16, 17, "adat", 1, 1 }, 722a1ad637SFrançois Tigeot { 18, 19, "adat", 1, 1 }, 732a1ad637SFrançois Tigeot 742a1ad637SFrançois Tigeot /* Single speed only. */ 752a1ad637SFrançois Tigeot { 20, 21, "adat", 1, 1 }, 762a1ad637SFrançois Tigeot { 22, 23, "adat", 1, 1 }, 772a1ad637SFrançois Tigeot { 24, 25, "adat", 1, 1 }, 782a1ad637SFrançois Tigeot { 26, 27, "adat", 1, 1 }, 792a1ad637SFrançois Tigeot { 28, 29, "adat", 1, 1 }, 802a1ad637SFrançois Tigeot { 30, 31, "adat", 1, 1 }, 812a1ad637SFrançois Tigeot { 32, 33, "adat", 1, 1 }, 822a1ad637SFrançois Tigeot { 34, 35, "adat", 1, 1 }, 832a1ad637SFrançois Tigeot 842a1ad637SFrançois Tigeot { 0, 0, NULL, 0, 0 }, 852a1ad637SFrançois Tigeot }; 862a1ad637SFrançois Tigeot 872a1ad637SFrançois Tigeot static void 882a1ad637SFrançois Tigeot hdspe_intr(void *p) 892a1ad637SFrançois Tigeot { 902a1ad637SFrançois Tigeot struct sc_info *sc = (struct sc_info *)p; 912a1ad637SFrançois Tigeot struct sc_pcminfo *scp; 922a1ad637SFrançois Tigeot device_t *devlist; 932a1ad637SFrançois Tigeot int devcount, status; 942a1ad637SFrançois Tigeot int i, err; 952a1ad637SFrançois Tigeot 962a1ad637SFrançois Tigeot snd_mtxlock(sc->lock); 972a1ad637SFrançois Tigeot 982a1ad637SFrançois Tigeot status = hdspe_read_1(sc, HDSPE_STATUS_REG); 992a1ad637SFrançois Tigeot if (status & HDSPE_AUDIO_IRQ_PENDING) { 1002a1ad637SFrançois Tigeot if ((err = device_get_children(sc->dev, &devlist, &devcount)) != 0) 1012a1ad637SFrançois Tigeot return; 1022a1ad637SFrançois Tigeot 1032a1ad637SFrançois Tigeot for (i = 0; i < devcount; i++) { 1042a1ad637SFrançois Tigeot scp = device_get_ivars(devlist[i]); 1052a1ad637SFrançois Tigeot if (scp->ih != NULL) 1062a1ad637SFrançois Tigeot scp->ih(scp); 1072a1ad637SFrançois Tigeot } 1082a1ad637SFrançois Tigeot 1092a1ad637SFrançois Tigeot hdspe_write_1(sc, HDSPE_INTERRUPT_ACK, 0); 110*67931cc4SFrançois Tigeot kfree(devlist, M_TEMP); 1112a1ad637SFrançois Tigeot } 1122a1ad637SFrançois Tigeot 1132a1ad637SFrançois Tigeot snd_mtxunlock(sc->lock); 1142a1ad637SFrançois Tigeot } 1152a1ad637SFrançois Tigeot 1162a1ad637SFrançois Tigeot static void 1172a1ad637SFrançois Tigeot hdspe_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1182a1ad637SFrançois Tigeot { 1192a1ad637SFrançois Tigeot #if 0 1202a1ad637SFrançois Tigeot struct sc_info *sc = (struct sc_info *)arg; 1212a1ad637SFrançois Tigeot device_printf(sc->dev, "hdspe_dmapsetmap()\n"); 1222a1ad637SFrançois Tigeot #endif 1232a1ad637SFrançois Tigeot } 1242a1ad637SFrançois Tigeot 1252a1ad637SFrançois Tigeot static int 1262a1ad637SFrançois Tigeot hdspe_alloc_resources(struct sc_info *sc) 1272a1ad637SFrançois Tigeot { 1282a1ad637SFrançois Tigeot 1292a1ad637SFrançois Tigeot /* Allocate resource. */ 1302a1ad637SFrançois Tigeot sc->csid = PCIR_BAR(0); 1312a1ad637SFrançois Tigeot sc->cs = bus_alloc_resource(sc->dev, SYS_RES_MEMORY, 1322a1ad637SFrançois Tigeot &sc->csid, 0, ~0, 1, RF_ACTIVE); 1332a1ad637SFrançois Tigeot 1342a1ad637SFrançois Tigeot if (!sc->cs) { 1352a1ad637SFrançois Tigeot device_printf(sc->dev, "Unable to map SYS_RES_MEMORY.\n"); 1362a1ad637SFrançois Tigeot return (ENXIO); 1372a1ad637SFrançois Tigeot } 1382a1ad637SFrançois Tigeot sc->cst = rman_get_bustag(sc->cs); 1392a1ad637SFrançois Tigeot sc->csh = rman_get_bushandle(sc->cs); 1402a1ad637SFrançois Tigeot 1412a1ad637SFrançois Tigeot 1422a1ad637SFrançois Tigeot /* Allocate interrupt resource. */ 1432a1ad637SFrançois Tigeot sc->irqid = 0; 1442a1ad637SFrançois Tigeot sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid, 1452a1ad637SFrançois Tigeot 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 1462a1ad637SFrançois Tigeot 1472a1ad637SFrançois Tigeot if (!sc->irq || 148*67931cc4SFrançois Tigeot bus_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, 149*67931cc4SFrançois Tigeot hdspe_intr, sc, &sc->ih, NULL)) { 1502a1ad637SFrançois Tigeot device_printf(sc->dev, "Unable to alloc interrupt resource.\n"); 1512a1ad637SFrançois Tigeot return (ENXIO); 1522a1ad637SFrançois Tigeot } 1532a1ad637SFrançois Tigeot 1542a1ad637SFrançois Tigeot /* Allocate DMA resources. */ 1552a1ad637SFrançois Tigeot if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev), 1562a1ad637SFrançois Tigeot /*alignment*/4, 1572a1ad637SFrançois Tigeot /*boundary*/0, 1582a1ad637SFrançois Tigeot /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 1592a1ad637SFrançois Tigeot /*highaddr*/BUS_SPACE_MAXADDR, 1602a1ad637SFrançois Tigeot /*filter*/NULL, 1612a1ad637SFrançois Tigeot /*filterarg*/NULL, 1622a1ad637SFrançois Tigeot /*maxsize*/2 * HDSPE_DMASEGSIZE, 1632a1ad637SFrançois Tigeot /*nsegments*/2, 1642a1ad637SFrançois Tigeot /*maxsegsz*/HDSPE_DMASEGSIZE, 1652a1ad637SFrançois Tigeot /*flags*/0, 1662a1ad637SFrançois Tigeot /*dmatag*/&sc->dmat) != 0) { 1672a1ad637SFrançois Tigeot device_printf(sc->dev, "Unable to create dma tag.\n"); 1682a1ad637SFrançois Tigeot return (ENXIO); 1692a1ad637SFrançois Tigeot } 1702a1ad637SFrançois Tigeot 1712a1ad637SFrançois Tigeot sc->bufsize = HDSPE_DMASEGSIZE; 1722a1ad637SFrançois Tigeot 1732a1ad637SFrançois Tigeot /* pbuf (play buffer). */ 1742a1ad637SFrançois Tigeot if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, 1752a1ad637SFrançois Tigeot BUS_DMA_NOWAIT, &sc->pmap)) { 1762a1ad637SFrançois Tigeot device_printf(sc->dev, "Can't alloc pbuf.\n"); 1772a1ad637SFrançois Tigeot return (ENXIO); 1782a1ad637SFrançois Tigeot } 1792a1ad637SFrançois Tigeot 1802a1ad637SFrançois Tigeot if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->bufsize, 1812a1ad637SFrançois Tigeot hdspe_dmapsetmap, sc, 0)) { 1822a1ad637SFrançois Tigeot device_printf(sc->dev, "Can't load pbuf.\n"); 1832a1ad637SFrançois Tigeot return (ENXIO); 1842a1ad637SFrançois Tigeot } 1852a1ad637SFrançois Tigeot 1862a1ad637SFrançois Tigeot /* rbuf (rec buffer). */ 1872a1ad637SFrançois Tigeot if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, 1882a1ad637SFrançois Tigeot BUS_DMA_NOWAIT, &sc->rmap)) { 1892a1ad637SFrançois Tigeot device_printf(sc->dev, "Can't alloc rbuf.\n"); 1902a1ad637SFrançois Tigeot return (ENXIO); 1912a1ad637SFrançois Tigeot } 1922a1ad637SFrançois Tigeot 1932a1ad637SFrançois Tigeot if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->bufsize, 1942a1ad637SFrançois Tigeot hdspe_dmapsetmap, sc, 0)) { 1952a1ad637SFrançois Tigeot device_printf(sc->dev, "Can't load rbuf.\n"); 1962a1ad637SFrançois Tigeot return (ENXIO); 1972a1ad637SFrançois Tigeot } 1982a1ad637SFrançois Tigeot 1992a1ad637SFrançois Tigeot bzero(sc->pbuf, sc->bufsize); 2002a1ad637SFrançois Tigeot bzero(sc->rbuf, sc->bufsize); 2012a1ad637SFrançois Tigeot 2022a1ad637SFrançois Tigeot return (0); 2032a1ad637SFrançois Tigeot } 2042a1ad637SFrançois Tigeot 2052a1ad637SFrançois Tigeot static void 2062a1ad637SFrançois Tigeot hdspe_map_dmabuf(struct sc_info *sc) 2072a1ad637SFrançois Tigeot { 2082a1ad637SFrançois Tigeot uint32_t paddr,raddr; 2092a1ad637SFrançois Tigeot int i; 2102a1ad637SFrançois Tigeot 2112a1ad637SFrançois Tigeot paddr = vtophys(sc->pbuf); 2122a1ad637SFrançois Tigeot raddr = vtophys(sc->rbuf); 2132a1ad637SFrançois Tigeot 2142a1ad637SFrançois Tigeot for (i = 0; i < HDSPE_MAX_SLOTS * 16; i++) { 2152a1ad637SFrançois Tigeot hdspe_write_4(sc, HDSPE_PAGE_ADDR_BUF_OUT + 4 * i, 2162a1ad637SFrançois Tigeot paddr + i * 4096); 2172a1ad637SFrançois Tigeot hdspe_write_4(sc, HDSPE_PAGE_ADDR_BUF_IN + 4 * i, 2182a1ad637SFrançois Tigeot raddr + i * 4096); 2192a1ad637SFrançois Tigeot } 2202a1ad637SFrançois Tigeot } 2212a1ad637SFrançois Tigeot 2222a1ad637SFrançois Tigeot static int 2232a1ad637SFrançois Tigeot hdspe_probe(device_t dev) 2242a1ad637SFrançois Tigeot { 2252a1ad637SFrançois Tigeot uint32_t rev; 2262a1ad637SFrançois Tigeot 2272a1ad637SFrançois Tigeot if (pci_get_vendor(dev) == PCI_VENDOR_XILINX && 2282a1ad637SFrançois Tigeot pci_get_device(dev) == PCI_DEVICE_XILINX_HDSPE) { 2292a1ad637SFrançois Tigeot rev = pci_get_revid(dev); 2302a1ad637SFrançois Tigeot switch (rev) { 2312a1ad637SFrançois Tigeot case PCI_REVISION_AIO: 2322a1ad637SFrançois Tigeot device_set_desc(dev, "RME HDSPe AIO"); 2332a1ad637SFrançois Tigeot return 0; 2342a1ad637SFrançois Tigeot case PCI_REVISION_RAYDAT: 2352a1ad637SFrançois Tigeot device_set_desc(dev, "RME HDSPe RayDAT"); 2362a1ad637SFrançois Tigeot return 0; 2372a1ad637SFrançois Tigeot } 2382a1ad637SFrançois Tigeot } 2392a1ad637SFrançois Tigeot 2402a1ad637SFrançois Tigeot return (ENXIO); 2412a1ad637SFrançois Tigeot } 2422a1ad637SFrançois Tigeot 2432a1ad637SFrançois Tigeot static int 2442a1ad637SFrançois Tigeot hdspe_init(struct sc_info *sc) 2452a1ad637SFrançois Tigeot { 2462a1ad637SFrançois Tigeot long long period; 2472a1ad637SFrançois Tigeot 2482a1ad637SFrançois Tigeot /* Set defaults. */ 2492a1ad637SFrançois Tigeot sc->ctrl_register |= HDSPM_CLOCK_MODE_MASTER; 2502a1ad637SFrançois Tigeot 2512a1ad637SFrançois Tigeot /* Set latency. */ 2522a1ad637SFrançois Tigeot sc->period = 32; 2532a1ad637SFrançois Tigeot sc->ctrl_register = hdspe_encode_latency(7); 2542a1ad637SFrançois Tigeot 2552a1ad637SFrançois Tigeot /* Set rate. */ 2562a1ad637SFrançois Tigeot sc->speed = HDSPE_SPEED_DEFAULT; 2572a1ad637SFrançois Tigeot sc->ctrl_register &= ~HDSPE_FREQ_MASK; 2582a1ad637SFrançois Tigeot sc->ctrl_register |= HDSPE_FREQ_MASK_DEFAULT; 2592a1ad637SFrançois Tigeot hdspe_write_4(sc, HDSPE_CONTROL_REG, sc->ctrl_register); 2602a1ad637SFrançois Tigeot 2612a1ad637SFrançois Tigeot switch (sc->type) { 2622a1ad637SFrançois Tigeot case RAYDAT: 2632a1ad637SFrançois Tigeot case AIO: 2642a1ad637SFrançois Tigeot period = HDSPE_FREQ_AIO; 2652a1ad637SFrançois Tigeot break; 2662a1ad637SFrançois Tigeot default: 2672a1ad637SFrançois Tigeot return (ENXIO); 2682a1ad637SFrançois Tigeot } 2692a1ad637SFrançois Tigeot 2702a1ad637SFrançois Tigeot /* Set DDS value. */ 2712a1ad637SFrançois Tigeot period /= sc->speed; 2722a1ad637SFrançois Tigeot hdspe_write_4(sc, HDSPE_FREQ_REG, period); 2732a1ad637SFrançois Tigeot 2742a1ad637SFrançois Tigeot /* Other settings. */ 2752a1ad637SFrançois Tigeot sc->settings_register = 0; 2762a1ad637SFrançois Tigeot hdspe_write_4(sc, HDSPE_SETTINGS_REG, sc->settings_register); 2772a1ad637SFrançois Tigeot 2782a1ad637SFrançois Tigeot return 0; 2792a1ad637SFrançois Tigeot } 2802a1ad637SFrançois Tigeot 2812a1ad637SFrançois Tigeot static int 2822a1ad637SFrançois Tigeot hdspe_attach(device_t dev) 2832a1ad637SFrançois Tigeot { 2842a1ad637SFrançois Tigeot struct sc_info *sc; 2852a1ad637SFrançois Tigeot struct sc_pcminfo *scp; 2862a1ad637SFrançois Tigeot struct hdspe_channel *chan_map; 2872a1ad637SFrançois Tigeot uint32_t rev; 2882a1ad637SFrançois Tigeot int i, err; 2892a1ad637SFrançois Tigeot 2902a1ad637SFrançois Tigeot #if 0 2912a1ad637SFrançois Tigeot device_printf(dev, "hdspe_attach()\n"); 2922a1ad637SFrançois Tigeot #endif 2932a1ad637SFrançois Tigeot 2942a1ad637SFrançois Tigeot sc = device_get_softc(dev); 2952a1ad637SFrançois Tigeot sc->lock = snd_mtxcreate(device_get_nameunit(dev), 2962a1ad637SFrançois Tigeot "snd_hdspe softc"); 2972a1ad637SFrançois Tigeot sc->dev = dev; 2982a1ad637SFrançois Tigeot 2992a1ad637SFrançois Tigeot pci_enable_busmaster(dev); 3002a1ad637SFrançois Tigeot rev = pci_get_revid(dev); 3012a1ad637SFrançois Tigeot switch (rev) { 3022a1ad637SFrançois Tigeot case PCI_REVISION_AIO: 3032a1ad637SFrançois Tigeot sc->type = AIO; 3042a1ad637SFrançois Tigeot chan_map = chan_map_aio; 3052a1ad637SFrançois Tigeot break; 3062a1ad637SFrançois Tigeot case PCI_REVISION_RAYDAT: 3072a1ad637SFrançois Tigeot sc->type = RAYDAT; 3082a1ad637SFrançois Tigeot chan_map = chan_map_rd; 3092a1ad637SFrançois Tigeot break; 3102a1ad637SFrançois Tigeot default: 3112a1ad637SFrançois Tigeot return ENXIO; 3122a1ad637SFrançois Tigeot } 3132a1ad637SFrançois Tigeot 3142a1ad637SFrançois Tigeot /* Allocate resources. */ 3152a1ad637SFrançois Tigeot err = hdspe_alloc_resources(sc); 3162a1ad637SFrançois Tigeot if (err) { 3172a1ad637SFrançois Tigeot device_printf(dev, "Unable to allocate system resources.\n"); 3182a1ad637SFrançois Tigeot return ENXIO; 3192a1ad637SFrançois Tigeot } 3202a1ad637SFrançois Tigeot 3212a1ad637SFrançois Tigeot if (hdspe_init(sc) != 0) 3222a1ad637SFrançois Tigeot return ENXIO; 3232a1ad637SFrançois Tigeot 3242a1ad637SFrançois Tigeot for (i = 0; i < HDSPE_MAX_CHANS && chan_map[i].descr != NULL; i++) { 325*67931cc4SFrançois Tigeot scp = kmalloc(sizeof(struct sc_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO); 3262a1ad637SFrançois Tigeot scp->hc = &chan_map[i]; 3272a1ad637SFrançois Tigeot scp->sc = sc; 3282a1ad637SFrançois Tigeot scp->dev = device_add_child(dev, "pcm", -1); 3292a1ad637SFrançois Tigeot device_set_ivars(scp->dev, scp); 3302a1ad637SFrançois Tigeot } 3312a1ad637SFrançois Tigeot 3322a1ad637SFrançois Tigeot hdspe_map_dmabuf(sc); 3332a1ad637SFrançois Tigeot 3342a1ad637SFrançois Tigeot return (bus_generic_attach(dev)); 3352a1ad637SFrançois Tigeot } 3362a1ad637SFrançois Tigeot 3372a1ad637SFrançois Tigeot static void 3382a1ad637SFrançois Tigeot hdspe_dmafree(struct sc_info *sc) 3392a1ad637SFrançois Tigeot { 3402a1ad637SFrançois Tigeot 3412a1ad637SFrançois Tigeot bus_dmamap_unload(sc->dmat, sc->rmap); 3422a1ad637SFrançois Tigeot bus_dmamap_unload(sc->dmat, sc->pmap); 3432a1ad637SFrançois Tigeot bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 3442a1ad637SFrançois Tigeot bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 3452a1ad637SFrançois Tigeot sc->rbuf = sc->pbuf = NULL; 3462a1ad637SFrançois Tigeot } 3472a1ad637SFrançois Tigeot 3482a1ad637SFrançois Tigeot static int 3492a1ad637SFrançois Tigeot hdspe_detach(device_t dev) 3502a1ad637SFrançois Tigeot { 3512a1ad637SFrançois Tigeot struct sc_info *sc; 3522a1ad637SFrançois Tigeot int err; 3532a1ad637SFrançois Tigeot 3542a1ad637SFrançois Tigeot sc = device_get_softc(dev); 3552a1ad637SFrançois Tigeot if (sc == NULL) { 3562a1ad637SFrançois Tigeot device_printf(dev,"Can't detach: softc is null.\n"); 3572a1ad637SFrançois Tigeot return 0; 3582a1ad637SFrançois Tigeot } 3592a1ad637SFrançois Tigeot 3602a1ad637SFrançois Tigeot err = device_delete_children(dev); 3612a1ad637SFrançois Tigeot if (err) 3622a1ad637SFrançois Tigeot return (err); 3632a1ad637SFrançois Tigeot 3642a1ad637SFrançois Tigeot hdspe_dmafree(sc); 3652a1ad637SFrançois Tigeot 3662a1ad637SFrançois Tigeot if (sc->ih) 3672a1ad637SFrançois Tigeot bus_teardown_intr(dev, sc->irq, sc->ih); 3682a1ad637SFrançois Tigeot if (sc->dmat) 3692a1ad637SFrançois Tigeot bus_dma_tag_destroy(sc->dmat); 3702a1ad637SFrançois Tigeot if (sc->irq) 3712a1ad637SFrançois Tigeot bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); 3722a1ad637SFrançois Tigeot if (sc->cs) 3732a1ad637SFrançois Tigeot bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), sc->cs); 3742a1ad637SFrançois Tigeot if (sc->lock) 3752a1ad637SFrançois Tigeot snd_mtxfree(sc->lock); 3762a1ad637SFrançois Tigeot 3772a1ad637SFrançois Tigeot return 0; 3782a1ad637SFrançois Tigeot } 3792a1ad637SFrançois Tigeot 3802a1ad637SFrançois Tigeot static device_method_t hdspe_methods[] = { 3812a1ad637SFrançois Tigeot DEVMETHOD(device_probe, hdspe_probe), 3822a1ad637SFrançois Tigeot DEVMETHOD(device_attach, hdspe_attach), 3832a1ad637SFrançois Tigeot DEVMETHOD(device_detach, hdspe_detach), 3842a1ad637SFrançois Tigeot { 0, 0 } 3852a1ad637SFrançois Tigeot }; 3862a1ad637SFrançois Tigeot 3872a1ad637SFrançois Tigeot static driver_t hdspe_driver = { 3882a1ad637SFrançois Tigeot "hdspe", 3892a1ad637SFrançois Tigeot hdspe_methods, 3902a1ad637SFrançois Tigeot PCM_SOFTC_SIZE, 3912a1ad637SFrançois Tigeot }; 3922a1ad637SFrançois Tigeot 3932a1ad637SFrançois Tigeot static devclass_t hdspe_devclass; 3942a1ad637SFrançois Tigeot 3952a1ad637SFrançois Tigeot DRIVER_MODULE(snd_hdspe, pci, hdspe_driver, hdspe_devclass, 0, 0); 396