1/* 2 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF 24 * SUCH DAMAGE. 25 *
| 1/* 2 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF 24 * SUCH DAMAGE. 25 *
|
26 * $FreeBSD: head/sys/dev/sound/pci/t4dwave.c 71503 2001-01-24 01:20:04Z cg $
| 26 * $FreeBSD: head/sys/dev/sound/pci/t4dwave.c 74763 2001-03-24 23:10:29Z cg $
|
27 */ 28 29#include <dev/sound/pcm/sound.h> 30#include <dev/sound/pcm/ac97.h> 31#include <dev/sound/pci/t4dwave.h> 32 33#include <pci/pcireg.h> 34#include <pci/pcivar.h> 35 36/* -------------------------------------------------------------------- */ 37 38#define TDX_PCI_ID 0x20001023 39#define TNX_PCI_ID 0x20011023 40 41#define TR_BUFFSIZE 0x1000 42#define TR_TIMEOUT_CDC 0xffff 43#define TR_MAXPLAYCH 4 44 45struct tr_info; 46 47/* channel registers */ 48struct tr_chinfo { 49 u_int32_t cso, alpha, fms, fmc, ec; 50 u_int32_t lba; 51 u_int32_t eso, delta; 52 u_int32_t rvol, cvol; 53 u_int32_t gvsel, pan, vol, ctrl; 54 int index, bufhalf;
| 27 */ 28 29#include <dev/sound/pcm/sound.h> 30#include <dev/sound/pcm/ac97.h> 31#include <dev/sound/pci/t4dwave.h> 32 33#include <pci/pcireg.h> 34#include <pci/pcivar.h> 35 36/* -------------------------------------------------------------------- */ 37 38#define TDX_PCI_ID 0x20001023 39#define TNX_PCI_ID 0x20011023 40 41#define TR_BUFFSIZE 0x1000 42#define TR_TIMEOUT_CDC 0xffff 43#define TR_MAXPLAYCH 4 44 45struct tr_info; 46 47/* channel registers */ 48struct tr_chinfo { 49 u_int32_t cso, alpha, fms, fmc, ec; 50 u_int32_t lba; 51 u_int32_t eso, delta; 52 u_int32_t rvol, cvol; 53 u_int32_t gvsel, pan, vol, ctrl; 54 int index, bufhalf;
|
55 snd_dbuf *buffer; 56 pcm_channel *channel;
| 55 struct snd_dbuf *buffer; 56 struct pcm_channel *channel;
|
57 struct tr_info *parent; 58}; 59 60struct tr_rchinfo { 61 u_int32_t delta;
| 57 struct tr_info *parent; 58}; 59 60struct tr_rchinfo { 61 u_int32_t delta;
|
62 snd_dbuf *buffer; 63 pcm_channel *channel;
| 62 struct snd_dbuf *buffer; 63 struct pcm_channel *channel;
|
64 struct tr_info *parent; 65}; 66 67/* device private data */ 68struct tr_info { 69 u_int32_t type; 70 71 bus_space_tag_t st; 72 bus_space_handle_t sh; 73 bus_dma_tag_t parent_dmat; 74 75 struct resource *reg, *irq; 76 int regtype, regid, irqid; 77 void *ih; 78
| 64 struct tr_info *parent; 65}; 66 67/* device private data */ 68struct tr_info { 69 u_int32_t type; 70 71 bus_space_tag_t st; 72 bus_space_handle_t sh; 73 bus_dma_tag_t parent_dmat; 74 75 struct resource *reg, *irq; 76 int regtype, regid, irqid; 77 void *ih; 78
|
| 79 void *lock; 80
|
79 u_int32_t playchns; 80 struct tr_chinfo chinfo[TR_MAXPLAYCH]; 81 struct tr_rchinfo recchinfo; 82}; 83 84/* -------------------------------------------------------------------- */ 85 86static u_int32_t tr_recfmt[] = { 87 AFMT_U8, 88 AFMT_STEREO | AFMT_U8, 89 AFMT_S8, 90 AFMT_STEREO | AFMT_S8, 91 AFMT_S16_LE, 92 AFMT_STEREO | AFMT_S16_LE, 93 AFMT_U16_LE, 94 AFMT_STEREO | AFMT_U16_LE, 95 0 96};
| 81 u_int32_t playchns; 82 struct tr_chinfo chinfo[TR_MAXPLAYCH]; 83 struct tr_rchinfo recchinfo; 84}; 85 86/* -------------------------------------------------------------------- */ 87 88static u_int32_t tr_recfmt[] = { 89 AFMT_U8, 90 AFMT_STEREO | AFMT_U8, 91 AFMT_S8, 92 AFMT_STEREO | AFMT_S8, 93 AFMT_S16_LE, 94 AFMT_STEREO | AFMT_S16_LE, 95 AFMT_U16_LE, 96 AFMT_STEREO | AFMT_U16_LE, 97 0 98};
|
97static pcmchan_caps tr_reccaps = {4000, 48000, tr_recfmt, 0};
| 99static struct pcmchan_caps tr_reccaps = {4000, 48000, tr_recfmt, 0};
|
98 99static u_int32_t tr_playfmt[] = { 100 AFMT_U8, 101 AFMT_STEREO | AFMT_U8, 102 AFMT_S8, 103 AFMT_STEREO | AFMT_S8, 104 AFMT_S16_LE, 105 AFMT_STEREO | AFMT_S16_LE, 106 AFMT_U16_LE, 107 AFMT_STEREO | AFMT_U16_LE, 108 0 109};
| 100 101static u_int32_t tr_playfmt[] = { 102 AFMT_U8, 103 AFMT_STEREO | AFMT_U8, 104 AFMT_S8, 105 AFMT_STEREO | AFMT_S8, 106 AFMT_S16_LE, 107 AFMT_STEREO | AFMT_S16_LE, 108 AFMT_U16_LE, 109 AFMT_STEREO | AFMT_U16_LE, 110 0 111};
|
110static pcmchan_caps tr_playcaps = {4000, 48000, tr_playfmt, 0};
| 112static struct pcmchan_caps tr_playcaps = {4000, 48000, tr_playfmt, 0};
|
111 112/* -------------------------------------------------------------------- */ 113 114/* Hardware */ 115 116static u_int32_t 117tr_rd(struct tr_info *tr, int regno, int size) 118{ 119 switch(size) { 120 case 1: 121 return bus_space_read_1(tr->st, tr->sh, regno); 122 case 2: 123 return bus_space_read_2(tr->st, tr->sh, regno); 124 case 4: 125 return bus_space_read_4(tr->st, tr->sh, regno); 126 default: 127 return 0xffffffff; 128 } 129} 130 131static void 132tr_wr(struct tr_info *tr, int regno, u_int32_t data, int size) 133{ 134 switch(size) { 135 case 1: 136 bus_space_write_1(tr->st, tr->sh, regno, data); 137 break; 138 case 2: 139 bus_space_write_2(tr->st, tr->sh, regno, data); 140 break; 141 case 4: 142 bus_space_write_4(tr->st, tr->sh, regno, data); 143 break; 144 } 145} 146 147/* -------------------------------------------------------------------- */ 148/* ac97 codec */ 149 150static int 151tr_rdcd(kobj_t obj, void *devinfo, int regno) 152{ 153 struct tr_info *tr = (struct tr_info *)devinfo; 154 int i, j, treg, trw; 155 156 switch (tr->type) { 157 case TDX_PCI_ID: 158 treg=TDX_REG_CODECRD; 159 trw=TDX_CDC_RWSTAT; 160 break; 161 case TNX_PCI_ID: 162 treg=(regno & 0x100)? TNX_REG_CODEC2RD : TNX_REG_CODEC1RD; 163 trw=TNX_CDC_RWSTAT; 164 break; 165 default: 166 printf("!!! tr_rdcd defaulted !!!\n"); 167 return -1; 168 } 169 170 regno &= 0x7f;
| 113 114/* -------------------------------------------------------------------- */ 115 116/* Hardware */ 117 118static u_int32_t 119tr_rd(struct tr_info *tr, int regno, int size) 120{ 121 switch(size) { 122 case 1: 123 return bus_space_read_1(tr->st, tr->sh, regno); 124 case 2: 125 return bus_space_read_2(tr->st, tr->sh, regno); 126 case 4: 127 return bus_space_read_4(tr->st, tr->sh, regno); 128 default: 129 return 0xffffffff; 130 } 131} 132 133static void 134tr_wr(struct tr_info *tr, int regno, u_int32_t data, int size) 135{ 136 switch(size) { 137 case 1: 138 bus_space_write_1(tr->st, tr->sh, regno, data); 139 break; 140 case 2: 141 bus_space_write_2(tr->st, tr->sh, regno, data); 142 break; 143 case 4: 144 bus_space_write_4(tr->st, tr->sh, regno, data); 145 break; 146 } 147} 148 149/* -------------------------------------------------------------------- */ 150/* ac97 codec */ 151 152static int 153tr_rdcd(kobj_t obj, void *devinfo, int regno) 154{ 155 struct tr_info *tr = (struct tr_info *)devinfo; 156 int i, j, treg, trw; 157 158 switch (tr->type) { 159 case TDX_PCI_ID: 160 treg=TDX_REG_CODECRD; 161 trw=TDX_CDC_RWSTAT; 162 break; 163 case TNX_PCI_ID: 164 treg=(regno & 0x100)? TNX_REG_CODEC2RD : TNX_REG_CODEC1RD; 165 trw=TNX_CDC_RWSTAT; 166 break; 167 default: 168 printf("!!! tr_rdcd defaulted !!!\n"); 169 return -1; 170 } 171 172 regno &= 0x7f;
|
| 173 snd_mtxlock(tr->lock);
|
171 tr_wr(tr, treg, regno | trw, 4); 172 j=trw; 173 for (i=TR_TIMEOUT_CDC; (i > 0) && (j & trw); i--) j=tr_rd(tr, treg, 4);
| 174 tr_wr(tr, treg, regno | trw, 4); 175 j=trw; 176 for (i=TR_TIMEOUT_CDC; (i > 0) && (j & trw); i--) j=tr_rd(tr, treg, 4);
|
| 177 snd_mtxunlock(tr->lock);
|
174 if (i == 0) printf("codec timeout during read of register %x\n", regno); 175 return (j >> TR_CDC_DATA) & 0xffff; 176} 177 178static int 179tr_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data) 180{ 181 struct tr_info *tr = (struct tr_info *)devinfo; 182 int i, j, treg, trw; 183 184 switch (tr->type) { 185 case TDX_PCI_ID: 186 treg=TDX_REG_CODECWR; 187 trw=TDX_CDC_RWSTAT; 188 break; 189 case TNX_PCI_ID: 190 treg=TNX_REG_CODECWR; 191 trw=TNX_CDC_RWSTAT | ((regno & 0x100)? TNX_CDC_SEC : 0); 192 break; 193 default: 194 printf("!!! tr_wrcd defaulted !!!"); 195 return -1; 196 } 197 198 regno &= 0x7f; 199#if 0 200 printf("tr_wrcd: reg %x was %x", regno, tr_rdcd(devinfo, regno)); 201#endif 202 j=trw;
| 178 if (i == 0) printf("codec timeout during read of register %x\n", regno); 179 return (j >> TR_CDC_DATA) & 0xffff; 180} 181 182static int 183tr_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data) 184{ 185 struct tr_info *tr = (struct tr_info *)devinfo; 186 int i, j, treg, trw; 187 188 switch (tr->type) { 189 case TDX_PCI_ID: 190 treg=TDX_REG_CODECWR; 191 trw=TDX_CDC_RWSTAT; 192 break; 193 case TNX_PCI_ID: 194 treg=TNX_REG_CODECWR; 195 trw=TNX_CDC_RWSTAT | ((regno & 0x100)? TNX_CDC_SEC : 0); 196 break; 197 default: 198 printf("!!! tr_wrcd defaulted !!!"); 199 return -1; 200 } 201 202 regno &= 0x7f; 203#if 0 204 printf("tr_wrcd: reg %x was %x", regno, tr_rdcd(devinfo, regno)); 205#endif 206 j=trw;
|
| 207 snd_mtxlock(tr->lock);
|
203 for (i=TR_TIMEOUT_CDC; (i>0) && (j & trw); i--) j=tr_rd(tr, treg, 4); 204 tr_wr(tr, treg, (data << TR_CDC_DATA) | regno | trw, 4); 205#if 0 206 printf(" - wrote %x, now %x\n", data, tr_rdcd(devinfo, regno)); 207#endif
| 208 for (i=TR_TIMEOUT_CDC; (i>0) && (j & trw); i--) j=tr_rd(tr, treg, 4); 209 tr_wr(tr, treg, (data << TR_CDC_DATA) | regno | trw, 4); 210#if 0 211 printf(" - wrote %x, now %x\n", data, tr_rdcd(devinfo, regno)); 212#endif
|
| 213 snd_mtxunlock(tr->lock);
|
208 if (i==0) printf("codec timeout writing %x, data %x\n", regno, data); 209 return (i > 0)? 0 : -1; 210} 211 212static kobj_method_t tr_ac97_methods[] = { 213 KOBJMETHOD(ac97_read, tr_rdcd), 214 KOBJMETHOD(ac97_write, tr_wrcd), 215 { 0, 0 } 216}; 217AC97_DECLARE(tr_ac97); 218 219/* -------------------------------------------------------------------- */ 220/* playback channel interrupts */ 221 222#if 0 223static u_int32_t 224tr_testint(struct tr_chinfo *ch) 225{ 226 struct tr_info *tr = ch->parent; 227 int bank, chan; 228 229 bank = (ch->index & 0x20) ? 1 : 0; 230 chan = ch->index & 0x1f; 231 return tr_rd(tr, bank? TR_REG_ADDRINTB : TR_REG_ADDRINTA, 4) & (1 << chan); 232} 233#endif 234 235static void 236tr_clrint(struct tr_chinfo *ch) 237{ 238 struct tr_info *tr = ch->parent; 239 int bank, chan; 240 241 bank = (ch->index & 0x20) ? 1 : 0; 242 chan = ch->index & 0x1f; 243 tr_wr(tr, bank? TR_REG_ADDRINTB : TR_REG_ADDRINTA, 1 << chan, 4); 244} 245 246static void 247tr_enaint(struct tr_chinfo *ch, int enable) 248{ 249 struct tr_info *tr = ch->parent; 250 u_int32_t i, reg; 251 int bank, chan; 252
| 214 if (i==0) printf("codec timeout writing %x, data %x\n", regno, data); 215 return (i > 0)? 0 : -1; 216} 217 218static kobj_method_t tr_ac97_methods[] = { 219 KOBJMETHOD(ac97_read, tr_rdcd), 220 KOBJMETHOD(ac97_write, tr_wrcd), 221 { 0, 0 } 222}; 223AC97_DECLARE(tr_ac97); 224 225/* -------------------------------------------------------------------- */ 226/* playback channel interrupts */ 227 228#if 0 229static u_int32_t 230tr_testint(struct tr_chinfo *ch) 231{ 232 struct tr_info *tr = ch->parent; 233 int bank, chan; 234 235 bank = (ch->index & 0x20) ? 1 : 0; 236 chan = ch->index & 0x1f; 237 return tr_rd(tr, bank? TR_REG_ADDRINTB : TR_REG_ADDRINTA, 4) & (1 << chan); 238} 239#endif 240 241static void 242tr_clrint(struct tr_chinfo *ch) 243{ 244 struct tr_info *tr = ch->parent; 245 int bank, chan; 246 247 bank = (ch->index & 0x20) ? 1 : 0; 248 chan = ch->index & 0x1f; 249 tr_wr(tr, bank? TR_REG_ADDRINTB : TR_REG_ADDRINTA, 1 << chan, 4); 250} 251 252static void 253tr_enaint(struct tr_chinfo *ch, int enable) 254{ 255 struct tr_info *tr = ch->parent; 256 u_int32_t i, reg; 257 int bank, chan; 258
|
| 259 snd_mtxlock(tr->lock);
|
253 bank = (ch->index & 0x20) ? 1 : 0; 254 chan = ch->index & 0x1f; 255 reg = bank? TR_REG_INTENB : TR_REG_INTENA; 256 257 i = tr_rd(tr, reg, 4); 258 i &= ~(1 << chan); 259 i |= (enable? 1 : 0) << chan; 260 261 tr_clrint(ch); 262 tr_wr(tr, reg, i, 4);
| 260 bank = (ch->index & 0x20) ? 1 : 0; 261 chan = ch->index & 0x1f; 262 reg = bank? TR_REG_INTENB : TR_REG_INTENA; 263 264 i = tr_rd(tr, reg, 4); 265 i &= ~(1 << chan); 266 i |= (enable? 1 : 0) << chan; 267 268 tr_clrint(ch); 269 tr_wr(tr, reg, i, 4);
|
| 270 snd_mtxunlock(tr->lock);
|
263} 264 265/* playback channels */ 266 267static void 268tr_selch(struct tr_chinfo *ch) 269{ 270 struct tr_info *tr = ch->parent; 271 int i; 272 273 i = tr_rd(tr, TR_REG_CIR, 4); 274 i &= ~TR_CIR_MASK; 275 i |= ch->index & 0x3f; 276 tr_wr(tr, TR_REG_CIR, i, 4); 277} 278 279static void 280tr_startch(struct tr_chinfo *ch) 281{ 282 struct tr_info *tr = ch->parent; 283 int bank, chan; 284 285 bank = (ch->index & 0x20) ? 1 : 0; 286 chan = ch->index & 0x1f; 287 tr_wr(tr, bank? TR_REG_STARTB : TR_REG_STARTA, 1 << chan, 4); 288} 289 290static void 291tr_stopch(struct tr_chinfo *ch) 292{ 293 struct tr_info *tr = ch->parent; 294 int bank, chan; 295 296 bank = (ch->index & 0x20) ? 1 : 0; 297 chan = ch->index & 0x1f; 298 tr_wr(tr, bank? TR_REG_STOPB : TR_REG_STOPA, 1 << chan, 4); 299} 300 301static void 302tr_wrch(struct tr_chinfo *ch) 303{ 304 struct tr_info *tr = ch->parent; 305 u_int32_t cr[TR_CHN_REGS], i; 306 307 ch->gvsel &= 0x00000001; 308 ch->fmc &= 0x00000003; 309 ch->fms &= 0x0000000f; 310 ch->ctrl &= 0x0000000f; 311 ch->pan &= 0x0000007f; 312 ch->rvol &= 0x0000007f; 313 ch->cvol &= 0x0000007f; 314 ch->vol &= 0x000000ff; 315 ch->ec &= 0x00000fff; 316 ch->alpha &= 0x00000fff; 317 ch->delta &= 0x0000ffff; 318 ch->lba &= 0x3fffffff; 319 320 cr[1]=ch->lba; 321 cr[3]=(ch->fmc<<14) | (ch->rvol<<7) | (ch->cvol); 322 cr[4]=(ch->gvsel<<31) | (ch->pan<<24) | (ch->vol<<16) | (ch->ctrl<<12) | (ch->ec); 323 324 switch (tr->type) { 325 case TDX_PCI_ID: 326 ch->cso &= 0x0000ffff; 327 ch->eso &= 0x0000ffff; 328 cr[0]=(ch->cso<<16) | (ch->alpha<<4) | (ch->fms); 329 cr[2]=(ch->eso<<16) | (ch->delta); 330 break; 331 case TNX_PCI_ID: 332 ch->cso &= 0x00ffffff; 333 ch->eso &= 0x00ffffff; 334 cr[0]=((ch->delta & 0xff)<<24) | (ch->cso); 335 cr[2]=((ch->delta>>16)<<24) | (ch->eso); 336 cr[3]|=(ch->alpha<<20) | (ch->fms<<16) | (ch->fmc<<14); 337 break; 338 }
| 271} 272 273/* playback channels */ 274 275static void 276tr_selch(struct tr_chinfo *ch) 277{ 278 struct tr_info *tr = ch->parent; 279 int i; 280 281 i = tr_rd(tr, TR_REG_CIR, 4); 282 i &= ~TR_CIR_MASK; 283 i |= ch->index & 0x3f; 284 tr_wr(tr, TR_REG_CIR, i, 4); 285} 286 287static void 288tr_startch(struct tr_chinfo *ch) 289{ 290 struct tr_info *tr = ch->parent; 291 int bank, chan; 292 293 bank = (ch->index & 0x20) ? 1 : 0; 294 chan = ch->index & 0x1f; 295 tr_wr(tr, bank? TR_REG_STARTB : TR_REG_STARTA, 1 << chan, 4); 296} 297 298static void 299tr_stopch(struct tr_chinfo *ch) 300{ 301 struct tr_info *tr = ch->parent; 302 int bank, chan; 303 304 bank = (ch->index & 0x20) ? 1 : 0; 305 chan = ch->index & 0x1f; 306 tr_wr(tr, bank? TR_REG_STOPB : TR_REG_STOPA, 1 << chan, 4); 307} 308 309static void 310tr_wrch(struct tr_chinfo *ch) 311{ 312 struct tr_info *tr = ch->parent; 313 u_int32_t cr[TR_CHN_REGS], i; 314 315 ch->gvsel &= 0x00000001; 316 ch->fmc &= 0x00000003; 317 ch->fms &= 0x0000000f; 318 ch->ctrl &= 0x0000000f; 319 ch->pan &= 0x0000007f; 320 ch->rvol &= 0x0000007f; 321 ch->cvol &= 0x0000007f; 322 ch->vol &= 0x000000ff; 323 ch->ec &= 0x00000fff; 324 ch->alpha &= 0x00000fff; 325 ch->delta &= 0x0000ffff; 326 ch->lba &= 0x3fffffff; 327 328 cr[1]=ch->lba; 329 cr[3]=(ch->fmc<<14) | (ch->rvol<<7) | (ch->cvol); 330 cr[4]=(ch->gvsel<<31) | (ch->pan<<24) | (ch->vol<<16) | (ch->ctrl<<12) | (ch->ec); 331 332 switch (tr->type) { 333 case TDX_PCI_ID: 334 ch->cso &= 0x0000ffff; 335 ch->eso &= 0x0000ffff; 336 cr[0]=(ch->cso<<16) | (ch->alpha<<4) | (ch->fms); 337 cr[2]=(ch->eso<<16) | (ch->delta); 338 break; 339 case TNX_PCI_ID: 340 ch->cso &= 0x00ffffff; 341 ch->eso &= 0x00ffffff; 342 cr[0]=((ch->delta & 0xff)<<24) | (ch->cso); 343 cr[2]=((ch->delta>>16)<<24) | (ch->eso); 344 cr[3]|=(ch->alpha<<20) | (ch->fms<<16) | (ch->fmc<<14); 345 break; 346 }
|
| 347 snd_mtxlock(tr->lock);
|
339 tr_selch(ch); 340 for (i=0; i<TR_CHN_REGS; i++) 341 tr_wr(tr, TR_REG_CHNBASE+(i<<2), cr[i], 4);
| 348 tr_selch(ch); 349 for (i=0; i<TR_CHN_REGS; i++) 350 tr_wr(tr, TR_REG_CHNBASE+(i<<2), cr[i], 4);
|
| 351 snd_mtxunlock(tr->lock);
|
342} 343 344static void 345tr_rdch(struct tr_chinfo *ch) 346{ 347 struct tr_info *tr = ch->parent; 348 u_int32_t cr[5], i; 349
| 352} 353 354static void 355tr_rdch(struct tr_chinfo *ch) 356{ 357 struct tr_info *tr = ch->parent; 358 u_int32_t cr[5], i; 359
|
| 360 snd_mtxlock(tr->lock);
|
350 tr_selch(ch); 351 for (i=0; i<5; i++) 352 cr[i]=tr_rd(tr, TR_REG_CHNBASE+(i<<2), 4);
| 361 tr_selch(ch); 362 for (i=0; i<5; i++) 363 cr[i]=tr_rd(tr, TR_REG_CHNBASE+(i<<2), 4);
|
| 364 snd_mtxunlock(tr->lock);
|
353 354 355 ch->lba= (cr[1] & 0x3fffffff); 356 ch->fmc= (cr[3] & 0x0000c000) >> 14; 357 ch->rvol= (cr[3] & 0x00003f80) >> 7; 358 ch->cvol= (cr[3] & 0x0000007f); 359 ch->gvsel= (cr[4] & 0x80000000) >> 31; 360 ch->pan= (cr[4] & 0x7f000000) >> 24; 361 ch->vol= (cr[4] & 0x00ff0000) >> 16; 362 ch->ctrl= (cr[4] & 0x0000f000) >> 12; 363 ch->ec= (cr[4] & 0x00000fff); 364 switch(tr->type) { 365 case TDX_PCI_ID: 366 ch->cso= (cr[0] & 0xffff0000) >> 16; 367 ch->alpha= (cr[0] & 0x0000fff0) >> 4; 368 ch->fms= (cr[0] & 0x0000000f); 369 ch->eso= (cr[2] & 0xffff0000) >> 16; 370 ch->delta= (cr[2] & 0x0000ffff); 371 break; 372 case TNX_PCI_ID: 373 ch->cso= (cr[0] & 0x00ffffff); 374 ch->eso= (cr[2] & 0x00ffffff); 375 ch->delta= ((cr[2] & 0xff000000) >> 16) | ((cr[0] & 0xff000000) >> 24); 376 ch->alpha= (cr[3] & 0xfff00000) >> 20; 377 ch->fms= (cr[3] & 0x000f0000) >> 16; 378 break; 379 } 380} 381 382static u_int32_t 383tr_fmttobits(u_int32_t fmt) 384{ 385 u_int32_t bits; 386 387 bits = 0; 388 bits |= (fmt & AFMT_SIGNED)? 0x2 : 0; 389 bits |= (fmt & AFMT_STEREO)? 0x4 : 0; 390 bits |= (fmt & AFMT_16BIT)? 0x8 : 0; 391 392 return bits; 393} 394 395/* -------------------------------------------------------------------- */ 396/* channel interface */ 397 398static void *
| 365 366 367 ch->lba= (cr[1] & 0x3fffffff); 368 ch->fmc= (cr[3] & 0x0000c000) >> 14; 369 ch->rvol= (cr[3] & 0x00003f80) >> 7; 370 ch->cvol= (cr[3] & 0x0000007f); 371 ch->gvsel= (cr[4] & 0x80000000) >> 31; 372 ch->pan= (cr[4] & 0x7f000000) >> 24; 373 ch->vol= (cr[4] & 0x00ff0000) >> 16; 374 ch->ctrl= (cr[4] & 0x0000f000) >> 12; 375 ch->ec= (cr[4] & 0x00000fff); 376 switch(tr->type) { 377 case TDX_PCI_ID: 378 ch->cso= (cr[0] & 0xffff0000) >> 16; 379 ch->alpha= (cr[0] & 0x0000fff0) >> 4; 380 ch->fms= (cr[0] & 0x0000000f); 381 ch->eso= (cr[2] & 0xffff0000) >> 16; 382 ch->delta= (cr[2] & 0x0000ffff); 383 break; 384 case TNX_PCI_ID: 385 ch->cso= (cr[0] & 0x00ffffff); 386 ch->eso= (cr[2] & 0x00ffffff); 387 ch->delta= ((cr[2] & 0xff000000) >> 16) | ((cr[0] & 0xff000000) >> 24); 388 ch->alpha= (cr[3] & 0xfff00000) >> 20; 389 ch->fms= (cr[3] & 0x000f0000) >> 16; 390 break; 391 } 392} 393 394static u_int32_t 395tr_fmttobits(u_int32_t fmt) 396{ 397 u_int32_t bits; 398 399 bits = 0; 400 bits |= (fmt & AFMT_SIGNED)? 0x2 : 0; 401 bits |= (fmt & AFMT_STEREO)? 0x4 : 0; 402 bits |= (fmt & AFMT_16BIT)? 0x8 : 0; 403 404 return bits; 405} 406 407/* -------------------------------------------------------------------- */ 408/* channel interface */ 409 410static void *
|
399trpchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
| 411trpchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
|
400{ 401 struct tr_info *tr = devinfo; 402 struct tr_chinfo *ch; 403 404 KASSERT(dir == PCMDIR_PLAY, ("trpchan_init: bad direction")); 405 ch = &tr->chinfo[tr->playchns]; 406 ch->index = tr->playchns++; 407 ch->buffer = b; 408 ch->parent = tr; 409 ch->channel = c; 410 if (sndbuf_alloc(ch->buffer, tr->parent_dmat, TR_BUFFSIZE) == -1) 411 return NULL; 412 413 return ch; 414} 415 416static int 417trpchan_setformat(kobj_t obj, void *data, u_int32_t format) 418{ 419 struct tr_chinfo *ch = data; 420 421 ch->ctrl = tr_fmttobits(format) | 0x01; 422 423 return 0; 424} 425 426static int 427trpchan_setspeed(kobj_t obj, void *data, u_int32_t speed) 428{ 429 struct tr_chinfo *ch = data; 430 431 ch->delta = (speed << 12) / 48000; 432 return (ch->delta * 48000) >> 12; 433} 434 435static int 436trpchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 437{ 438 struct tr_chinfo *ch = data; 439 440 sndbuf_resize(ch->buffer, 2, blocksize); 441 return blocksize; 442} 443 444static int 445trpchan_trigger(kobj_t obj, void *data, int go) 446{ 447 struct tr_chinfo *ch = data; 448 449 if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) 450 return 0; 451 452 if (go == PCMTRIG_START) { 453 ch->fmc = 3; 454 ch->fms = 0; 455 ch->ec = 0; 456 ch->alpha = 0; 457 ch->lba = vtophys(sndbuf_getbuf(ch->buffer)); 458 ch->cso = 0; 459 ch->eso = (sndbuf_getsize(ch->buffer) / sndbuf_getbps(ch->buffer)) - 1; 460 ch->rvol = ch->cvol = 0x7f; 461 ch->gvsel = 0; 462 ch->pan = 0; 463 ch->vol = 0; 464 ch->bufhalf = 0; 465 tr_wrch(ch); 466 tr_enaint(ch, 1); 467 tr_startch(ch); 468 } else 469 tr_stopch(ch); 470 471 return 0; 472} 473 474static int 475trpchan_getptr(kobj_t obj, void *data) 476{ 477 struct tr_chinfo *ch = data; 478 479 tr_rdch(ch); 480 return ch->cso * sndbuf_getbps(ch->buffer); 481} 482
| 412{ 413 struct tr_info *tr = devinfo; 414 struct tr_chinfo *ch; 415 416 KASSERT(dir == PCMDIR_PLAY, ("trpchan_init: bad direction")); 417 ch = &tr->chinfo[tr->playchns]; 418 ch->index = tr->playchns++; 419 ch->buffer = b; 420 ch->parent = tr; 421 ch->channel = c; 422 if (sndbuf_alloc(ch->buffer, tr->parent_dmat, TR_BUFFSIZE) == -1) 423 return NULL; 424 425 return ch; 426} 427 428static int 429trpchan_setformat(kobj_t obj, void *data, u_int32_t format) 430{ 431 struct tr_chinfo *ch = data; 432 433 ch->ctrl = tr_fmttobits(format) | 0x01; 434 435 return 0; 436} 437 438static int 439trpchan_setspeed(kobj_t obj, void *data, u_int32_t speed) 440{ 441 struct tr_chinfo *ch = data; 442 443 ch->delta = (speed << 12) / 48000; 444 return (ch->delta * 48000) >> 12; 445} 446 447static int 448trpchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 449{ 450 struct tr_chinfo *ch = data; 451 452 sndbuf_resize(ch->buffer, 2, blocksize); 453 return blocksize; 454} 455 456static int 457trpchan_trigger(kobj_t obj, void *data, int go) 458{ 459 struct tr_chinfo *ch = data; 460 461 if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) 462 return 0; 463 464 if (go == PCMTRIG_START) { 465 ch->fmc = 3; 466 ch->fms = 0; 467 ch->ec = 0; 468 ch->alpha = 0; 469 ch->lba = vtophys(sndbuf_getbuf(ch->buffer)); 470 ch->cso = 0; 471 ch->eso = (sndbuf_getsize(ch->buffer) / sndbuf_getbps(ch->buffer)) - 1; 472 ch->rvol = ch->cvol = 0x7f; 473 ch->gvsel = 0; 474 ch->pan = 0; 475 ch->vol = 0; 476 ch->bufhalf = 0; 477 tr_wrch(ch); 478 tr_enaint(ch, 1); 479 tr_startch(ch); 480 } else 481 tr_stopch(ch); 482 483 return 0; 484} 485 486static int 487trpchan_getptr(kobj_t obj, void *data) 488{ 489 struct tr_chinfo *ch = data; 490 491 tr_rdch(ch); 492 return ch->cso * sndbuf_getbps(ch->buffer); 493} 494
|
483static pcmchan_caps *
| 495static struct pcmchan_caps *
|
484trpchan_getcaps(kobj_t obj, void *data) 485{ 486 return &tr_playcaps; 487} 488 489static kobj_method_t trpchan_methods[] = { 490 KOBJMETHOD(channel_init, trpchan_init), 491 KOBJMETHOD(channel_setformat, trpchan_setformat), 492 KOBJMETHOD(channel_setspeed, trpchan_setspeed), 493 KOBJMETHOD(channel_setblocksize, trpchan_setblocksize), 494 KOBJMETHOD(channel_trigger, trpchan_trigger), 495 KOBJMETHOD(channel_getptr, trpchan_getptr), 496 KOBJMETHOD(channel_getcaps, trpchan_getcaps), 497 { 0, 0 } 498}; 499CHANNEL_DECLARE(trpchan); 500 501/* -------------------------------------------------------------------- */ 502/* rec channel interface */ 503 504static void *
| 496trpchan_getcaps(kobj_t obj, void *data) 497{ 498 return &tr_playcaps; 499} 500 501static kobj_method_t trpchan_methods[] = { 502 KOBJMETHOD(channel_init, trpchan_init), 503 KOBJMETHOD(channel_setformat, trpchan_setformat), 504 KOBJMETHOD(channel_setspeed, trpchan_setspeed), 505 KOBJMETHOD(channel_setblocksize, trpchan_setblocksize), 506 KOBJMETHOD(channel_trigger, trpchan_trigger), 507 KOBJMETHOD(channel_getptr, trpchan_getptr), 508 KOBJMETHOD(channel_getcaps, trpchan_getcaps), 509 { 0, 0 } 510}; 511CHANNEL_DECLARE(trpchan); 512 513/* -------------------------------------------------------------------- */ 514/* rec channel interface */ 515 516static void *
|
505trrchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
| 517trrchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
|
506{ 507 struct tr_info *tr = devinfo; 508 struct tr_rchinfo *ch; 509 510 KASSERT(dir == PCMDIR_REC, ("trrchan_init: bad direction")); 511 ch = &tr->recchinfo; 512 ch->buffer = b; 513 ch->parent = tr; 514 ch->channel = c; 515 if (sndbuf_alloc(ch->buffer, tr->parent_dmat, TR_BUFFSIZE) == -1) 516 return NULL; 517 518 return ch; 519} 520 521static int 522trrchan_setformat(kobj_t obj, void *data, u_int32_t format) 523{ 524 struct tr_rchinfo *ch = data; 525 struct tr_info *tr = ch->parent; 526 u_int32_t i, bits; 527 528 bits = tr_fmttobits(format); 529 /* set # of samples between interrupts */ 530 i = (sndbuf_runsz(ch->buffer) >> ((bits & 0x08)? 1 : 0)) - 1; 531 tr_wr(tr, TR_REG_SBBL, i | (i << 16), 4); 532 /* set sample format */ 533 i = 0x18 | (bits << 4); 534 tr_wr(tr, TR_REG_SBCTRL, i, 1); 535 536 return 0; 537 538} 539 540static int 541trrchan_setspeed(kobj_t obj, void *data, u_int32_t speed) 542{ 543 struct tr_rchinfo *ch = data; 544 struct tr_info *tr = ch->parent; 545 546 /* setup speed */ 547 ch->delta = (48000 << 12) / speed; 548 tr_wr(tr, TR_REG_SBDELTA, ch->delta, 2); 549 550 /* return closest possible speed */ 551 return (48000 << 12) / ch->delta; 552} 553 554static int 555trrchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 556{ 557 struct tr_rchinfo *ch = data; 558 559 sndbuf_resize(ch->buffer, 2, blocksize); 560 561 return blocksize; 562} 563 564static int 565trrchan_trigger(kobj_t obj, void *data, int go) 566{ 567 struct tr_rchinfo *ch = data; 568 struct tr_info *tr = ch->parent; 569 u_int32_t i; 570 571 if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) 572 return 0; 573 574 if (go == PCMTRIG_START) { 575 /* set up dma mode regs */ 576 tr_wr(tr, TR_REG_DMAR15, 0, 1); 577 i = tr_rd(tr, TR_REG_DMAR11, 1) & 0x03; 578 tr_wr(tr, TR_REG_DMAR11, i | 0x54, 1); 579 /* set up base address */ 580 tr_wr(tr, TR_REG_DMAR0, vtophys(sndbuf_getbuf(ch->buffer)), 4); 581 /* set up buffer size */ 582 i = tr_rd(tr, TR_REG_DMAR4, 4) & ~0x00ffffff; 583 tr_wr(tr, TR_REG_DMAR4, i | (sndbuf_runsz(ch->buffer) - 1), 4); 584 /* start */ 585 tr_wr(tr, TR_REG_SBCTRL, tr_rd(tr, TR_REG_SBCTRL, 1) | 1, 1); 586 } else 587 tr_wr(tr, TR_REG_SBCTRL, tr_rd(tr, TR_REG_SBCTRL, 1) & ~7, 1); 588 589 /* return 0 if ok */ 590 return 0; 591} 592 593static int 594trrchan_getptr(kobj_t obj, void *data) 595{ 596 struct tr_rchinfo *ch = data; 597 struct tr_info *tr = ch->parent; 598 599 /* return current byte offset of channel */ 600 return tr_rd(tr, TR_REG_DMAR0, 4) - vtophys(sndbuf_getbuf(ch->buffer)); 601} 602
| 518{ 519 struct tr_info *tr = devinfo; 520 struct tr_rchinfo *ch; 521 522 KASSERT(dir == PCMDIR_REC, ("trrchan_init: bad direction")); 523 ch = &tr->recchinfo; 524 ch->buffer = b; 525 ch->parent = tr; 526 ch->channel = c; 527 if (sndbuf_alloc(ch->buffer, tr->parent_dmat, TR_BUFFSIZE) == -1) 528 return NULL; 529 530 return ch; 531} 532 533static int 534trrchan_setformat(kobj_t obj, void *data, u_int32_t format) 535{ 536 struct tr_rchinfo *ch = data; 537 struct tr_info *tr = ch->parent; 538 u_int32_t i, bits; 539 540 bits = tr_fmttobits(format); 541 /* set # of samples between interrupts */ 542 i = (sndbuf_runsz(ch->buffer) >> ((bits & 0x08)? 1 : 0)) - 1; 543 tr_wr(tr, TR_REG_SBBL, i | (i << 16), 4); 544 /* set sample format */ 545 i = 0x18 | (bits << 4); 546 tr_wr(tr, TR_REG_SBCTRL, i, 1); 547 548 return 0; 549 550} 551 552static int 553trrchan_setspeed(kobj_t obj, void *data, u_int32_t speed) 554{ 555 struct tr_rchinfo *ch = data; 556 struct tr_info *tr = ch->parent; 557 558 /* setup speed */ 559 ch->delta = (48000 << 12) / speed; 560 tr_wr(tr, TR_REG_SBDELTA, ch->delta, 2); 561 562 /* return closest possible speed */ 563 return (48000 << 12) / ch->delta; 564} 565 566static int 567trrchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 568{ 569 struct tr_rchinfo *ch = data; 570 571 sndbuf_resize(ch->buffer, 2, blocksize); 572 573 return blocksize; 574} 575 576static int 577trrchan_trigger(kobj_t obj, void *data, int go) 578{ 579 struct tr_rchinfo *ch = data; 580 struct tr_info *tr = ch->parent; 581 u_int32_t i; 582 583 if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) 584 return 0; 585 586 if (go == PCMTRIG_START) { 587 /* set up dma mode regs */ 588 tr_wr(tr, TR_REG_DMAR15, 0, 1); 589 i = tr_rd(tr, TR_REG_DMAR11, 1) & 0x03; 590 tr_wr(tr, TR_REG_DMAR11, i | 0x54, 1); 591 /* set up base address */ 592 tr_wr(tr, TR_REG_DMAR0, vtophys(sndbuf_getbuf(ch->buffer)), 4); 593 /* set up buffer size */ 594 i = tr_rd(tr, TR_REG_DMAR4, 4) & ~0x00ffffff; 595 tr_wr(tr, TR_REG_DMAR4, i | (sndbuf_runsz(ch->buffer) - 1), 4); 596 /* start */ 597 tr_wr(tr, TR_REG_SBCTRL, tr_rd(tr, TR_REG_SBCTRL, 1) | 1, 1); 598 } else 599 tr_wr(tr, TR_REG_SBCTRL, tr_rd(tr, TR_REG_SBCTRL, 1) & ~7, 1); 600 601 /* return 0 if ok */ 602 return 0; 603} 604 605static int 606trrchan_getptr(kobj_t obj, void *data) 607{ 608 struct tr_rchinfo *ch = data; 609 struct tr_info *tr = ch->parent; 610 611 /* return current byte offset of channel */ 612 return tr_rd(tr, TR_REG_DMAR0, 4) - vtophys(sndbuf_getbuf(ch->buffer)); 613} 614
|
603static pcmchan_caps *
| 615static struct pcmchan_caps *
|
604trrchan_getcaps(kobj_t obj, void *data) 605{ 606 return &tr_reccaps; 607} 608 609static kobj_method_t trrchan_methods[] = { 610 KOBJMETHOD(channel_init, trrchan_init), 611 KOBJMETHOD(channel_setformat, trrchan_setformat), 612 KOBJMETHOD(channel_setspeed, trrchan_setspeed), 613 KOBJMETHOD(channel_setblocksize, trrchan_setblocksize), 614 KOBJMETHOD(channel_trigger, trrchan_trigger), 615 KOBJMETHOD(channel_getptr, trrchan_getptr), 616 KOBJMETHOD(channel_getcaps, trrchan_getcaps), 617 { 0, 0 } 618}; 619CHANNEL_DECLARE(trrchan); 620 621/* -------------------------------------------------------------------- */ 622/* The interrupt handler */ 623 624static void 625tr_intr(void *p) 626{ 627 struct tr_info *tr = (struct tr_info *)p; 628 struct tr_chinfo *ch; 629 u_int32_t active, mask, bufhalf, chnum, intsrc; 630 int tmp; 631 632 intsrc = tr_rd(tr, TR_REG_MISCINT, 4); 633 if (intsrc & TR_INT_ADDR) { 634 chnum = 0; 635 while (chnum < 64) { 636 mask = 0x00000001; 637 active = tr_rd(tr, (chnum < 32)? TR_REG_ADDRINTA : TR_REG_ADDRINTB, 4); 638 bufhalf = tr_rd(tr, (chnum < 32)? TR_REG_CSPF_A : TR_REG_CSPF_B, 4); 639 if (active) { 640 do { 641 if (active & mask) { 642 tmp = (bufhalf & mask)? 1 : 0; 643 if (chnum < tr->playchns) { 644 ch = &tr->chinfo[chnum]; 645 /* printf("%d @ %d, ", chnum, trpchan_getptr(NULL, ch)); */ 646 if (ch->bufhalf != tmp) { 647 chn_intr(ch->channel); 648 ch->bufhalf = tmp;
| 616trrchan_getcaps(kobj_t obj, void *data) 617{ 618 return &tr_reccaps; 619} 620 621static kobj_method_t trrchan_methods[] = { 622 KOBJMETHOD(channel_init, trrchan_init), 623 KOBJMETHOD(channel_setformat, trrchan_setformat), 624 KOBJMETHOD(channel_setspeed, trrchan_setspeed), 625 KOBJMETHOD(channel_setblocksize, trrchan_setblocksize), 626 KOBJMETHOD(channel_trigger, trrchan_trigger), 627 KOBJMETHOD(channel_getptr, trrchan_getptr), 628 KOBJMETHOD(channel_getcaps, trrchan_getcaps), 629 { 0, 0 } 630}; 631CHANNEL_DECLARE(trrchan); 632 633/* -------------------------------------------------------------------- */ 634/* The interrupt handler */ 635 636static void 637tr_intr(void *p) 638{ 639 struct tr_info *tr = (struct tr_info *)p; 640 struct tr_chinfo *ch; 641 u_int32_t active, mask, bufhalf, chnum, intsrc; 642 int tmp; 643 644 intsrc = tr_rd(tr, TR_REG_MISCINT, 4); 645 if (intsrc & TR_INT_ADDR) { 646 chnum = 0; 647 while (chnum < 64) { 648 mask = 0x00000001; 649 active = tr_rd(tr, (chnum < 32)? TR_REG_ADDRINTA : TR_REG_ADDRINTB, 4); 650 bufhalf = tr_rd(tr, (chnum < 32)? TR_REG_CSPF_A : TR_REG_CSPF_B, 4); 651 if (active) { 652 do { 653 if (active & mask) { 654 tmp = (bufhalf & mask)? 1 : 0; 655 if (chnum < tr->playchns) { 656 ch = &tr->chinfo[chnum]; 657 /* printf("%d @ %d, ", chnum, trpchan_getptr(NULL, ch)); */ 658 if (ch->bufhalf != tmp) { 659 chn_intr(ch->channel); 660 ch->bufhalf = tmp;
|
649 } else 650 printf("same bufhalf\n"); 651
| 661 }
|
652 } 653 } 654 chnum++; 655 mask <<= 1; 656 } while (chnum & 31); 657 } else 658 chnum += 32; 659 660 tr_wr(tr, (chnum <= 32)? TR_REG_ADDRINTA : TR_REG_ADDRINTB, active, 4); 661 } 662 } 663 if (intsrc & TR_INT_SB) { 664 chn_intr(tr->recchinfo.channel); 665 tr_rd(tr, TR_REG_SBR9, 1); 666 tr_rd(tr, TR_REG_SBR10, 1); 667 } 668} 669 670/* -------------------------------------------------------------------- */ 671 672/* 673 * Probe and attach the card 674 */ 675 676static int 677tr_init(struct tr_info *tr) 678{ 679 if (tr->type == TDX_PCI_ID) { 680 tr_wr(tr, TDX_REG_CODECST, TDX_CDC_ON, 4); 681 } else tr_wr(tr, TNX_REG_CODECST, TNX_CDC_ON, 4); 682 683 tr_wr(tr, TR_REG_CIR, TR_CIR_MIDENA | TR_CIR_ADDRENA, 4); 684 tr->playchns = 0; 685 return 0; 686} 687 688static int 689tr_pci_probe(device_t dev) 690{ 691 if (pci_get_devid(dev) == TDX_PCI_ID) { 692 device_set_desc(dev, "Trident 4DWave DX"); 693 return 0; 694 } 695 if (pci_get_devid(dev) == TNX_PCI_ID) { 696 device_set_desc(dev, "Trident 4DWave NX"); 697 return 0; 698 } 699 700 return ENXIO; 701} 702 703static int 704tr_pci_attach(device_t dev) 705{ 706 u_int32_t data; 707 struct tr_info *tr; 708 struct ac97_info *codec = 0; 709 int i; 710 char status[SND_STATUSLEN]; 711 712 if ((tr = malloc(sizeof(*tr), M_DEVBUF, M_NOWAIT)) == NULL) { 713 device_printf(dev, "cannot allocate softc\n"); 714 return ENXIO; 715 } 716 717 bzero(tr, sizeof(*tr)); 718 tr->type = pci_get_devid(dev);
| 662 } 663 } 664 chnum++; 665 mask <<= 1; 666 } while (chnum & 31); 667 } else 668 chnum += 32; 669 670 tr_wr(tr, (chnum <= 32)? TR_REG_ADDRINTA : TR_REG_ADDRINTB, active, 4); 671 } 672 } 673 if (intsrc & TR_INT_SB) { 674 chn_intr(tr->recchinfo.channel); 675 tr_rd(tr, TR_REG_SBR9, 1); 676 tr_rd(tr, TR_REG_SBR10, 1); 677 } 678} 679 680/* -------------------------------------------------------------------- */ 681 682/* 683 * Probe and attach the card 684 */ 685 686static int 687tr_init(struct tr_info *tr) 688{ 689 if (tr->type == TDX_PCI_ID) { 690 tr_wr(tr, TDX_REG_CODECST, TDX_CDC_ON, 4); 691 } else tr_wr(tr, TNX_REG_CODECST, TNX_CDC_ON, 4); 692 693 tr_wr(tr, TR_REG_CIR, TR_CIR_MIDENA | TR_CIR_ADDRENA, 4); 694 tr->playchns = 0; 695 return 0; 696} 697 698static int 699tr_pci_probe(device_t dev) 700{ 701 if (pci_get_devid(dev) == TDX_PCI_ID) { 702 device_set_desc(dev, "Trident 4DWave DX"); 703 return 0; 704 } 705 if (pci_get_devid(dev) == TNX_PCI_ID) { 706 device_set_desc(dev, "Trident 4DWave NX"); 707 return 0; 708 } 709 710 return ENXIO; 711} 712 713static int 714tr_pci_attach(device_t dev) 715{ 716 u_int32_t data; 717 struct tr_info *tr; 718 struct ac97_info *codec = 0; 719 int i; 720 char status[SND_STATUSLEN]; 721 722 if ((tr = malloc(sizeof(*tr), M_DEVBUF, M_NOWAIT)) == NULL) { 723 device_printf(dev, "cannot allocate softc\n"); 724 return ENXIO; 725 } 726 727 bzero(tr, sizeof(*tr)); 728 tr->type = pci_get_devid(dev);
|
| 729 tr->lock = snd_mtxcreate(device_get_nameunit(dev));
|
719 720 data = pci_read_config(dev, PCIR_COMMAND, 2); 721 data |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); 722 pci_write_config(dev, PCIR_COMMAND, data, 2); 723 data = pci_read_config(dev, PCIR_COMMAND, 2); 724 725 tr->regid = PCIR_MAPS; 726 tr->regtype = SYS_RES_IOPORT; 727 tr->reg = bus_alloc_resource(dev, tr->regtype, &tr->regid, 0, ~0, 1, RF_ACTIVE); 728 if (tr->reg) { 729 tr->st = rman_get_bustag(tr->reg); 730 tr->sh = rman_get_bushandle(tr->reg); 731 } else { 732 device_printf(dev, "unable to map register space\n"); 733 goto bad; 734 } 735 736 if (tr_init(tr) == -1) { 737 device_printf(dev, "unable to initialize the card\n"); 738 goto bad; 739 } 740 741 codec = AC97_CREATE(dev, tr, tr_ac97); 742 if (codec == NULL) goto bad; 743 if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) goto bad; 744 745 tr->irqid = 0; 746 tr->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &tr->irqid, 747 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
| 730 731 data = pci_read_config(dev, PCIR_COMMAND, 2); 732 data |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); 733 pci_write_config(dev, PCIR_COMMAND, data, 2); 734 data = pci_read_config(dev, PCIR_COMMAND, 2); 735 736 tr->regid = PCIR_MAPS; 737 tr->regtype = SYS_RES_IOPORT; 738 tr->reg = bus_alloc_resource(dev, tr->regtype, &tr->regid, 0, ~0, 1, RF_ACTIVE); 739 if (tr->reg) { 740 tr->st = rman_get_bustag(tr->reg); 741 tr->sh = rman_get_bushandle(tr->reg); 742 } else { 743 device_printf(dev, "unable to map register space\n"); 744 goto bad; 745 } 746 747 if (tr_init(tr) == -1) { 748 device_printf(dev, "unable to initialize the card\n"); 749 goto bad; 750 } 751 752 codec = AC97_CREATE(dev, tr, tr_ac97); 753 if (codec == NULL) goto bad; 754 if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) goto bad; 755 756 tr->irqid = 0; 757 tr->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &tr->irqid, 758 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
|
748 if (!tr->irq || 749 bus_setup_intr(dev, tr->irq, INTR_TYPE_TTY, tr_intr, tr, &tr->ih)) {
| 759 if (!tr->irq || snd_setup_intr(dev, tr->irq, INTR_MPSAFE, tr_intr, tr, &tr->ih)) {
|
750 device_printf(dev, "unable to map interrupt\n"); 751 goto bad; 752 } 753 754 if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 755 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 756 /*highaddr*/BUS_SPACE_MAXADDR, 757 /*filter*/NULL, /*filterarg*/NULL, 758 /*maxsize*/TR_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff, 759 /*flags*/0, &tr->parent_dmat) != 0) { 760 device_printf(dev, "unable to create dma tag\n"); 761 goto bad; 762 } 763 764 snprintf(status, 64, "at io 0x%lx irq %ld", 765 rman_get_start(tr->reg), rman_get_start(tr->irq)); 766 767 if (pcm_register(dev, tr, TR_MAXPLAYCH, 1)) goto bad; 768 pcm_addchan(dev, PCMDIR_REC, &trrchan_class, tr); 769 for (i = 0; i < TR_MAXPLAYCH; i++) 770 pcm_addchan(dev, PCMDIR_PLAY, &trpchan_class, tr); 771 pcm_setstatus(dev, status); 772 773 return 0; 774 775bad: 776 if (codec) ac97_destroy(codec); 777 if (tr->reg) bus_release_resource(dev, tr->regtype, tr->regid, tr->reg); 778 if (tr->ih) bus_teardown_intr(dev, tr->irq, tr->ih); 779 if (tr->irq) bus_release_resource(dev, SYS_RES_IRQ, tr->irqid, tr->irq); 780 if (tr->parent_dmat) bus_dma_tag_destroy(tr->parent_dmat);
| 760 device_printf(dev, "unable to map interrupt\n"); 761 goto bad; 762 } 763 764 if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 765 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 766 /*highaddr*/BUS_SPACE_MAXADDR, 767 /*filter*/NULL, /*filterarg*/NULL, 768 /*maxsize*/TR_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff, 769 /*flags*/0, &tr->parent_dmat) != 0) { 770 device_printf(dev, "unable to create dma tag\n"); 771 goto bad; 772 } 773 774 snprintf(status, 64, "at io 0x%lx irq %ld", 775 rman_get_start(tr->reg), rman_get_start(tr->irq)); 776 777 if (pcm_register(dev, tr, TR_MAXPLAYCH, 1)) goto bad; 778 pcm_addchan(dev, PCMDIR_REC, &trrchan_class, tr); 779 for (i = 0; i < TR_MAXPLAYCH; i++) 780 pcm_addchan(dev, PCMDIR_PLAY, &trpchan_class, tr); 781 pcm_setstatus(dev, status); 782 783 return 0; 784 785bad: 786 if (codec) ac97_destroy(codec); 787 if (tr->reg) bus_release_resource(dev, tr->regtype, tr->regid, tr->reg); 788 if (tr->ih) bus_teardown_intr(dev, tr->irq, tr->ih); 789 if (tr->irq) bus_release_resource(dev, SYS_RES_IRQ, tr->irqid, tr->irq); 790 if (tr->parent_dmat) bus_dma_tag_destroy(tr->parent_dmat);
|
| 791 if (tr->lock) snd_mtxfree(tr->lock);
|
781 free(tr, M_DEVBUF); 782 return ENXIO; 783} 784 785static int 786tr_pci_detach(device_t dev) 787{ 788 int r; 789 struct tr_info *tr; 790 791 r = pcm_unregister(dev); 792 if (r) 793 return r; 794 795 tr = pcm_getdevinfo(dev); 796 bus_release_resource(dev, tr->regtype, tr->regid, tr->reg); 797 bus_teardown_intr(dev, tr->irq, tr->ih); 798 bus_release_resource(dev, SYS_RES_IRQ, tr->irqid, tr->irq); 799 bus_dma_tag_destroy(tr->parent_dmat);
| 792 free(tr, M_DEVBUF); 793 return ENXIO; 794} 795 796static int 797tr_pci_detach(device_t dev) 798{ 799 int r; 800 struct tr_info *tr; 801 802 r = pcm_unregister(dev); 803 if (r) 804 return r; 805 806 tr = pcm_getdevinfo(dev); 807 bus_release_resource(dev, tr->regtype, tr->regid, tr->reg); 808 bus_teardown_intr(dev, tr->irq, tr->ih); 809 bus_release_resource(dev, SYS_RES_IRQ, tr->irqid, tr->irq); 810 bus_dma_tag_destroy(tr->parent_dmat);
|
| 811 snd_mtxfree(tr->lock);
|
800 free(tr, M_DEVBUF); 801 802 return 0; 803} 804 805static device_method_t tr_methods[] = { 806 /* Device interface */ 807 DEVMETHOD(device_probe, tr_pci_probe), 808 DEVMETHOD(device_attach, tr_pci_attach), 809 DEVMETHOD(device_detach, tr_pci_detach), 810 811 { 0, 0 } 812}; 813 814static driver_t tr_driver = { 815 "pcm", 816 tr_methods,
| 812 free(tr, M_DEVBUF); 813 814 return 0; 815} 816 817static device_method_t tr_methods[] = { 818 /* Device interface */ 819 DEVMETHOD(device_probe, tr_pci_probe), 820 DEVMETHOD(device_attach, tr_pci_attach), 821 DEVMETHOD(device_detach, tr_pci_detach), 822 823 { 0, 0 } 824}; 825 826static driver_t tr_driver = { 827 "pcm", 828 tr_methods,
|
817 sizeof(snddev_info),
| 829 sizeof(struct snddev_info),
|
818}; 819 820static devclass_t pcm_devclass; 821 822DRIVER_MODULE(snd_t4dwave, pci, tr_driver, pcm_devclass, 0, 0); 823MODULE_DEPEND(snd_t4dwave, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); 824MODULE_VERSION(snd_t4dwave, 1);
| 830}; 831 832static devclass_t pcm_devclass; 833 834DRIVER_MODULE(snd_t4dwave, pci, tr_driver, pcm_devclass, 0, 0); 835MODULE_DEPEND(snd_t4dwave, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); 836MODULE_VERSION(snd_t4dwave, 1);
|