1139749Simp/*- 2102011Sorion * Copyright (c) 2002 Orion Hodson <orion@freebsd.org> 3102011Sorion * Portions of this code derived from via82c686.c: 4102011Sorion * Copyright (c) 2000 David Jones <dej@ox.org> 5102011Sorion * All rights reserved. 6102011Sorion * 7102011Sorion * Redistribution and use in source and binary forms, with or without 8102011Sorion * modification, are permitted provided that the following conditions 9102011Sorion * are met: 10102011Sorion * 1. Redistributions of source code must retain the above copyright 11102011Sorion * notice, this list of conditions and the following disclaimer. 12102011Sorion * 2. Redistributions in binary form must reproduce the above copyright 13102011Sorion * notice, this list of conditions and the following disclaimer in the 14102011Sorion * documentation and/or other materials provided with the distribution. 15102011Sorion * 16102011Sorion * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17102011Sorion * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18102011Sorion * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19102011Sorion * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20102011Sorion * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21102011Sorion * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22102011Sorion * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23102011Sorion * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24102011Sorion * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25102011Sorion * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26102011Sorion * SUCH DAMAGE. 27102011Sorion */ 28102011Sorion 29111269Sorion/* 30111269Sorion * Credits due to: 31102011Sorion * 32102011Sorion * Grzybowski Rafal, Russell Davies, Mark Handley, Daniel O'Connor for 33102011Sorion * comments, machine time, testing patches, and patience. VIA for 34102011Sorion * providing specs. ALSA for helpful comments and some register poke 35164614Sariff * ordering. 36102011Sorion */ 37102011Sorion 38193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS 39193640Sariff#include "opt_snd.h" 40193640Sariff#endif 41193640Sariff 42102011Sorion#include <dev/sound/pcm/sound.h> 43102011Sorion#include <dev/sound/pcm/ac97.h> 44102011Sorion 45119287Simp#include <dev/pci/pcireg.h> 46119287Simp#include <dev/pci/pcivar.h> 47102011Sorion#include <sys/sysctl.h> 48102011Sorion 49102011Sorion#include <dev/sound/pci/via8233.h> 50102011Sorion 51102011SorionSND_DECLARE_FILE("$FreeBSD$"); 52102011Sorion 53102011Sorion#define VIA8233_PCI_ID 0x30591106 54102011Sorion 55111269Sorion#define VIA8233_REV_ID_8233PRE 0x10 56111269Sorion#define VIA8233_REV_ID_8233C 0x20 57111269Sorion#define VIA8233_REV_ID_8233 0x30 58111269Sorion#define VIA8233_REV_ID_8233A 0x40 59111269Sorion#define VIA8233_REV_ID_8235 0x50 60129758Smatk#define VIA8233_REV_ID_8237 0x60 61157956Sariff#define VIA8233_REV_ID_8251 0x70 62111269Sorion 63102011Sorion#define SEGS_PER_CHAN 2 /* Segments per channel */ 64111269Sorion#define NDXSCHANS 4 /* No of DXS channels */ 65111269Sorion#define NMSGDCHANS 1 /* No of multichannel SGD */ 66111269Sorion#define NWRCHANS 1 /* No of write channels */ 67111269Sorion#define NCHANS (NWRCHANS + NDXSCHANS + NMSGDCHANS) 68102011Sorion#define NSEGS NCHANS * SEGS_PER_CHAN /* Segments in SGD table */ 69164614Sariff#define VIA_SEGS_MIN 2 70166278Sariff#define VIA_SEGS_MAX 64 71164614Sariff#define VIA_SEGS_DEFAULT 2 72167648Sariff#define VIA_BLK_MIN 32 73167648Sariff#define VIA_BLK_ALIGN (~(VIA_BLK_MIN - 1)) 74102011Sorion 75102011Sorion#define VIA_DEFAULT_BUFSZ 0x1000 76102011Sorion 77102011Sorion/* we rely on this struct being packed to 64 bits */ 78102011Sorionstruct via_dma_op { 79164614Sariff volatile uint32_t ptr; 80164614Sariff volatile uint32_t flags; 81102011Sorion#define VIA_DMAOP_EOL 0x80000000 82102011Sorion#define VIA_DMAOP_FLAG 0x40000000 83102011Sorion#define VIA_DMAOP_STOP 0x20000000 84102011Sorion#define VIA_DMAOP_COUNT(x) ((x)&0x00FFFFFF) 85102011Sorion}; 86102011Sorion 87102011Sorionstruct via_info; 88102011Sorion 89102011Sorionstruct via_chinfo { 90102011Sorion struct via_info *parent; 91102011Sorion struct pcm_channel *channel; 92102011Sorion struct snd_dbuf *buffer; 93102011Sorion struct via_dma_op *sgd_table; 94111183Scognet bus_addr_t sgd_addr; 95164614Sariff int dir, rbase, active; 96164614Sariff unsigned int blksz, blkcnt; 97164614Sariff unsigned int ptr, prevptr; 98102011Sorion}; 99102011Sorion 100102011Sorionstruct via_info { 101167648Sariff device_t dev; 102167648Sariff 103102011Sorion bus_space_tag_t st; 104102011Sorion bus_space_handle_t sh; 105102011Sorion bus_dma_tag_t parent_dmat; 106102011Sorion bus_dma_tag_t sgd_dmat; 107102011Sorion bus_dmamap_t sgd_dmamap; 108111183Scognet bus_addr_t sgd_addr; 109102011Sorion 110102011Sorion struct resource *reg, *irq; 111102011Sorion int regid, irqid; 112102011Sorion void *ih; 113102011Sorion struct ac97_info *codec; 114102011Sorion 115164614Sariff unsigned int bufsz, blkcnt; 116157956Sariff int dxs_src, dma_eol_wake; 117102011Sorion 118111269Sorion struct via_chinfo pch[NDXSCHANS + NMSGDCHANS]; 119111269Sorion struct via_chinfo rch[NWRCHANS]; 120102011Sorion struct via_dma_op *sgd_table; 121164614Sariff uint16_t codec_caps; 122164614Sariff uint16_t n_dxs_registered; 123170137Sariff int play_num, rec_num; 124148596Snetchild struct mtx *lock; 125164614Sariff struct callout poll_timer; 126164614Sariff int poll_ticks, polling; 127102011Sorion}; 128102011Sorion 129164614Sariffstatic uint32_t via_fmt[] = { 130193640Sariff SND_FORMAT(AFMT_U8, 1, 0), 131193640Sariff SND_FORMAT(AFMT_U8, 2, 0), 132193640Sariff SND_FORMAT(AFMT_S16_LE, 1, 0), 133193640Sariff SND_FORMAT(AFMT_S16_LE, 2, 0), 134102011Sorion 0 135102011Sorion}; 136102011Sorion 137102011Sorionstatic struct pcmchan_caps via_vracaps = { 4000, 48000, via_fmt, 0 }; 138102011Sorionstatic struct pcmchan_caps via_caps = { 48000, 48000, via_fmt, 0 }; 139102011Sorion 140164614Sariffstatic __inline int 141164614Sariffvia_chan_active(struct via_info *via) 142164614Sariff{ 143164614Sariff int i, ret = 0; 144164614Sariff 145164614Sariff if (via == NULL) 146164614Sariff return (0); 147164614Sariff 148164614Sariff for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++) 149164614Sariff ret += via->pch[i].active; 150164614Sariff 151164614Sariff for (i = 0; i < NWRCHANS; i++) 152164614Sariff ret += via->rch[i].active; 153164614Sariff 154164614Sariff return (ret); 155164614Sariff} 156164614Sariff 157148596Snetchildstatic int 158148596Snetchildsysctl_via8233_spdif_enable(SYSCTL_HANDLER_ARGS) 159148596Snetchild{ 160148596Snetchild struct via_info *via; 161148596Snetchild device_t dev; 162150980Snetchild uint32_t r; 163150980Snetchild int err, new_en; 164148596Snetchild 165148596Snetchild dev = oidp->oid_arg1; 166148596Snetchild via = pcm_getdevinfo(dev); 167148596Snetchild snd_mtxlock(via->lock); 168150980Snetchild r = pci_read_config(dev, VIA_PCI_SPDIF, 1); 169148596Snetchild snd_mtxunlock(via->lock); 170150980Snetchild new_en = (r & VIA_SPDIF_EN) ? 1 : 0; 171170289Sdwmalone err = sysctl_handle_int(oidp, &new_en, 0, req); 172148596Snetchild 173148596Snetchild if (err || req->newptr == NULL) 174164614Sariff return (err); 175148596Snetchild if (new_en < 0 || new_en > 1) 176164614Sariff return (EINVAL); 177148596Snetchild 178148596Snetchild if (new_en) 179148596Snetchild r |= VIA_SPDIF_EN; 180150980Snetchild else 181150980Snetchild r &= ~VIA_SPDIF_EN; 182150980Snetchild snd_mtxlock(via->lock); 183148596Snetchild pci_write_config(dev, VIA_PCI_SPDIF, r, 1); 184148596Snetchild snd_mtxunlock(via->lock); 185148596Snetchild 186164614Sariff return (0); 187148596Snetchild} 188148596Snetchild 189148596Snetchildstatic int 190148596Snetchildsysctl_via8233_dxs_src(SYSCTL_HANDLER_ARGS) 191148596Snetchild{ 192148596Snetchild struct via_info *via; 193148596Snetchild device_t dev; 194148596Snetchild int err, val; 195148596Snetchild 196148596Snetchild dev = oidp->oid_arg1; 197148596Snetchild via = pcm_getdevinfo(dev); 198148596Snetchild snd_mtxlock(via->lock); 199148596Snetchild val = via->dxs_src; 200148596Snetchild snd_mtxunlock(via->lock); 201170289Sdwmalone err = sysctl_handle_int(oidp, &val, 0, req); 202148596Snetchild 203148596Snetchild if (err || req->newptr == NULL) 204164614Sariff return (err); 205148596Snetchild if (val < 0 || val > 1) 206164614Sariff return (EINVAL); 207148596Snetchild 208148596Snetchild snd_mtxlock(via->lock); 209148596Snetchild via->dxs_src = val; 210148596Snetchild snd_mtxunlock(via->lock); 211148596Snetchild 212164614Sariff return (0); 213148596Snetchild} 214164614Sariff 215164614Sariffstatic int 216164614Sariffsysctl_via_polling(SYSCTL_HANDLER_ARGS) 217164614Sariff{ 218164614Sariff struct via_info *via; 219164614Sariff device_t dev; 220164614Sariff int err, val; 221164614Sariff 222164614Sariff dev = oidp->oid_arg1; 223164614Sariff via = pcm_getdevinfo(dev); 224164614Sariff if (via == NULL) 225164614Sariff return (EINVAL); 226164614Sariff snd_mtxlock(via->lock); 227164614Sariff val = via->polling; 228164614Sariff snd_mtxunlock(via->lock); 229170289Sdwmalone err = sysctl_handle_int(oidp, &val, 0, req); 230164614Sariff 231164614Sariff if (err || req->newptr == NULL) 232164614Sariff return (err); 233164614Sariff if (val < 0 || val > 1) 234164614Sariff return (EINVAL); 235164614Sariff 236164614Sariff snd_mtxlock(via->lock); 237164614Sariff if (val != via->polling) { 238164614Sariff if (via_chan_active(via) != 0) 239164614Sariff err = EBUSY; 240164614Sariff else if (val == 0) 241164614Sariff via->polling = 0; 242164614Sariff else 243164614Sariff via->polling = 1; 244164614Sariff } 245164614Sariff snd_mtxunlock(via->lock); 246164614Sariff 247164614Sariff return (err); 248164614Sariff} 249148596Snetchild 250148596Snetchildstatic void 251148596Snetchildvia_init_sysctls(device_t dev) 252148596Snetchild{ 253159732Snetchild /* XXX: an user should be able to set this with a control tool, 254159732Snetchild if not done before 7.0-RELEASE, this needs to be converted to 255159732Snetchild a device specific sysctl "dev.pcm.X.yyy" via device_get_sysctl_*() 256159732Snetchild as discussed on multimedia@ in msg-id <861wujij2q.fsf@xps.des.no> */ 257164614Sariff SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 258164614Sariff SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 259164614Sariff "spdif_enabled", CTLTYPE_INT | CTLFLAG_RW, dev, sizeof(dev), 260164614Sariff sysctl_via8233_spdif_enable, "I", 261164614Sariff "Enable S/PDIF output on primary playback channel"); 262164614Sariff SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 263164614Sariff SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 264164614Sariff "dxs_src", CTLTYPE_INT | CTLFLAG_RW, dev, sizeof(dev), 265164614Sariff sysctl_via8233_dxs_src, "I", 266164614Sariff "Enable VIA DXS Sample Rate Converter"); 267164614Sariff SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 268164614Sariff SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 269164614Sariff "polling", CTLTYPE_INT | CTLFLAG_RW, dev, sizeof(dev), 270164614Sariff sysctl_via_polling, "I", 271164614Sariff "Enable polling mode"); 272148596Snetchild} 273148596Snetchild 274164614Sariffstatic __inline uint32_t 275102011Sorionvia_rd(struct via_info *via, int regno, int size) 276102011Sorion{ 277102011Sorion switch (size) { 278102011Sorion case 1: 279164614Sariff return (bus_space_read_1(via->st, via->sh, regno)); 280102011Sorion case 2: 281164614Sariff return (bus_space_read_2(via->st, via->sh, regno)); 282102011Sorion case 4: 283164614Sariff return (bus_space_read_4(via->st, via->sh, regno)); 284102011Sorion default: 285164614Sariff return (0xFFFFFFFF); 286102011Sorion } 287102011Sorion} 288102011Sorion 289150980Snetchildstatic __inline void 290164614Sariffvia_wr(struct via_info *via, int regno, uint32_t data, int size) 291102011Sorion{ 292102011Sorion 293102011Sorion switch (size) { 294102011Sorion case 1: 295102011Sorion bus_space_write_1(via->st, via->sh, regno, data); 296102011Sorion break; 297102011Sorion case 2: 298102011Sorion bus_space_write_2(via->st, via->sh, regno, data); 299102011Sorion break; 300102011Sorion case 4: 301102011Sorion bus_space_write_4(via->st, via->sh, regno, data); 302102011Sorion break; 303102011Sorion } 304102011Sorion} 305102011Sorion 306102011Sorion/* -------------------------------------------------------------------- */ 307102011Sorion/* Codec interface */ 308102011Sorion 309102011Sorionstatic int 310102011Sorionvia_waitready_codec(struct via_info *via) 311102011Sorion{ 312102011Sorion int i; 313102011Sorion 314102011Sorion /* poll until codec not busy */ 315102011Sorion for (i = 0; i < 1000; i++) { 316102011Sorion if ((via_rd(via, VIA_AC97_CONTROL, 4) & VIA_AC97_BUSY) == 0) 317164614Sariff return (0); 318102011Sorion DELAY(1); 319102011Sorion } 320167648Sariff device_printf(via->dev, "%s: codec busy\n", __func__); 321164614Sariff return (1); 322102011Sorion} 323102011Sorion 324102011Sorionstatic int 325102011Sorionvia_waitvalid_codec(struct via_info *via) 326102011Sorion{ 327102011Sorion int i; 328102011Sorion 329102011Sorion /* poll until codec valid */ 330102011Sorion for (i = 0; i < 1000; i++) { 331102011Sorion if (via_rd(via, VIA_AC97_CONTROL, 4) & VIA_AC97_CODEC00_VALID) 332164614Sariff return (0); 333102011Sorion DELAY(1); 334102011Sorion } 335167648Sariff device_printf(via->dev, "%s: codec invalid\n", __func__); 336164614Sariff return (1); 337102011Sorion} 338102011Sorion 339102011Sorionstatic int 340164614Sariffvia_write_codec(kobj_t obj, void *addr, int reg, uint32_t val) 341102011Sorion{ 342102011Sorion struct via_info *via = addr; 343102011Sorion 344164614Sariff if (via_waitready_codec(via)) 345164614Sariff return (-1); 346102011Sorion 347164614Sariff via_wr(via, VIA_AC97_CONTROL, 348102011Sorion VIA_AC97_CODEC00_VALID | VIA_AC97_INDEX(reg) | 349102011Sorion VIA_AC97_DATA(val), 4); 350102011Sorion 351164614Sariff return (0); 352102011Sorion} 353102011Sorion 354102011Sorionstatic int 355102011Sorionvia_read_codec(kobj_t obj, void *addr, int reg) 356102011Sorion{ 357102011Sorion struct via_info *via = addr; 358102011Sorion 359102011Sorion if (via_waitready_codec(via)) 360164614Sariff return (-1); 361102011Sorion 362164614Sariff via_wr(via, VIA_AC97_CONTROL, VIA_AC97_CODEC00_VALID | 363164614Sariff VIA_AC97_READ | VIA_AC97_INDEX(reg), 4); 364102011Sorion 365102011Sorion if (via_waitready_codec(via)) 366164614Sariff return (-1); 367102011Sorion 368102011Sorion if (via_waitvalid_codec(via)) 369164614Sariff return (-1); 370102011Sorion 371164614Sariff return (via_rd(via, VIA_AC97_CONTROL, 2)); 372102011Sorion} 373102011Sorion 374102011Sorionstatic kobj_method_t via_ac97_methods[] = { 375164614Sariff KOBJMETHOD(ac97_read, via_read_codec), 376164614Sariff KOBJMETHOD(ac97_write, via_write_codec), 377193640Sariff KOBJMETHOD_END 378102011Sorion}; 379102011SorionAC97_DECLARE(via_ac97); 380102011Sorion 381102011Sorion/* -------------------------------------------------------------------- */ 382102011Sorion 383102011Sorionstatic int 384102011Sorionvia_buildsgdt(struct via_chinfo *ch) 385102011Sorion{ 386164614Sariff uint32_t phys_addr, flag; 387164614Sariff int i; 388102011Sorion 389111183Scognet phys_addr = sndbuf_getbufaddr(ch->buffer); 390102011Sorion 391164614Sariff for (i = 0; i < ch->blkcnt; i++) { 392164614Sariff flag = (i == ch->blkcnt - 1) ? VIA_DMAOP_EOL : VIA_DMAOP_FLAG; 393164614Sariff ch->sgd_table[i].ptr = phys_addr + (i * ch->blksz); 394164614Sariff ch->sgd_table[i].flags = flag | ch->blksz; 395102011Sorion } 396102011Sorion 397164614Sariff return (0); 398102011Sorion} 399102011Sorion 400111269Sorion/* -------------------------------------------------------------------- */ 401111269Sorion/* Format setting functions */ 402111269Sorion 403102011Sorionstatic int 404164614Sariffvia8233wr_setformat(kobj_t obj, void *data, uint32_t format) 405102011Sorion{ 406102011Sorion struct via_chinfo *ch = data; 407102011Sorion struct via_info *via = ch->parent; 408148596Snetchild 409164614Sariff uint32_t f = WR_FORMAT_STOP_INDEX; 410102011Sorion 411193640Sariff if (AFMT_CHANNEL(format) > 1) 412111269Sorion f |= WR_FORMAT_STEREO; 413111269Sorion if (format & AFMT_S16_LE) 414111269Sorion f |= WR_FORMAT_16BIT; 415150980Snetchild snd_mtxlock(via->lock); 416111269Sorion via_wr(via, VIA_WR0_FORMAT, f, 4); 417150980Snetchild snd_mtxunlock(via->lock); 418111269Sorion 419164614Sariff return (0); 420111269Sorion} 421111269Sorion 422111269Sorionstatic int 423164614Sariffvia8233dxs_setformat(kobj_t obj, void *data, uint32_t format) 424111269Sorion{ 425111269Sorion struct via_chinfo *ch = data; 426111269Sorion struct via_info *via = ch->parent; 427164614Sariff uint32_t r, v; 428111269Sorion 429148596Snetchild r = ch->rbase + VIA8233_RP_DXS_RATEFMT; 430150980Snetchild snd_mtxlock(via->lock); 431148596Snetchild v = via_rd(via, r, 4); 432111269Sorion 433111269Sorion v &= ~(VIA8233_DXS_RATEFMT_STEREO | VIA8233_DXS_RATEFMT_16BIT); 434193640Sariff if (AFMT_CHANNEL(format) > 1) 435111269Sorion v |= VIA8233_DXS_RATEFMT_STEREO; 436164614Sariff if (format & AFMT_16BIT) 437111269Sorion v |= VIA8233_DXS_RATEFMT_16BIT; 438111269Sorion via_wr(via, r, v, 4); 439150980Snetchild snd_mtxunlock(via->lock); 440111269Sorion 441164614Sariff return (0); 442111269Sorion} 443111269Sorion 444111269Sorionstatic int 445164614Sariffvia8233msgd_setformat(kobj_t obj, void *data, uint32_t format) 446111269Sorion{ 447111269Sorion struct via_chinfo *ch = data; 448111269Sorion struct via_info *via = ch->parent; 449111269Sorion 450164614Sariff uint32_t s = 0xff000000; 451164614Sariff uint8_t v = (format & AFMT_S16_LE) ? MC_SGD_16BIT : MC_SGD_8BIT; 452102011Sorion 453193640Sariff if (AFMT_CHANNEL(format) > 1) { 454102011Sorion v |= MC_SGD_CHANNELS(2); 455102011Sorion s |= SLOT3(1) | SLOT4(2); 456102011Sorion } else { 457102011Sorion v |= MC_SGD_CHANNELS(1); 458102011Sorion s |= SLOT3(1) | SLOT4(1); 459102011Sorion } 460102011Sorion 461150980Snetchild snd_mtxlock(via->lock); 462102011Sorion via_wr(via, VIA_MC_SLOT_SELECT, s, 4); 463102011Sorion via_wr(via, VIA_MC_SGD_FORMAT, v, 1); 464150980Snetchild snd_mtxunlock(via->lock); 465102011Sorion 466164614Sariff return (0); 467102011Sorion} 468102011Sorion 469111269Sorion/* -------------------------------------------------------------------- */ 470111269Sorion/* Speed setting functions */ 471111269Sorion 472193640Sariffstatic uint32_t 473164614Sariffvia8233wr_setspeed(kobj_t obj, void *data, uint32_t speed) 474102011Sorion{ 475102011Sorion struct via_chinfo *ch = data; 476102011Sorion struct via_info *via = ch->parent; 477102011Sorion 478148596Snetchild if (via->codec_caps & AC97_EXTCAP_VRA) 479164614Sariff return (ac97_setrate(via->codec, AC97_REGEXT_LADCRATE, speed)); 480148596Snetchild 481164614Sariff return (48000); 482102011Sorion} 483102011Sorion 484193640Sariffstatic uint32_t 485164614Sariffvia8233dxs_setspeed(kobj_t obj, void *data, uint32_t speed) 486102011Sorion{ 487102011Sorion struct via_chinfo *ch = data; 488102011Sorion struct via_info *via = ch->parent; 489164614Sariff uint32_t r, v; 490102011Sorion 491148596Snetchild r = ch->rbase + VIA8233_RP_DXS_RATEFMT; 492150980Snetchild snd_mtxlock(via->lock); 493148596Snetchild v = via_rd(via, r, 4) & ~VIA8233_DXS_RATEFMT_48K; 494102011Sorion 495111269Sorion /* Careful to avoid overflow (divide by 48 per vt8233c docs) */ 496111269Sorion 497111269Sorion v |= VIA8233_DXS_RATEFMT_48K * (speed / 48) / (48000 / 48); 498111269Sorion via_wr(via, r, v, 4); 499150980Snetchild snd_mtxunlock(via->lock); 500111269Sorion 501164614Sariff return (speed); 502102011Sorion} 503102011Sorion 504193640Sariffstatic uint32_t 505164614Sariffvia8233msgd_setspeed(kobj_t obj, void *data, uint32_t speed) 506102011Sorion{ 507102011Sorion struct via_chinfo *ch = data; 508102011Sorion struct via_info *via = ch->parent; 509102011Sorion 510111269Sorion if (via->codec_caps & AC97_EXTCAP_VRA) 511164614Sariff return (ac97_setrate(via->codec, AC97_REGEXT_FDACRATE, speed)); 512111269Sorion 513164614Sariff return (48000); 514102011Sorion} 515102011Sorion 516111269Sorion/* -------------------------------------------------------------------- */ 517112438Sorion/* Format probing functions */ 518112438Sorion 519112438Sorionstatic struct pcmchan_caps * 520112438Sorionvia8233wr_getcaps(kobj_t obj, void *data) 521112438Sorion{ 522112438Sorion struct via_chinfo *ch = data; 523112438Sorion struct via_info *via = ch->parent; 524112438Sorion 525112438Sorion /* Controlled by ac97 registers */ 526148596Snetchild if (via->codec_caps & AC97_EXTCAP_VRA) 527164614Sariff return (&via_vracaps); 528164614Sariff return (&via_caps); 529112438Sorion} 530112438Sorion 531112438Sorionstatic struct pcmchan_caps * 532112438Sorionvia8233dxs_getcaps(kobj_t obj, void *data) 533112438Sorion{ 534148596Snetchild struct via_chinfo *ch = data; 535148596Snetchild struct via_info *via = ch->parent; 536148596Snetchild 537148596Snetchild /* 538148596Snetchild * Controlled by onboard registers 539148596Snetchild * 540148596Snetchild * Apparently, few boards can do DXS sample rate 541148596Snetchild * conversion. 542148596Snetchild */ 543148596Snetchild if (via->dxs_src) 544164614Sariff return (&via_vracaps); 545164614Sariff return (&via_caps); 546112438Sorion} 547112438Sorion 548112438Sorionstatic struct pcmchan_caps * 549112438Sorionvia8233msgd_getcaps(kobj_t obj, void *data) 550112438Sorion{ 551112438Sorion struct via_chinfo *ch = data; 552112438Sorion struct via_info *via = ch->parent; 553112438Sorion 554112438Sorion /* Controlled by ac97 registers */ 555148596Snetchild if (via->codec_caps & AC97_EXTCAP_VRA) 556164614Sariff return (&via_vracaps); 557164614Sariff return (&via_caps); 558112438Sorion} 559112438Sorion 560112438Sorion/* -------------------------------------------------------------------- */ 561111269Sorion/* Common functions */ 562111269Sorion 563102011Sorionstatic int 564167648Sariffvia8233chan_setfragments(kobj_t obj, void *data, 565167648Sariff uint32_t blksz, uint32_t blkcnt) 566102011Sorion{ 567102011Sorion struct via_chinfo *ch = data; 568167648Sariff struct via_info *via = ch->parent; 569148596Snetchild 570167648Sariff blksz &= VIA_BLK_ALIGN; 571164614Sariff 572167648Sariff if (blksz > (sndbuf_getmaxsize(ch->buffer) / VIA_SEGS_MIN)) 573167648Sariff blksz = sndbuf_getmaxsize(ch->buffer) / VIA_SEGS_MIN; 574167648Sariff if (blksz < VIA_BLK_MIN) 575167648Sariff blksz = VIA_BLK_MIN; 576167648Sariff if (blkcnt > VIA_SEGS_MAX) 577167648Sariff blkcnt = VIA_SEGS_MAX; 578167648Sariff if (blkcnt < VIA_SEGS_MIN) 579167648Sariff blkcnt = VIA_SEGS_MIN; 580167648Sariff 581167648Sariff while ((blksz * blkcnt) > sndbuf_getmaxsize(ch->buffer)) { 582167648Sariff if ((blkcnt >> 1) >= VIA_SEGS_MIN) 583167648Sariff blkcnt >>= 1; 584167648Sariff else if ((blksz >> 1) >= VIA_BLK_MIN) 585167648Sariff blksz >>= 1; 586167648Sariff else 587167648Sariff break; 588167648Sariff } 589167648Sariff 590164614Sariff if ((sndbuf_getblksz(ch->buffer) != blksz || 591167648Sariff sndbuf_getblkcnt(ch->buffer) != blkcnt) && 592167648Sariff sndbuf_resize(ch->buffer, blkcnt, blksz) != 0) 593167648Sariff device_printf(via->dev, "%s: failed blksz=%u blkcnt=%u\n", 594167648Sariff __func__, blksz, blkcnt); 595164614Sariff 596109863Sorion ch->blksz = sndbuf_getblksz(ch->buffer); 597167648Sariff ch->blkcnt = sndbuf_getblkcnt(ch->buffer); 598164614Sariff 599193640Sariff return (0); 600167648Sariff} 601167648Sariff 602193640Sariffstatic uint32_t 603167648Sariffvia8233chan_setblocksize(kobj_t obj, void *data, uint32_t blksz) 604167648Sariff{ 605167648Sariff struct via_chinfo *ch = data; 606167648Sariff struct via_info *via = ch->parent; 607167648Sariff 608167648Sariff via8233chan_setfragments(obj, data, blksz, via->blkcnt); 609167648Sariff 610164614Sariff return (ch->blksz); 611102011Sorion} 612102011Sorion 613193640Sariffstatic uint32_t 614102011Sorionvia8233chan_getptr(kobj_t obj, void *data) 615102011Sorion{ 616102011Sorion struct via_chinfo *ch = data; 617102011Sorion struct via_info *via = ch->parent; 618193640Sariff uint32_t v, index, count, ptr; 619102011Sorion 620150980Snetchild snd_mtxlock(via->lock); 621164614Sariff if (via->polling != 0) { 622164614Sariff ptr = ch->ptr; 623164614Sariff snd_mtxunlock(via->lock); 624164614Sariff } else { 625164614Sariff v = via_rd(via, ch->rbase + VIA_RP_CURRENT_COUNT, 4); 626164614Sariff snd_mtxunlock(via->lock); 627164614Sariff index = v >> 24; /* Last completed buffer */ 628164614Sariff count = v & 0x00ffffff; /* Bytes remaining */ 629164614Sariff ptr = (index + 1) * ch->blksz - count; 630164614Sariff ptr %= ch->blkcnt * ch->blksz; /* Wrap to available space */ 631164614Sariff } 632109863Sorion 633164614Sariff return (ptr); 634102011Sorion} 635102011Sorion 636102011Sorionstatic void 637102011Sorionvia8233chan_reset(struct via_info *via, struct via_chinfo *ch) 638102011Sorion{ 639102011Sorion via_wr(via, ch->rbase + VIA_RP_CONTROL, SGD_CONTROL_STOP, 1); 640102011Sorion via_wr(via, ch->rbase + VIA_RP_CONTROL, 0x00, 1); 641164614Sariff via_wr(via, ch->rbase + VIA_RP_STATUS, 642164614Sariff SGD_STATUS_EOL | SGD_STATUS_FLAG, 1); 643102011Sorion} 644102011Sorion 645111269Sorion/* -------------------------------------------------------------------- */ 646111269Sorion/* Channel initialization functions */ 647111269Sorion 648111269Sorionstatic void 649111269Sorionvia8233chan_sgdinit(struct via_info *via, struct via_chinfo *ch, int chnum) 650111269Sorion{ 651167648Sariff ch->sgd_table = &via->sgd_table[chnum * VIA_SEGS_MAX]; 652167648Sariff ch->sgd_addr = via->sgd_addr + chnum * VIA_SEGS_MAX * 653164614Sariff sizeof(struct via_dma_op); 654111269Sorion} 655111269Sorion 656102011Sorionstatic void* 657111269Sorionvia8233wr_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, 658164614Sariff struct pcm_channel *c, int dir) 659102011Sorion{ 660102011Sorion struct via_info *via = devinfo; 661170137Sariff struct via_chinfo *ch; 662170137Sariff int num; 663102011Sorion 664170137Sariff snd_mtxlock(via->lock); 665170137Sariff num = via->rec_num++; 666170137Sariff ch = &via->rch[num]; 667111269Sorion ch->parent = via; 668111269Sorion ch->channel = c; 669111269Sorion ch->buffer = b; 670111269Sorion ch->dir = dir; 671164614Sariff ch->blkcnt = via->blkcnt; 672170137Sariff ch->rbase = VIA_WR_BASE(num); 673111269Sorion via_wr(via, ch->rbase + VIA_WR_RP_SGD_FORMAT, WR_FIFO_ENABLE, 1); 674148596Snetchild snd_mtxunlock(via->lock); 675111269Sorion 676168847Sariff if (sndbuf_alloc(ch->buffer, via->parent_dmat, 0, via->bufsz) != 0) 677164614Sariff return (NULL); 678148596Snetchild 679148596Snetchild snd_mtxlock(via->lock); 680170137Sariff via8233chan_sgdinit(via, ch, num); 681111269Sorion via8233chan_reset(via, ch); 682148596Snetchild snd_mtxunlock(via->lock); 683111269Sorion 684164614Sariff return (ch); 685111269Sorion} 686111269Sorion 687111269Sorionstatic void* 688111269Sorionvia8233dxs_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, 689164614Sariff struct pcm_channel *c, int dir) 690111269Sorion{ 691111269Sorion struct via_info *via = devinfo; 692170137Sariff struct via_chinfo *ch; 693170137Sariff int num; 694111269Sorion 695170137Sariff snd_mtxlock(via->lock); 696170137Sariff num = via->play_num++; 697170137Sariff ch = &via->pch[num]; 698111197Sorion ch->parent = via; 699111197Sorion ch->channel = c; 700111197Sorion ch->buffer = b; 701111197Sorion ch->dir = dir; 702164614Sariff ch->blkcnt = via->blkcnt; 703111197Sorion 704111269Sorion /* 705111269Sorion * All cards apparently support DXS3, but not other DXS 706111269Sorion * channels. We therefore want to align first DXS channel to 707111269Sorion * DXS3. 708111269Sorion */ 709111269Sorion ch->rbase = VIA_DXS_BASE(NDXSCHANS - 1 - via->n_dxs_registered); 710111269Sorion via->n_dxs_registered++; 711148596Snetchild snd_mtxunlock(via->lock); 712111269Sorion 713168847Sariff if (sndbuf_alloc(ch->buffer, via->parent_dmat, 0, via->bufsz) != 0) 714164614Sariff return (NULL); 715148596Snetchild 716148596Snetchild snd_mtxlock(via->lock); 717170137Sariff via8233chan_sgdinit(via, ch, NWRCHANS + num); 718111269Sorion via8233chan_reset(via, ch); 719148596Snetchild snd_mtxunlock(via->lock); 720102011Sorion 721164614Sariff return (ch); 722111269Sorion} 723111269Sorion 724111269Sorionstatic void* 725111269Sorionvia8233msgd_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, 726164614Sariff struct pcm_channel *c, int dir) 727111269Sorion{ 728111269Sorion struct via_info *via = devinfo; 729170137Sariff struct via_chinfo *ch; 730170137Sariff int num; 731111269Sorion 732170137Sariff snd_mtxlock(via->lock); 733170137Sariff num = via->play_num++; 734170137Sariff ch = &via->pch[num]; 735111269Sorion ch->parent = via; 736111269Sorion ch->channel = c; 737111269Sorion ch->buffer = b; 738111269Sorion ch->dir = dir; 739111269Sorion ch->rbase = VIA_MC_SGD_STATUS; 740164614Sariff ch->blkcnt = via->blkcnt; 741170137Sariff snd_mtxunlock(via->lock); 742111269Sorion 743168847Sariff if (sndbuf_alloc(ch->buffer, via->parent_dmat, 0, via->bufsz) != 0) 744164614Sariff return (NULL); 745148596Snetchild 746148596Snetchild snd_mtxlock(via->lock); 747170137Sariff via8233chan_sgdinit(via, ch, NWRCHANS + num); 748102011Sorion via8233chan_reset(via, ch); 749148596Snetchild snd_mtxunlock(via->lock); 750102011Sorion 751164614Sariff return (ch); 752102011Sorion} 753102011Sorion 754111269Sorionstatic void 755111269Sorionvia8233chan_mute(struct via_info *via, struct via_chinfo *ch, int muted) 756111269Sorion{ 757111269Sorion if (BASE_IS_VIA_DXS_REG(ch->rbase)) { 758111269Sorion int r; 759111269Sorion muted = (muted) ? VIA8233_DXS_MUTE : 0; 760111269Sorion via_wr(via, ch->rbase + VIA8233_RP_DXS_LVOL, muted, 1); 761111269Sorion via_wr(via, ch->rbase + VIA8233_RP_DXS_RVOL, muted, 1); 762164614Sariff r = via_rd(via, ch->rbase + VIA8233_RP_DXS_LVOL, 1) & 763164614Sariff VIA8233_DXS_MUTE; 764167648Sariff if (r != muted) 765167648Sariff device_printf(via->dev, 766167648Sariff "%s: failed to set dxs volume " 767167648Sariff "(dxs base 0x%02x).\n", __func__, ch->rbase); 768111269Sorion } 769111269Sorion} 770111269Sorion 771164614Sariffstatic __inline int 772164614Sariffvia_poll_channel(struct via_chinfo *ch) 773164614Sariff{ 774164614Sariff struct via_info *via; 775164614Sariff uint32_t sz, delta; 776164614Sariff uint32_t v, index, count; 777164614Sariff int ptr; 778164614Sariff 779164614Sariff if (ch == NULL || ch->channel == NULL || ch->active == 0) 780164614Sariff return (0); 781164614Sariff 782164614Sariff via = ch->parent; 783164614Sariff sz = ch->blksz * ch->blkcnt; 784164614Sariff v = via_rd(via, ch->rbase + VIA_RP_CURRENT_COUNT, 4); 785164614Sariff index = v >> 24; 786164614Sariff count = v & 0x00ffffff; 787164614Sariff ptr = ((index + 1) * ch->blksz) - count; 788164614Sariff ptr %= sz; 789164614Sariff ptr &= ~(ch->blksz - 1); 790164614Sariff ch->ptr = ptr; 791164614Sariff delta = (sz + ptr - ch->prevptr) % sz; 792164614Sariff 793164614Sariff if (delta < ch->blksz) 794164614Sariff return (0); 795164614Sariff 796164614Sariff ch->prevptr = ptr; 797164614Sariff 798164614Sariff return (1); 799164614Sariff} 800164614Sariff 801164614Sariffstatic void 802164614Sariffvia_poll_callback(void *arg) 803164614Sariff{ 804164614Sariff struct via_info *via = arg; 805164614Sariff uint32_t ptrigger = 0, rtrigger = 0; 806164614Sariff int i; 807164614Sariff 808164614Sariff if (via == NULL) 809164614Sariff return; 810164614Sariff 811164614Sariff snd_mtxlock(via->lock); 812164614Sariff if (via->polling == 0 || via_chan_active(via) == 0) { 813164614Sariff snd_mtxunlock(via->lock); 814164614Sariff return; 815164614Sariff } 816164614Sariff 817164614Sariff for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++) 818164614Sariff ptrigger |= (via_poll_channel(&via->pch[i]) != 0) ? 819164614Sariff (1 << i) : 0; 820164614Sariff 821164614Sariff for (i = 0; i < NWRCHANS; i++) 822164614Sariff rtrigger |= (via_poll_channel(&via->rch[i]) != 0) ? 823164614Sariff (1 << i) : 0; 824164614Sariff 825164614Sariff /* XXX */ 826164614Sariff callout_reset(&via->poll_timer, 1/*via->poll_ticks*/, 827164614Sariff via_poll_callback, via); 828164614Sariff 829164614Sariff snd_mtxunlock(via->lock); 830164614Sariff 831164614Sariff for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++) { 832164614Sariff if (ptrigger & (1 << i)) 833164614Sariff chn_intr(via->pch[i].channel); 834164614Sariff } 835164614Sariff for (i = 0; i < NWRCHANS; i++) { 836164614Sariff if (rtrigger & (1 << i)) 837164614Sariff chn_intr(via->rch[i].channel); 838164614Sariff } 839164614Sariff} 840164614Sariff 841102011Sorionstatic int 842164614Sariffvia_poll_ticks(struct via_info *via) 843164614Sariff{ 844164614Sariff struct via_chinfo *ch; 845164614Sariff int i; 846164614Sariff int ret = hz; 847164614Sariff int pollticks; 848164614Sariff 849164614Sariff for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++) { 850164614Sariff ch = &via->pch[i]; 851164614Sariff if (ch->channel == NULL || ch->active == 0) 852164614Sariff continue; 853164614Sariff pollticks = ((uint64_t)hz * ch->blksz) / 854193640Sariff ((uint64_t)sndbuf_getalign(ch->buffer) * 855164614Sariff sndbuf_getspd(ch->buffer)); 856164614Sariff pollticks >>= 2; 857164614Sariff if (pollticks > hz) 858164614Sariff pollticks = hz; 859164614Sariff if (pollticks < 1) 860164614Sariff pollticks = 1; 861164614Sariff if (pollticks < ret) 862164614Sariff ret = pollticks; 863164614Sariff } 864164614Sariff 865164614Sariff for (i = 0; i < NWRCHANS; i++) { 866164614Sariff ch = &via->rch[i]; 867164614Sariff if (ch->channel == NULL || ch->active == 0) 868164614Sariff continue; 869164614Sariff pollticks = ((uint64_t)hz * ch->blksz) / 870193640Sariff ((uint64_t)sndbuf_getalign(ch->buffer) * 871164614Sariff sndbuf_getspd(ch->buffer)); 872164614Sariff pollticks >>= 2; 873164614Sariff if (pollticks > hz) 874164614Sariff pollticks = hz; 875164614Sariff if (pollticks < 1) 876164614Sariff pollticks = 1; 877164614Sariff if (pollticks < ret) 878164614Sariff ret = pollticks; 879164614Sariff } 880164614Sariff 881164614Sariff return (ret); 882164614Sariff} 883164614Sariff 884164614Sariffstatic int 885102011Sorionvia8233chan_trigger(kobj_t obj, void* data, int go) 886102011Sorion{ 887102011Sorion struct via_chinfo *ch = data; 888102011Sorion struct via_info *via = ch->parent; 889164614Sariff int pollticks; 890102011Sorion 891170521Sariff if (!PCMTRIG_COMMON(go)) 892170521Sariff return (0); 893170521Sariff 894150980Snetchild snd_mtxlock(via->lock); 895102011Sorion switch(go) { 896102011Sorion case PCMTRIG_START: 897102011Sorion via_buildsgdt(ch); 898111269Sorion via8233chan_mute(via, ch, 0); 899111183Scognet via_wr(via, ch->rbase + VIA_RP_TABLE_PTR, ch->sgd_addr, 4); 900164614Sariff if (via->polling != 0) { 901164614Sariff ch->ptr = 0; 902164614Sariff ch->prevptr = 0; 903164614Sariff pollticks = ((uint64_t)hz * ch->blksz) / 904193640Sariff ((uint64_t)sndbuf_getalign(ch->buffer) * 905164614Sariff sndbuf_getspd(ch->buffer)); 906164614Sariff pollticks >>= 2; 907164614Sariff if (pollticks > hz) 908164614Sariff pollticks = hz; 909164614Sariff if (pollticks < 1) 910164614Sariff pollticks = 1; 911164614Sariff if (via_chan_active(via) == 0 || 912164614Sariff pollticks < via->poll_ticks) { 913164614Sariff if (bootverbose) { 914164614Sariff if (via_chan_active(via) == 0) 915164614Sariff printf("%s: pollticks=%d\n", 916164614Sariff __func__, pollticks); 917164614Sariff else 918164614Sariff printf("%s: " 919164614Sariff "pollticks %d -> %d\n", 920164614Sariff __func__, via->poll_ticks, 921164614Sariff pollticks); 922164614Sariff } 923164614Sariff via->poll_ticks = pollticks; 924164614Sariff callout_reset(&via->poll_timer, 1, 925164614Sariff via_poll_callback, via); 926164614Sariff } 927164614Sariff } 928102011Sorion via_wr(via, ch->rbase + VIA_RP_CONTROL, 929164614Sariff SGD_CONTROL_START | SGD_CONTROL_AUTOSTART | 930164614Sariff ((via->polling == 0) ? 931164614Sariff (SGD_CONTROL_I_EOL | SGD_CONTROL_I_FLAG) : 0), 1); 932164614Sariff ch->active = 1; 933102011Sorion break; 934102011Sorion case PCMTRIG_STOP: 935102011Sorion case PCMTRIG_ABORT: 936102011Sorion via_wr(via, ch->rbase + VIA_RP_CONTROL, SGD_CONTROL_STOP, 1); 937111269Sorion via8233chan_mute(via, ch, 1); 938102011Sorion via8233chan_reset(via, ch); 939164614Sariff ch->active = 0; 940164614Sariff if (via->polling != 0) { 941164614Sariff if (via_chan_active(via) == 0) { 942164614Sariff callout_stop(&via->poll_timer); 943164614Sariff via->poll_ticks = 1; 944164614Sariff } else { 945164614Sariff pollticks = via_poll_ticks(via); 946164614Sariff if (pollticks > via->poll_ticks) { 947164614Sariff if (bootverbose) 948164614Sariff printf("%s: pollticks " 949164614Sariff "%d -> %d\n", 950164614Sariff __func__, via->poll_ticks, 951164614Sariff pollticks); 952164614Sariff via->poll_ticks = pollticks; 953164614Sariff callout_reset(&via->poll_timer, 954164614Sariff 1, via_poll_callback, 955164614Sariff via); 956164614Sariff } 957164614Sariff } 958164614Sariff } 959102011Sorion break; 960164614Sariff default: 961164614Sariff break; 962102011Sorion } 963150980Snetchild snd_mtxunlock(via->lock); 964164614Sariff return (0); 965102011Sorion} 966102011Sorion 967111269Sorionstatic kobj_method_t via8233wr_methods[] = { 968164614Sariff KOBJMETHOD(channel_init, via8233wr_init), 969164614Sariff KOBJMETHOD(channel_setformat, via8233wr_setformat), 970164614Sariff KOBJMETHOD(channel_setspeed, via8233wr_setspeed), 971164614Sariff KOBJMETHOD(channel_getcaps, via8233wr_getcaps), 972164614Sariff KOBJMETHOD(channel_setblocksize, via8233chan_setblocksize), 973167648Sariff KOBJMETHOD(channel_setfragments, via8233chan_setfragments), 974164614Sariff KOBJMETHOD(channel_trigger, via8233chan_trigger), 975164614Sariff KOBJMETHOD(channel_getptr, via8233chan_getptr), 976193640Sariff KOBJMETHOD_END 977102011Sorion}; 978111269SorionCHANNEL_DECLARE(via8233wr); 979102011Sorion 980111269Sorionstatic kobj_method_t via8233dxs_methods[] = { 981164614Sariff KOBJMETHOD(channel_init, via8233dxs_init), 982164614Sariff KOBJMETHOD(channel_setformat, via8233dxs_setformat), 983164614Sariff KOBJMETHOD(channel_setspeed, via8233dxs_setspeed), 984164614Sariff KOBJMETHOD(channel_getcaps, via8233dxs_getcaps), 985164614Sariff KOBJMETHOD(channel_setblocksize, via8233chan_setblocksize), 986167648Sariff KOBJMETHOD(channel_setfragments, via8233chan_setfragments), 987164614Sariff KOBJMETHOD(channel_trigger, via8233chan_trigger), 988164614Sariff KOBJMETHOD(channel_getptr, via8233chan_getptr), 989193640Sariff KOBJMETHOD_END 990102011Sorion}; 991111269SorionCHANNEL_DECLARE(via8233dxs); 992102011Sorion 993111269Sorionstatic kobj_method_t via8233msgd_methods[] = { 994164614Sariff KOBJMETHOD(channel_init, via8233msgd_init), 995164614Sariff KOBJMETHOD(channel_setformat, via8233msgd_setformat), 996164614Sariff KOBJMETHOD(channel_setspeed, via8233msgd_setspeed), 997164614Sariff KOBJMETHOD(channel_getcaps, via8233msgd_getcaps), 998164614Sariff KOBJMETHOD(channel_setblocksize, via8233chan_setblocksize), 999167648Sariff KOBJMETHOD(channel_setfragments, via8233chan_setfragments), 1000164614Sariff KOBJMETHOD(channel_trigger, via8233chan_trigger), 1001164614Sariff KOBJMETHOD(channel_getptr, via8233chan_getptr), 1002193640Sariff KOBJMETHOD_END 1003111269Sorion}; 1004111269SorionCHANNEL_DECLARE(via8233msgd); 1005111269Sorion 1006102011Sorion/* -------------------------------------------------------------------- */ 1007102011Sorion 1008102011Sorionstatic void 1009102011Sorionvia_intr(void *p) 1010102011Sorion{ 1011102011Sorion struct via_info *via = p; 1012164614Sariff uint32_t ptrigger = 0, rtrigger = 0; 1013157956Sariff int i, reg, stat; 1014102011Sorion 1015164614Sariff snd_mtxlock(via->lock); 1016164614Sariff if (via->polling != 0) { 1017164614Sariff snd_mtxunlock(via->lock); 1018164614Sariff return; 1019164614Sariff } 1020111269Sorion /* Poll playback channels */ 1021111269Sorion for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++) { 1022164614Sariff if (via->pch[i].channel == NULL || via->pch[i].active == 0) 1023111269Sorion continue; 1024157956Sariff reg = via->pch[i].rbase + VIA_RP_STATUS; 1025157956Sariff stat = via_rd(via, reg, 1); 1026157956Sariff if (stat & SGD_STATUS_INTR) { 1027157956Sariff if (via->dma_eol_wake && ((stat & SGD_STATUS_EOL) || 1028164614Sariff !(stat & SGD_STATUS_ACTIVE))) 1029164614Sariff via_wr(via, via->pch[i].rbase + VIA_RP_CONTROL, 1030164614Sariff SGD_CONTROL_START | SGD_CONTROL_AUTOSTART | 1031164614Sariff SGD_CONTROL_I_EOL | SGD_CONTROL_I_FLAG, 1); 1032157956Sariff via_wr(via, reg, stat, 1); 1033164614Sariff ptrigger |= 1 << i; 1034111269Sorion } 1035102011Sorion } 1036111269Sorion /* Poll record channels */ 1037111269Sorion for (i = 0; i < NWRCHANS; i++) { 1038164614Sariff if (via->rch[i].channel == NULL || via->rch[i].active == 0) 1039111269Sorion continue; 1040157956Sariff reg = via->rch[i].rbase + VIA_RP_STATUS; 1041157956Sariff stat = via_rd(via, reg, 1); 1042157956Sariff if (stat & SGD_STATUS_INTR) { 1043157956Sariff if (via->dma_eol_wake && ((stat & SGD_STATUS_EOL) || 1044164614Sariff !(stat & SGD_STATUS_ACTIVE))) 1045164614Sariff via_wr(via, via->rch[i].rbase + VIA_RP_CONTROL, 1046164614Sariff SGD_CONTROL_START | SGD_CONTROL_AUTOSTART | 1047164614Sariff SGD_CONTROL_I_EOL | SGD_CONTROL_I_FLAG, 1); 1048157956Sariff via_wr(via, reg, stat, 1); 1049164614Sariff rtrigger |= 1 << i; 1050111269Sorion } 1051111269Sorion } 1052148596Snetchild snd_mtxunlock(via->lock); 1053164614Sariff 1054164614Sariff for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++) { 1055164614Sariff if (ptrigger & (1 << i)) 1056164614Sariff chn_intr(via->pch[i].channel); 1057164614Sariff } 1058164614Sariff for (i = 0; i < NWRCHANS; i++) { 1059164614Sariff if (rtrigger & (1 << i)) 1060164614Sariff chn_intr(via->rch[i].channel); 1061164614Sariff } 1062102011Sorion} 1063102011Sorion 1064102011Sorion/* 1065102011Sorion * Probe and attach the card 1066102011Sorion */ 1067102011Sorionstatic int 1068102011Sorionvia_probe(device_t dev) 1069102011Sorion{ 1070102011Sorion switch(pci_get_devid(dev)) { 1071102011Sorion case VIA8233_PCI_ID: 1072102011Sorion switch(pci_get_revid(dev)) { 1073164614Sariff case VIA8233_REV_ID_8233PRE: 1074102011Sorion device_set_desc(dev, "VIA VT8233 (pre)"); 1075164614Sariff return (BUS_PROBE_DEFAULT); 1076111269Sorion case VIA8233_REV_ID_8233C: 1077102011Sorion device_set_desc(dev, "VIA VT8233C"); 1078164614Sariff return (BUS_PROBE_DEFAULT); 1079111269Sorion case VIA8233_REV_ID_8233: 1080102011Sorion device_set_desc(dev, "VIA VT8233"); 1081164614Sariff return (BUS_PROBE_DEFAULT); 1082111269Sorion case VIA8233_REV_ID_8233A: 1083102011Sorion device_set_desc(dev, "VIA VT8233A"); 1084164614Sariff return (BUS_PROBE_DEFAULT); 1085111269Sorion case VIA8233_REV_ID_8235: 1086102011Sorion device_set_desc(dev, "VIA VT8235"); 1087164614Sariff return (BUS_PROBE_DEFAULT); 1088129758Smatk case VIA8233_REV_ID_8237: 1089129758Smatk device_set_desc(dev, "VIA VT8237"); 1090164614Sariff return (BUS_PROBE_DEFAULT); 1091157956Sariff case VIA8233_REV_ID_8251: 1092157956Sariff device_set_desc(dev, "VIA VT8251"); 1093164614Sariff return (BUS_PROBE_DEFAULT); 1094102011Sorion default: 1095102011Sorion device_set_desc(dev, "VIA VT8233X"); /* Unknown */ 1096164614Sariff return (BUS_PROBE_DEFAULT); 1097164614Sariff } 1098102011Sorion } 1099164614Sariff return (ENXIO); 1100102011Sorion} 1101102011Sorion 1102102011Sorionstatic void 1103102011Soriondma_cb(void *p, bus_dma_segment_t *bds, int a, int b) 1104102011Sorion{ 1105111183Scognet struct via_info *via = (struct via_info *)p; 1106111183Scognet via->sgd_addr = bds->ds_addr; 1107102011Sorion} 1108102011Sorion 1109102011Sorionstatic int 1110102011Sorionvia_chip_init(device_t dev) 1111102011Sorion{ 1112164614Sariff uint32_t data, cnt; 1113102011Sorion 1114113598Sorion /* Wake up and reset AC97 if necessary */ 1115113598Sorion data = pci_read_config(dev, VIA_PCI_ACLINK_STAT, 1); 1116102011Sorion 1117113598Sorion if ((data & VIA_PCI_ACLINK_C00_READY) == 0) { 1118113598Sorion /* Cold reset per ac97r2.3 spec (page 95) */ 1119113598Sorion /* Assert low */ 1120164614Sariff pci_write_config(dev, VIA_PCI_ACLINK_CTRL, 1121164614Sariff VIA_PCI_ACLINK_EN, 1); 1122113598Sorion /* Wait T_rst_low */ 1123164614Sariff DELAY(100); 1124113598Sorion /* Assert high */ 1125164614Sariff pci_write_config(dev, VIA_PCI_ACLINK_CTRL, 1126164614Sariff VIA_PCI_ACLINK_EN | VIA_PCI_ACLINK_NRST, 1); 1127113598Sorion /* Wait T_rst2clk */ 1128113598Sorion DELAY(5); 1129113598Sorion /* Assert low */ 1130164614Sariff pci_write_config(dev, VIA_PCI_ACLINK_CTRL, 1131164614Sariff VIA_PCI_ACLINK_EN, 1); 1132113598Sorion } else { 1133113598Sorion /* Warm reset */ 1134113598Sorion /* Force no sync */ 1135164614Sariff pci_write_config(dev, VIA_PCI_ACLINK_CTRL, 1136164614Sariff VIA_PCI_ACLINK_EN, 1); 1137113598Sorion DELAY(100); 1138113598Sorion /* Sync */ 1139164614Sariff pci_write_config(dev, VIA_PCI_ACLINK_CTRL, 1140164614Sariff VIA_PCI_ACLINK_EN | VIA_PCI_ACLINK_SYNC, 1); 1141113598Sorion /* Wait T_sync_high */ 1142113598Sorion DELAY(5); 1143113598Sorion /* Force no sync */ 1144164614Sariff pci_write_config(dev, VIA_PCI_ACLINK_CTRL, 1145164614Sariff VIA_PCI_ACLINK_EN, 1); 1146113598Sorion /* Wait T_sync2clk */ 1147113598Sorion DELAY(5); 1148113598Sorion } 1149102011Sorion 1150113598Sorion /* Power everything up */ 1151113598Sorion pci_write_config(dev, VIA_PCI_ACLINK_CTRL, VIA_PCI_ACLINK_DESIRED, 1); 1152102011Sorion 1153113598Sorion /* Wait for codec to become ready (largest reported delay 310ms) */ 1154113598Sorion for (cnt = 0; cnt < 2000; cnt++) { 1155113598Sorion data = pci_read_config(dev, VIA_PCI_ACLINK_STAT, 1); 1156164614Sariff if (data & VIA_PCI_ACLINK_C00_READY) 1157164614Sariff return (0); 1158113598Sorion DELAY(5000); 1159102011Sorion } 1160113598Sorion device_printf(dev, "primary codec not ready (cnt = 0x%02x)\n", cnt); 1161164614Sariff return (ENXIO); 1162102011Sorion} 1163102011Sorion 1164102011Sorionstatic int 1165102011Sorionvia_attach(device_t dev) 1166102011Sorion{ 1167102011Sorion struct via_info *via = 0; 1168102011Sorion char status[SND_STATUSLEN]; 1169148596Snetchild int i, via_dxs_disabled, via_dxs_src, via_dxs_chnum, via_sgd_chnum; 1170164614Sariff int nsegs; 1171157956Sariff uint32_t revid; 1172102011Sorion 1173170721Sariff via = malloc(sizeof *via, M_DEVBUF, M_WAITOK | M_ZERO); 1174167608Sariff via->lock = snd_mtxcreate(device_get_nameunit(dev), 1175167608Sariff "snd_via8233 softc"); 1176167648Sariff via->dev = dev; 1177102011Sorion 1178164614Sariff callout_init(&via->poll_timer, CALLOUT_MPSAFE); 1179164614Sariff via->poll_ticks = 1; 1180164614Sariff 1181164614Sariff if (resource_int_value(device_get_name(dev), 1182164614Sariff device_get_unit(dev), "polling", &i) == 0 && i != 0) 1183164614Sariff via->polling = 1; 1184164614Sariff else 1185164614Sariff via->polling = 0; 1186164614Sariff 1187102011Sorion pci_set_powerstate(dev, PCI_POWERSTATE_D0); 1188102011Sorion pci_enable_busmaster(dev); 1189148596Snetchild 1190119690Sjhb via->regid = PCIR_BAR(0); 1191127135Snjl via->reg = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &via->regid, 1192127135Snjl RF_ACTIVE); 1193102011Sorion if (!via->reg) { 1194102011Sorion device_printf(dev, "cannot allocate bus resource."); 1195102011Sorion goto bad; 1196102011Sorion } 1197102011Sorion via->st = rman_get_bustag(via->reg); 1198102011Sorion via->sh = rman_get_bushandle(via->reg); 1199102011Sorion 1200102011Sorion via->irqid = 0; 1201127135Snjl via->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &via->irqid, 1202164614Sariff RF_ACTIVE | RF_SHAREABLE); 1203164614Sariff if (!via->irq || 1204164614Sariff snd_setup_intr(dev, via->irq, INTR_MPSAFE, 1205164614Sariff via_intr, via, &via->ih)) { 1206102011Sorion device_printf(dev, "unable to map interrupt\n"); 1207102011Sorion goto bad; 1208102011Sorion } 1209102011Sorion 1210164614Sariff via->bufsz = pcm_getbuffersize(dev, 4096, VIA_DEFAULT_BUFSZ, 65536); 1211164614Sariff if (resource_int_value(device_get_name(dev), 1212164614Sariff device_get_unit(dev), "blocksize", &i) == 0 && i > 0) { 1213167648Sariff i &= VIA_BLK_ALIGN; 1214167648Sariff if (i < VIA_BLK_MIN) 1215167648Sariff i = VIA_BLK_MIN; 1216164614Sariff via->blkcnt = via->bufsz / i; 1217164614Sariff i = 0; 1218164614Sariff while (via->blkcnt >> i) 1219164614Sariff i++; 1220164614Sariff via->blkcnt = 1 << (i - 1); 1221164614Sariff if (via->blkcnt < VIA_SEGS_MIN) 1222164614Sariff via->blkcnt = VIA_SEGS_MIN; 1223164614Sariff else if (via->blkcnt > VIA_SEGS_MAX) 1224164614Sariff via->blkcnt = VIA_SEGS_MAX; 1225102011Sorion 1226164614Sariff } else 1227164614Sariff via->blkcnt = VIA_SEGS_DEFAULT; 1228102011Sorion 1229157956Sariff revid = pci_get_revid(dev); 1230157956Sariff 1231148596Snetchild /* 1232157956Sariff * VIA8251 lost its interrupt after DMA EOL, and need 1233157956Sariff * a gentle spank on its face within interrupt handler. 1234157956Sariff */ 1235157956Sariff if (revid == VIA8233_REV_ID_8251) 1236157956Sariff via->dma_eol_wake = 1; 1237157956Sariff else 1238157956Sariff via->dma_eol_wake = 0; 1239157956Sariff 1240157956Sariff /* 1241148596Snetchild * Decide whether DXS had to be disabled or not 1242148596Snetchild */ 1243157956Sariff if (revid == VIA8233_REV_ID_8233A) { 1244112671Sorion /* 1245112671Sorion * DXS channel is disabled. Reports from multiple users 1246112671Sorion * that it plays at half-speed. Do not see this behaviour 1247112671Sorion * on available 8233C or when emulating 8233A register set 1248112671Sorion * on 8233C (either with or without ac97 VRA). 1249112671Sorion */ 1250148596Snetchild via_dxs_disabled = 1; 1251148596Snetchild } else if (resource_int_value(device_get_name(dev), 1252164614Sariff device_get_unit(dev), "via_dxs_disabled", 1253164614Sariff &via_dxs_disabled) == 0) 1254148596Snetchild via_dxs_disabled = (via_dxs_disabled > 0) ? 1 : 0; 1255148596Snetchild else 1256148596Snetchild via_dxs_disabled = 0; 1257148596Snetchild 1258148596Snetchild if (via_dxs_disabled) { 1259148596Snetchild via_dxs_chnum = 0; 1260148596Snetchild via_sgd_chnum = 1; 1261111269Sorion } else { 1262148596Snetchild if (resource_int_value(device_get_name(dev), 1263164614Sariff device_get_unit(dev), "via_dxs_channels", 1264164614Sariff &via_dxs_chnum) != 0) 1265148596Snetchild via_dxs_chnum = NDXSCHANS; 1266148596Snetchild if (resource_int_value(device_get_name(dev), 1267164614Sariff device_get_unit(dev), "via_sgd_channels", 1268164614Sariff &via_sgd_chnum) != 0) 1269148596Snetchild via_sgd_chnum = NMSGDCHANS; 1270148596Snetchild } 1271148596Snetchild if (via_dxs_chnum > NDXSCHANS) 1272148596Snetchild via_dxs_chnum = NDXSCHANS; 1273148596Snetchild else if (via_dxs_chnum < 0) 1274148596Snetchild via_dxs_chnum = 0; 1275148596Snetchild if (via_sgd_chnum > NMSGDCHANS) 1276148596Snetchild via_sgd_chnum = NMSGDCHANS; 1277148596Snetchild else if (via_sgd_chnum < 0) 1278148596Snetchild via_sgd_chnum = 0; 1279148596Snetchild if (via_dxs_chnum + via_sgd_chnum < 1) { 1280148596Snetchild /* Minimalist ? */ 1281148596Snetchild via_dxs_chnum = 1; 1282148596Snetchild via_sgd_chnum = 0; 1283148596Snetchild } 1284148596Snetchild if (via_dxs_chnum > 0 && resource_int_value(device_get_name(dev), 1285164614Sariff device_get_unit(dev), "via_dxs_src", &via_dxs_src) == 0) 1286148596Snetchild via->dxs_src = (via_dxs_src > 0) ? 1 : 0; 1287148596Snetchild else 1288148596Snetchild via->dxs_src = 0; 1289164614Sariff 1290167648Sariff nsegs = (via_dxs_chnum + via_sgd_chnum + NWRCHANS) * VIA_SEGS_MAX; 1291164614Sariff 1292164614Sariff /* DMA tag for buffers */ 1293166904Snetchild if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2, 1294166904Snetchild /*boundary*/0, 1295164614Sariff /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 1296164614Sariff /*highaddr*/BUS_SPACE_MAXADDR, 1297164614Sariff /*filter*/NULL, /*filterarg*/NULL, 1298164614Sariff /*maxsize*/via->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff, 1299164614Sariff /*flags*/0, /*lockfunc*/NULL, 1300164614Sariff /*lockarg*/NULL, &via->parent_dmat) != 0) { 1301164614Sariff device_printf(dev, "unable to create dma tag\n"); 1302164614Sariff goto bad; 1303164614Sariff } 1304164614Sariff 1305164614Sariff /* 1306164614Sariff * DMA tag for SGD table. The 686 uses scatter/gather DMA and 1307164614Sariff * requires a list in memory of work to do. We need only 16 bytes 1308164614Sariff * for this list, and it is wasteful to allocate 16K. 1309164614Sariff */ 1310166904Snetchild if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2, 1311166904Snetchild /*boundary*/0, 1312164614Sariff /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 1313164614Sariff /*highaddr*/BUS_SPACE_MAXADDR, 1314164614Sariff /*filter*/NULL, /*filterarg*/NULL, 1315164614Sariff /*maxsize*/nsegs * sizeof(struct via_dma_op), 1316164614Sariff /*nsegments*/1, /*maxsegz*/0x3ffff, 1317164614Sariff /*flags*/0, /*lockfunc*/NULL, 1318164614Sariff /*lockarg*/NULL, &via->sgd_dmat) != 0) { 1319164614Sariff device_printf(dev, "unable to create dma tag\n"); 1320164614Sariff goto bad; 1321164614Sariff } 1322164614Sariff 1323164614Sariff if (bus_dmamem_alloc(via->sgd_dmat, (void **)&via->sgd_table, 1324164614Sariff BUS_DMA_NOWAIT, &via->sgd_dmamap) == -1) 1325164614Sariff goto bad; 1326164614Sariff if (bus_dmamap_load(via->sgd_dmat, via->sgd_dmamap, via->sgd_table, 1327164614Sariff nsegs * sizeof(struct via_dma_op), dma_cb, via, 0)) 1328164614Sariff goto bad; 1329164614Sariff 1330164614Sariff if (via_chip_init(dev)) 1331164614Sariff goto bad; 1332164614Sariff 1333164614Sariff via->codec = AC97_CREATE(dev, via, via_ac97); 1334164614Sariff if (!via->codec) 1335164614Sariff goto bad; 1336164614Sariff 1337164614Sariff mixer_init(dev, ac97_getmixerclass(), via->codec); 1338164614Sariff 1339164614Sariff via->codec_caps = ac97_getextcaps(via->codec); 1340164614Sariff 1341164614Sariff /* Try to set VRA without generating an error, VRM not reqrd yet */ 1342164614Sariff if (via->codec_caps & 1343164614Sariff (AC97_EXTCAP_VRA | AC97_EXTCAP_VRM | AC97_EXTCAP_DRA)) { 1344164614Sariff uint16_t ext = ac97_getextmode(via->codec); 1345164614Sariff ext |= (via->codec_caps & 1346164614Sariff (AC97_EXTCAP_VRA | AC97_EXTCAP_VRM)); 1347164614Sariff ext &= ~AC97_EXTCAP_DRA; 1348164614Sariff ac97_setextmode(via->codec, ext); 1349164614Sariff } 1350164614Sariff 1351164614Sariff snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s", 1352164614Sariff rman_get_start(via->reg), rman_get_start(via->irq), 1353164614Sariff PCM_KLDSTRING(snd_via8233)); 1354164614Sariff 1355148596Snetchild /* Register */ 1356148596Snetchild if (pcm_register(dev, via, via_dxs_chnum + via_sgd_chnum, NWRCHANS)) 1357148596Snetchild goto bad; 1358148596Snetchild for (i = 0; i < via_dxs_chnum; i++) 1359148596Snetchild pcm_addchan(dev, PCMDIR_PLAY, &via8233dxs_class, via); 1360148596Snetchild for (i = 0; i < via_sgd_chnum; i++) 1361148596Snetchild pcm_addchan(dev, PCMDIR_PLAY, &via8233msgd_class, via); 1362148596Snetchild for (i = 0; i < NWRCHANS; i++) 1363148596Snetchild pcm_addchan(dev, PCMDIR_REC, &via8233wr_class, via); 1364148596Snetchild if (via_dxs_chnum > 0) 1365112671Sorion via_init_sysctls(dev); 1366148596Snetchild device_printf(dev, "<VIA DXS %sabled: DXS%s %d / SGD %d / REC %d>\n", 1367164614Sariff (via_dxs_chnum > 0) ? "En" : "Dis", (via->dxs_src) ? "(SRC)" : "", 1368164614Sariff via_dxs_chnum, via_sgd_chnum, NWRCHANS); 1369102011Sorion 1370102011Sorion pcm_setstatus(dev, status); 1371102011Sorion 1372164614Sariff return (0); 1373102011Sorionbad: 1374164614Sariff if (via->codec) 1375164614Sariff ac97_destroy(via->codec); 1376164614Sariff if (via->reg) 1377164614Sariff bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg); 1378164614Sariff if (via->ih) 1379164614Sariff bus_teardown_intr(dev, via->irq, via->ih); 1380164614Sariff if (via->irq) 1381164614Sariff bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq); 1382164614Sariff if (via->parent_dmat) 1383164614Sariff bus_dma_tag_destroy(via->parent_dmat); 1384164614Sariff if (via->sgd_dmamap) 1385164614Sariff bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap); 1386167773Sariff if (via->sgd_table) 1387167773Sariff bus_dmamem_free(via->sgd_dmat, via->sgd_table, via->sgd_dmamap); 1388164614Sariff if (via->sgd_dmat) 1389164614Sariff bus_dma_tag_destroy(via->sgd_dmat); 1390164614Sariff if (via->lock) 1391164614Sariff snd_mtxfree(via->lock); 1392164614Sariff if (via) 1393164614Sariff free(via, M_DEVBUF); 1394164614Sariff return (ENXIO); 1395102011Sorion} 1396102011Sorion 1397102011Sorionstatic int 1398102011Sorionvia_detach(device_t dev) 1399102011Sorion{ 1400102011Sorion int r; 1401170721Sariff struct via_info *via; 1402102011Sorion 1403102011Sorion r = pcm_unregister(dev); 1404164614Sariff if (r) 1405164614Sariff return (r); 1406102011Sorion 1407102011Sorion via = pcm_getdevinfo(dev); 1408170721Sariff 1409170721Sariff if (via != NULL && (via->play_num != 0 || via->rec_num != 0)) { 1410170721Sariff snd_mtxlock(via->lock); 1411170721Sariff via->polling = 0; 1412170721Sariff callout_stop(&via->poll_timer); 1413170721Sariff snd_mtxunlock(via->lock); 1414170721Sariff callout_drain(&via->poll_timer); 1415170721Sariff } 1416170721Sariff 1417102011Sorion bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg); 1418102011Sorion bus_teardown_intr(dev, via->irq, via->ih); 1419102011Sorion bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq); 1420102011Sorion bus_dma_tag_destroy(via->parent_dmat); 1421102011Sorion bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap); 1422167773Sariff bus_dmamem_free(via->sgd_dmat, via->sgd_table, via->sgd_dmamap); 1423102011Sorion bus_dma_tag_destroy(via->sgd_dmat); 1424148596Snetchild snd_mtxfree(via->lock); 1425102011Sorion free(via, M_DEVBUF); 1426164614Sariff return (0); 1427102011Sorion} 1428102011Sorion 1429102011Sorion 1430102011Sorionstatic device_method_t via_methods[] = { 1431102011Sorion DEVMETHOD(device_probe, via_probe), 1432102011Sorion DEVMETHOD(device_attach, via_attach), 1433102011Sorion DEVMETHOD(device_detach, via_detach), 1434102011Sorion { 0, 0} 1435102011Sorion}; 1436102011Sorion 1437102011Sorionstatic driver_t via_driver = { 1438102011Sorion "pcm", 1439102011Sorion via_methods, 1440102011Sorion PCM_SOFTC_SIZE, 1441102011Sorion}; 1442102011Sorion 1443102011SorionDRIVER_MODULE(snd_via8233, pci, via_driver, pcm_devclass, 0, 0); 1444132236StanimuraMODULE_DEPEND(snd_via8233, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 1445102011SorionMODULE_VERSION(snd_via8233, 1); 1446