Deleted Added
full compact
t4dwave.c (71503) t4dwave.c (74763)
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);