2 * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
26 * $FreeBSD: src/sys/dev/sound/pci/envy24.c,v 1.11.2.2 2007/06/11 19:33:27 ariff Exp $
27 * $DragonFly: src/sys/dev/sound/pci/envy24.c,v 1.3 2008/01/05 14:02:38 swildner Exp $
30 #include <dev/sound/pcm/sound.h>
31 #include <dev/sound/pcm/ac97.h>
32 #include <dev/sound/pci/spicds.h>
33 #include <dev/sound/pci/envy24.h>
35 #include <bus/pci/pcireg.h>
36 #include <bus/pci/pcivar.h>
40 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pci/envy24.c,v 1.3 2008/01/05 14:02:38 swildner Exp $");
42 MALLOC_DEFINE(M_ENVY24
, "envy24", "envy24 audio");
44 /* -------------------------------------------------------------------- */
48 #define ENVY24_PLAY_CHNUM 10
49 #define ENVY24_REC_CHNUM 12
50 #define ENVY24_PLAY_BUFUNIT (4 /* byte/sample */ * 10 /* channel */)
51 #define ENVY24_REC_BUFUNIT (4 /* byte/sample */ * 12 /* channel */)
52 #define ENVY24_SAMPLE_NUM 4096
54 #define ENVY24_TIMEOUT 1000
56 #define ENVY24_DEFAULT_FORMAT (AFMT_STEREO | AFMT_S16_LE)
58 #define ENVY24_NAMELEN 32
63 #define abs(i) (i < 0 ? -i : i)
65 struct envy24_sample
{
66 volatile u_int32_t buffer
;
69 typedef struct envy24_sample sample32_t
;
71 /* channel registers */
73 struct snd_dbuf
*buffer
;
74 struct pcm_channel
*channel
;
75 struct sc_info
*parent
;
77 unsigned num
; /* hw channel number */
79 /* channel information */
82 u_int32_t blk
; /* hw block size(dword) */
84 /* format conversion structure */
86 unsigned int size
; /* data buffer size(byte) */
87 int unit
; /* sample size(byte) */
88 unsigned int offset
; /* samples number offset */
89 void (*emldma
)(struct sc_chinfo
*);
95 /* codec interface entrys */
97 void *(*create
)(device_t dev
, void *devinfo
, int dir
, int num
);
98 void (*destroy
)(void *codec
);
99 void (*init
)(void *codec
);
100 void (*reinit
)(void *codec
);
101 void (*setvolume
)(void *codec
, int dir
, unsigned int left
, unsigned int right
);
102 void (*setrate
)(void *codec
, int which
, int rate
);
105 /* system configuration information */
108 u_int16_t subvendor
, subdevice
;
109 u_int8_t scfg
, acl
, i2s
, spdif
;
110 u_int8_t gpiomask
, gpiostate
, gpiodir
;
111 u_int8_t cdti
, cclk
, cs
, cif
, type
;
113 struct codec_entry
*codec
;
116 /* device private data */
121 /* Control/Status registor */
125 bus_space_handle_t csh
;
127 struct resource
*ddma
;
129 bus_space_tag_t ddmat
;
130 bus_space_handle_t ddmah
;
131 /* Consumer Section DMA Channel Registers */
135 bus_space_handle_t dsh
;
136 /* MultiTrack registor */
140 bus_space_handle_t mth
;
144 struct resource
*irq
;
148 /* system configuration data */
149 struct cfg_info
*cfg
;
151 /* ADC/DAC number and info */
153 void *adc
[4], *dac
[4];
155 /* mixer control data */
157 u_int8_t left
[ENVY24_CHAN_NUM
];
158 u_int8_t right
[ENVY24_CHAN_NUM
];
160 /* Play/Record DMA fifo */
163 u_int32_t psize
, rsize
; /* DMA buffer size(byte) */
164 u_int16_t blk
[2]; /* transfer check blocksize(dword) */
165 bus_dmamap_t pmap
, rmap
;
171 struct pcmchan_caps caps
[2];
173 /* channel info table */
175 struct sc_chinfo chan
[11];
178 /* -------------------------------------------------------------------- */
185 static void envy24_p8u(struct sc_chinfo
*);
186 static void envy24_p16sl(struct sc_chinfo
*);
187 static void envy24_p32sl(struct sc_chinfo
*);
188 static void envy24_r16sl(struct sc_chinfo
*);
189 static void envy24_r32sl(struct sc_chinfo
*);
191 /* channel interface */
192 static void *envy24chan_init(kobj_t
, void *, struct snd_dbuf
*, struct pcm_channel
*, int);
193 static int envy24chan_setformat(kobj_t
, void *, u_int32_t
);
194 static int envy24chan_setspeed(kobj_t
, void *, u_int32_t
);
195 static int envy24chan_setblocksize(kobj_t
, void *, u_int32_t
);
196 static int envy24chan_trigger(kobj_t
, void *, int);
197 static int envy24chan_getptr(kobj_t
, void *);
198 static struct pcmchan_caps
*envy24chan_getcaps(kobj_t
, void *);
200 /* mixer interface */
201 static int envy24mixer_init(struct snd_mixer
*);
202 static int envy24mixer_reinit(struct snd_mixer
*);
203 static int envy24mixer_uninit(struct snd_mixer
*);
204 static int envy24mixer_set(struct snd_mixer
*, unsigned, unsigned, unsigned);
205 static u_int32_t
envy24mixer_setrecsrc(struct snd_mixer
*, u_int32_t
);
207 /* M-Audio Delta series AK4524 access interface */
208 static void *envy24_delta_ak4524_create(device_t
, void *, int, int);
209 static void envy24_delta_ak4524_destroy(void *);
210 static void envy24_delta_ak4524_init(void *);
211 static void envy24_delta_ak4524_reinit(void *);
212 static void envy24_delta_ak4524_setvolume(void *, int, unsigned int, unsigned int);
214 /* -------------------------------------------------------------------- */
217 system constant tables
220 /* API -> hardware channel map */
221 static unsigned envy24_chanmap
[ENVY24_CHAN_NUM
] = {
222 ENVY24_CHAN_PLAY_SPDIF
, /* 0 */
223 ENVY24_CHAN_PLAY_DAC1
, /* 1 */
224 ENVY24_CHAN_PLAY_DAC2
, /* 2 */
225 ENVY24_CHAN_PLAY_DAC3
, /* 3 */
226 ENVY24_CHAN_PLAY_DAC4
, /* 4 */
227 ENVY24_CHAN_REC_MIX
, /* 5 */
228 ENVY24_CHAN_REC_SPDIF
, /* 6 */
229 ENVY24_CHAN_REC_ADC1
, /* 7 */
230 ENVY24_CHAN_REC_ADC2
, /* 8 */
231 ENVY24_CHAN_REC_ADC3
, /* 9 */
232 ENVY24_CHAN_REC_ADC4
, /* 10 */
235 /* mixer -> API channel map. see above */
236 static int envy24_mixmap
[] = {
237 -1, /* Master output level. It is depend on codec support */
238 -1, /* Treble level of all output channels */
239 -1, /* Bass level of all output channels */
240 -1, /* Volume of synthesier input */
241 0, /* Output level for the audio device */
242 -1, /* Output level for the PC speaker */
243 7, /* line in jack */
244 -1, /* microphone jack */
245 -1, /* CD audio input */
246 -1, /* Recording monitor */
247 1, /* alternative codec */
248 -1, /* global recording level */
250 -1, /* Output gain */
251 8, /* Input source 1 */
252 9, /* Input source 2 */
253 10, /* Input source 3 */
254 6, /* Digital (input) 1 */
255 -1, /* Digital (input) 2 */
256 -1, /* Digital (input) 3 */
257 -1, /* Phone input */
258 -1, /* Phone output */
259 -1, /* Video/TV (audio) in */
261 -1, /* Monitor volume */
264 /* variable rate audio */
265 static u_int32_t envy24_speed
[] = {
266 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000,
267 12000, 11025, 9600, 8000, 0
270 /* known boards configuration */
271 static struct codec_entry delta_codec
= {
272 envy24_delta_ak4524_create
,
273 envy24_delta_ak4524_destroy
,
274 envy24_delta_ak4524_init
,
275 envy24_delta_ak4524_reinit
,
276 envy24_delta_ak4524_setvolume
,
280 static struct cfg_info cfg_table
[] = {
282 "Envy24 audio (M Audio Delta Dio 2496)",
284 0x10, 0x80, 0xf0, 0x03,
286 0x10, 0x20, 0x40, 0x00, 0x00,
291 "Envy24 audio (Terratec DMX 6fire)",
293 0x2f, 0x80, 0xf0, 0x03,
295 0x10, 0x20, 0x01, 0x01, 0x00,
300 "Envy24 audio (M Audio Audiophile 2496)",
302 0x10, 0x80, 0x72, 0x03,
304 0x08, 0x02, 0x20, 0x00, 0x01,
309 "Envy24 audio (Generic)",
311 0x0f, 0x00, 0x01, 0x03,
313 0x10, 0x20, 0x40, 0x00, 0x00,
315 &delta_codec
, /* default codec routines */
319 static u_int32_t envy24_recfmt
[] = {
320 AFMT_STEREO
| AFMT_S16_LE
,
321 AFMT_STEREO
| AFMT_S32_LE
,
324 static struct pcmchan_caps envy24_reccaps
= {8000, 96000, envy24_recfmt
, 0};
326 static u_int32_t envy24_playfmt
[] = {
327 AFMT_STEREO
| AFMT_U8
,
328 AFMT_STEREO
| AFMT_S16_LE
,
329 AFMT_STEREO
| AFMT_S32_LE
,
333 static struct pcmchan_caps envy24_playcaps
= {8000, 96000, envy24_playfmt
, 0};
335 struct envy24_emldma
{
337 void (*emldma
)(struct sc_chinfo
*);
341 static struct envy24_emldma envy24_pemltab
[] = {
342 {AFMT_STEREO
| AFMT_U8
, envy24_p8u
, 2},
343 {AFMT_STEREO
| AFMT_S16_LE
, envy24_p16sl
, 4},
344 {AFMT_STEREO
| AFMT_S32_LE
, envy24_p32sl
, 8},
348 static struct envy24_emldma envy24_remltab
[] = {
349 {AFMT_STEREO
| AFMT_S16_LE
, envy24_r16sl
, 4},
350 {AFMT_STEREO
| AFMT_S32_LE
, envy24_r32sl
, 8},
354 /* -------------------------------------------------------------------- */
356 /* common routines */
358 envy24_rdcs(struct sc_info
*sc
, int regno
, int size
)
362 return bus_space_read_1(sc
->cst
, sc
->csh
, regno
);
364 return bus_space_read_2(sc
->cst
, sc
->csh
, regno
);
366 return bus_space_read_4(sc
->cst
, sc
->csh
, regno
);
373 envy24_wrcs(struct sc_info
*sc
, int regno
, u_int32_t data
, int size
)
377 bus_space_write_1(sc
->cst
, sc
->csh
, regno
, data
);
380 bus_space_write_2(sc
->cst
, sc
->csh
, regno
, data
);
383 bus_space_write_4(sc
->cst
, sc
->csh
, regno
, data
);
389 envy24_rdmt(struct sc_info
*sc
, int regno
, int size
)
393 return bus_space_read_1(sc
->mtt
, sc
->mth
, regno
);
395 return bus_space_read_2(sc
->mtt
, sc
->mth
, regno
);
397 return bus_space_read_4(sc
->mtt
, sc
->mth
, regno
);
404 envy24_wrmt(struct sc_info
*sc
, int regno
, u_int32_t data
, int size
)
408 bus_space_write_1(sc
->mtt
, sc
->mth
, regno
, data
);
411 bus_space_write_2(sc
->mtt
, sc
->mth
, regno
, data
);
414 bus_space_write_4(sc
->mtt
, sc
->mth
, regno
, data
);
420 envy24_rdci(struct sc_info
*sc
, int regno
)
422 envy24_wrcs(sc
, ENVY24_CCS_INDEX
, regno
, 1);
423 return envy24_rdcs(sc
, ENVY24_CCS_DATA
, 1);
427 envy24_wrci(struct sc_info
*sc
, int regno
, u_int32_t data
)
429 envy24_wrcs(sc
, ENVY24_CCS_INDEX
, regno
, 1);
430 envy24_wrcs(sc
, ENVY24_CCS_DATA
, data
, 1);
433 /* -------------------------------------------------------------------- */
435 /* I2C port/E2PROM access routines */
438 envy24_rdi2c(struct sc_info
*sc
, u_int32_t dev
, u_int32_t addr
)
444 device_printf(sc
->dev
, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev
, addr
);
446 for (i
= 0; i
< ENVY24_TIMEOUT
; i
++) {
447 data
= envy24_rdcs(sc
, ENVY24_CCS_I2CSTAT
, 1);
448 if ((data
& ENVY24_CCS_I2CSTAT_BSY
) == 0)
450 DELAY(32); /* 31.25kHz */
452 if (i
== ENVY24_TIMEOUT
) {
455 envy24_wrcs(sc
, ENVY24_CCS_I2CADDR
, addr
, 1);
456 envy24_wrcs(sc
, ENVY24_CCS_I2CDEV
,
457 (dev
& ENVY24_CCS_I2CDEV_ADDR
) | ENVY24_CCS_I2CDEV_RD
, 1);
458 for (i
= 0; i
< ENVY24_TIMEOUT
; i
++) {
459 data
= envy24_rdcs(sc
, ENVY24_CCS_I2CSTAT
, 1);
460 if ((data
& ENVY24_CCS_I2CSTAT_BSY
) == 0)
462 DELAY(32); /* 31.25kHz */
464 if (i
== ENVY24_TIMEOUT
) {
467 data
= envy24_rdcs(sc
, ENVY24_CCS_I2CDATA
, 1);
470 device_printf(sc
->dev
, "envy24_rdi2c(): return 0x%x\n", data
);
477 envy24_wri2c(struct sc_info
*sc
, u_int32_t dev
, u_int32_t addr
, u_int32_t data
)
483 device_printf(sc
->dev
, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev
, addr
);
485 for (i
= 0; i
< ENVY24_TIMEOUT
; i
++) {
486 tmp
= envy24_rdcs(sc
, ENVY24_CCS_I2CSTAT
, 1);
487 if ((tmp
& ENVY24_CCS_I2CSTAT_BSY
) == 0)
489 DELAY(32); /* 31.25kHz */
491 if (i
== ENVY24_TIMEOUT
) {
494 envy24_wrcs(sc
, ENVY24_CCS_I2CADDR
, addr
, 1);
495 envy24_wrcs(sc
, ENVY24_CCS_I2CDATA
, data
, 1);
496 envy24_wrcs(sc
, ENVY24_CCS_I2CDEV
,
497 (dev
& ENVY24_CCS_I2CDEV_ADDR
) | ENVY24_CCS_I2CDEV_WR
, 1);
498 for (i
= 0; i
< ENVY24_TIMEOUT
; i
++) {
499 data
= envy24_rdcs(sc
, ENVY24_CCS_I2CSTAT
, 1);
500 if ((data
& ENVY24_CCS_I2CSTAT_BSY
) == 0)
502 DELAY(32); /* 31.25kHz */
504 if (i
== ENVY24_TIMEOUT
) {
513 envy24_rdrom(struct sc_info
*sc
, u_int32_t addr
)
518 device_printf(sc
->dev
, "envy24_rdrom(sc, 0x%02x)\n", addr
);
520 data
= envy24_rdcs(sc
, ENVY24_CCS_I2CSTAT
, 1);
521 if ((data
& ENVY24_CCS_I2CSTAT_ROM
) == 0) {
523 device_printf(sc
->dev
, "envy24_rdrom(): E2PROM not presented\n");
528 return envy24_rdi2c(sc
, ENVY24_CCS_I2CDEV_ROM
, addr
);
531 static struct cfg_info
*
532 envy24_rom2cfg(struct sc_info
*sc
)
534 struct cfg_info
*buff
;
539 device_printf(sc
->dev
, "envy24_rom2cfg(sc)\n");
541 size
= envy24_rdrom(sc
, ENVY24_E2PROM_SIZE
);
542 if (size
< ENVY24_E2PROM_GPIODIR
+ 1) {
544 device_printf(sc
->dev
, "envy24_rom2cfg(): ENVY24_E2PROM_SIZE-->%d\n", size
);
548 buff
= kmalloc(sizeof(*buff
), M_ENVY24
, M_NOWAIT
);
551 device_printf(sc
->dev
, "envy24_rom2cfg(): malloc()\n");
557 buff
->subvendor
= envy24_rdrom(sc
, ENVY24_E2PROM_SUBVENDOR
) << 8;
558 buff
->subvendor
+= envy24_rdrom(sc
, ENVY24_E2PROM_SUBVENDOR
+ 1);
559 buff
->subdevice
= envy24_rdrom(sc
, ENVY24_E2PROM_SUBDEVICE
) << 8;
560 buff
->subdevice
+= envy24_rdrom(sc
, ENVY24_E2PROM_SUBDEVICE
+ 1);
561 buff
->scfg
= envy24_rdrom(sc
, ENVY24_E2PROM_SCFG
);
562 buff
->acl
= envy24_rdrom(sc
, ENVY24_E2PROM_ACL
);
563 buff
->i2s
= envy24_rdrom(sc
, ENVY24_E2PROM_I2S
);
564 buff
->spdif
= envy24_rdrom(sc
, ENVY24_E2PROM_SPDIF
);
565 buff
->gpiomask
= envy24_rdrom(sc
, ENVY24_E2PROM_GPIOMASK
);
566 buff
->gpiostate
= envy24_rdrom(sc
, ENVY24_E2PROM_GPIOSTATE
);
567 buff
->gpiodir
= envy24_rdrom(sc
, ENVY24_E2PROM_GPIODIR
);
569 for (i
= 0; cfg_table
[i
].subvendor
!= 0 || cfg_table
[i
].subdevice
!= 0; i
++)
570 if (cfg_table
[i
].subvendor
== buff
->subvendor
&&
571 cfg_table
[i
].subdevice
== buff
->subdevice
)
573 buff
->name
= cfg_table
[i
].name
;
574 buff
->codec
= cfg_table
[i
].codec
;
580 envy24_cfgfree(struct cfg_info
*cfg
) {
584 kfree(cfg
, M_ENVY24
);
588 /* -------------------------------------------------------------------- */
590 /* AC'97 codec access routines */
594 envy24_coldcd(struct sc_info
*sc
)
600 device_printf(sc
->dev
, "envy24_coldcd()\n");
602 envy24_wrmt(sc
, ENVY24_MT_AC97CMD
, ENVY24_MT_AC97CMD_CLD
, 1);
604 envy24_wrmt(sc
, ENVY24_MT_AC97CMD
, 0, 1);
606 for (i
= 0; i
< ENVY24_TIMEOUT
; i
++) {
607 data
= envy24_rdmt(sc
, ENVY24_MT_AC97CMD
, 1);
608 if (data
& ENVY24_MT_AC97CMD_RDY
) {
618 envy24_slavecd(struct sc_info
*sc
)
624 device_printf(sc
->dev
, "envy24_slavecd()\n");
626 envy24_wrmt(sc
, ENVY24_MT_AC97CMD
,
627 ENVY24_MT_AC97CMD_CLD
| ENVY24_MT_AC97CMD_WRM
, 1);
629 envy24_wrmt(sc
, ENVY24_MT_AC97CMD
, 0, 1);
631 for (i
= 0; i
< ENVY24_TIMEOUT
; i
++) {
632 data
= envy24_rdmt(sc
, ENVY24_MT_AC97CMD
, 1);
633 if (data
& ENVY24_MT_AC97CMD_RDY
) {
643 envy24_rdcd(kobj_t obj
, void *devinfo
, int regno
)
645 struct sc_info
*sc
= (struct sc_info
*)devinfo
;
650 device_printf(sc
->dev
, "envy24_rdcd(obj, sc, 0x%02x)\n", regno
);
652 envy24_wrmt(sc
, ENVY24_MT_AC97IDX
, (u_int32_t
)regno
, 1);
653 envy24_wrmt(sc
, ENVY24_MT_AC97CMD
, ENVY24_MT_AC97CMD_RD
, 1);
654 for (i
= 0; i
< ENVY24_TIMEOUT
; i
++) {
655 data
= envy24_rdmt(sc
, ENVY24_MT_AC97CMD
, 1);
656 if ((data
& ENVY24_MT_AC97CMD_RD
) == 0)
659 data
= envy24_rdmt(sc
, ENVY24_MT_AC97DLO
, 2);
662 device_printf(sc
->dev
, "envy24_rdcd(): return 0x%x\n", data
);
668 envy24_wrcd(kobj_t obj
, void *devinfo
, int regno
, u_int16_t data
)
670 struct sc_info
*sc
= (struct sc_info
*)devinfo
;
675 device_printf(sc
->dev
, "envy24_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno
, data
);
677 envy24_wrmt(sc
, ENVY24_MT_AC97IDX
, (u_int32_t
)regno
, 1);
678 envy24_wrmt(sc
, ENVY24_MT_AC97DLO
, (u_int32_t
)data
, 2);
679 envy24_wrmt(sc
, ENVY24_MT_AC97CMD
, ENVY24_MT_AC97CMD_WR
, 1);
680 for (i
= 0; i
< ENVY24_TIMEOUT
; i
++) {
681 cmd
= envy24_rdmt(sc
, ENVY24_MT_AC97CMD
, 1);
682 if ((cmd
& ENVY24_MT_AC97CMD_WR
) == 0)
689 static kobj_method_t envy24_ac97_methods
[] = {
690 KOBJMETHOD(ac97_read
, envy24_rdcd
),
691 KOBJMETHOD(ac97_write
, envy24_wrcd
),
694 AC97_DECLARE(envy24_ac97
);
697 /* -------------------------------------------------------------------- */
699 /* GPIO access routines */
702 envy24_gpiord(struct sc_info
*sc
)
704 return envy24_rdci(sc
, ENVY24_CCI_GPIODAT
);
708 envy24_gpiowr(struct sc_info
*sc
, u_int32_t data
)
711 device_printf(sc
->dev
, "envy24_gpiowr(sc, 0x%02x)\n", data
& 0xff);
714 envy24_wrci(sc
, ENVY24_CCI_GPIODAT
, data
);
720 envy24_gpiogetmask(struct sc_info
*sc
)
722 return envy24_rdci(sc
, ENVY24_CCI_GPIOMASK
);
727 envy24_gpiosetmask(struct sc_info
*sc
, u_int32_t mask
)
729 envy24_wrci(sc
, ENVY24_CCI_GPIOMASK
, mask
);
735 envy24_gpiogetdir(struct sc_info
*sc
)
737 return envy24_rdci(sc
, ENVY24_CCI_GPIOCTL
);
742 envy24_gpiosetdir(struct sc_info
*sc
, u_int32_t dir
)
744 envy24_wrci(sc
, ENVY24_CCI_GPIOCTL
, dir
);
748 /* -------------------------------------------------------------------- */
750 /* Envy24 I2C through GPIO bit-banging */
752 struct envy24_delta_ak4524_codec
{
753 struct spicds_info
*info
;
754 struct sc_info
*parent
;
761 envy24_gpio_i2c_ctl(void *codec
, unsigned int scl
, unsigned int sda
)
764 struct envy24_delta_ak4524_codec
*ptr
= codec
;
766 device_printf(ptr
->parent
->dev
, "--> %d, %d\n", scl
, sda
);
768 data
= envy24_gpiord(ptr
->parent
);
769 data
&= ~(SDA_GPIO
| SCL_GPIO
);
770 if (scl
) data
+= SCL_GPIO
;
771 if (sda
) data
+= SDA_GPIO
;
772 envy24_gpiowr(ptr
->parent
, data
);
777 i2c_wrbit(void *codec
, void (*ctrl
)(void*, unsigned int, unsigned int), int bit
)
779 struct envy24_delta_ak4524_codec
*ptr
= codec
;
796 i2c_start(void *codec
, void (*ctrl
)(void*, unsigned int, unsigned int))
798 struct envy24_delta_ak4524_codec
*ptr
= codec
;
809 i2c_stop(void *codec
, void (*ctrl
)(void*, unsigned int, unsigned int))
811 struct envy24_delta_ak4524_codec
*ptr
= codec
;
822 i2c_ack(void *codec
, void (*ctrl
)(void*, unsigned int, unsigned int))
824 struct envy24_delta_ak4524_codec
*ptr
= codec
;
830 /* dummy, need routine to change gpio direction */
836 i2c_wr(void *codec
, void (*ctrl
)(void*, unsigned int, unsigned int), u_int32_t dev
, int reg
, u_int8_t val
)
838 struct envy24_delta_ak4524_codec
*ptr
= codec
;
841 i2c_start(ptr
, ctrl
);
843 for (mask
= 0x80; mask
!= 0; mask
>>= 1)
844 i2c_wrbit(ptr
, ctrl
, dev
& mask
);
848 for (mask
= 0x80; mask
!= 0; mask
>>= 1)
849 i2c_wrbit(ptr
, ctrl
, reg
& mask
);
853 for (mask
= 0x80; mask
!= 0; mask
>>= 1)
854 i2c_wrbit(ptr
, ctrl
, val
& mask
);
860 /* -------------------------------------------------------------------- */
862 /* M-Audio Delta series AK4524 access interface routine */
865 envy24_delta_ak4524_ctl(void *codec
, unsigned int cs
, unsigned int cclk
, unsigned int cdti
)
868 struct envy24_delta_ak4524_codec
*ptr
= codec
;
871 device_printf(ptr
->parent
->dev
, "--> %d, %d, %d\n", cs
, cclk
, cdti
);
873 data
= envy24_gpiord(ptr
->parent
);
874 data
&= ~(ptr
->cs
| ptr
->cclk
| ptr
->cdti
);
875 if (cs
) data
+= ptr
->cs
;
876 if (cclk
) data
+= ptr
->cclk
;
877 if (cdti
) data
+= ptr
->cdti
;
878 envy24_gpiowr(ptr
->parent
, data
);
883 envy24_delta_ak4524_create(device_t dev
, void *info
, int dir
, int num
)
885 struct sc_info
*sc
= info
;
886 struct envy24_delta_ak4524_codec
*buff
= NULL
;
889 device_printf(sc
->dev
, "envy24_delta_ak4524_create(dev, sc, %d, %d)\n", dir
, num
);
892 buff
= kmalloc(sizeof(*buff
), M_ENVY24
, M_NOWAIT
);
896 if (dir
== PCMDIR_REC
&& sc
->adc
[num
] != NULL
)
897 buff
->info
= ((struct envy24_delta_ak4524_codec
*)sc
->adc
[num
])->info
;
898 else if (dir
== PCMDIR_PLAY
&& sc
->dac
[num
] != NULL
)
899 buff
->info
= ((struct envy24_delta_ak4524_codec
*)sc
->dac
[num
])->info
;
901 buff
->info
= spicds_create(dev
, buff
, num
, envy24_delta_ak4524_ctl
);
902 if (buff
->info
== NULL
) {
903 kfree(buff
, M_ENVY24
);
915 envy24_delta_ak4524_destroy(void *codec
)
917 struct envy24_delta_ak4524_codec
*ptr
= codec
;
921 device_printf(ptr
->parent
->dev
, "envy24_delta_ak4524_destroy()\n");
924 if (ptr
->dir
== PCMDIR_PLAY
) {
925 if (ptr
->parent
->dac
[ptr
->num
] != NULL
)
926 spicds_destroy(ptr
->info
);
929 if (ptr
->parent
->adc
[ptr
->num
] != NULL
)
930 spicds_destroy(ptr
->info
);
933 kfree(codec
, M_ENVY24
);
937 envy24_delta_ak4524_init(void *codec
)
940 u_int32_t gpiomask
, gpiodir
;
942 struct envy24_delta_ak4524_codec
*ptr
= codec
;
946 device_printf(ptr
->parent
->dev
, "envy24_delta_ak4524_init()\n");
950 gpiomask = envy24_gpiogetmask(ptr->parent);
951 gpiomask &= ~(ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1);
952 envy24_gpiosetmask(ptr->parent, gpiomask);
953 gpiodir = envy24_gpiogetdir(ptr->parent);
954 gpiodir |= ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1;
955 envy24_gpiosetdir(ptr->parent, gpiodir);
957 ptr
->cs
= ptr
->parent
->cfg
->cs
;
959 envy24_gpiosetmask(ptr
->parent
, ENVY24_GPIO_CS8414_STATUS
);
960 envy24_gpiosetdir(ptr
->parent
, ~ENVY24_GPIO_CS8414_STATUS
);
962 ptr
->cs
= ENVY24_GPIO_AK4524_CS0
;
964 ptr
->cs
= ENVY24_GPIO_AK4524_CS1
;
965 ptr
->cclk
= ENVY24_GPIO_AK4524_CCLK
;
967 ptr
->cclk
= ptr
->parent
->cfg
->cclk
;
968 ptr
->cdti
= ptr
->parent
->cfg
->cdti
;
969 spicds_settype(ptr
->info
, ptr
->parent
->cfg
->type
);
970 spicds_setcif(ptr
->info
, ptr
->parent
->cfg
->cif
);
971 spicds_setformat(ptr
->info
,
972 AK452X_FORMAT_I2S
| AK452X_FORMAT_256FSN
| AK452X_FORMAT_1X
);
973 spicds_setdvc(ptr
->info
, AK452X_DVC_DEMOFF
);
974 /* for the time being, init only first codec */
976 spicds_init(ptr
->info
);
978 /* 6fire rear input init test, set ptr->num to 1 for test */
979 if (ptr
->parent
->cfg
->subvendor
== 0x153b && \
980 ptr
->parent
->cfg
->subdevice
== 0x1138 && ptr
->num
== 100) {
982 spicds_init(ptr
->info
);
983 device_printf(ptr
->parent
->dev
, "6fire rear input init\n");
984 i2c_wr(ptr
, envy24_gpio_i2c_ctl
, \
985 PCA9554_I2CDEV
, PCA9554_DIR
, 0x80);
986 i2c_wr(ptr
, envy24_gpio_i2c_ctl
, \
987 PCA9554_I2CDEV
, PCA9554_OUT
, 0x02);
992 envy24_delta_ak4524_reinit(void *codec
)
994 struct envy24_delta_ak4524_codec
*ptr
= codec
;
998 device_printf(ptr
->parent
->dev
, "envy24_delta_ak4524_reinit()\n");
1001 spicds_reinit(ptr
->info
);
1005 envy24_delta_ak4524_setvolume(void *codec
, int dir
, unsigned int left
, unsigned int right
)
1007 struct envy24_delta_ak4524_codec
*ptr
= codec
;
1011 device_printf(ptr
->parent
->dev
, "envy24_delta_ak4524_set()\n");
1014 spicds_set(ptr
->info
, dir
, left
, right
);
1018 There is no need for AK452[48] codec to set sample rate
1020 envy24_delta_ak4524_setrate(struct envy24_delta_ak4524_codec *codec, int which, int rate)
1025 /* -------------------------------------------------------------------- */
1027 /* hardware access routeines */
1032 } envy24_speedtab
[] = {
1033 {48000, ENVY24_MT_RATE_48000
},
1034 {24000, ENVY24_MT_RATE_24000
},
1035 {12000, ENVY24_MT_RATE_12000
},
1036 {9600, ENVY24_MT_RATE_9600
},
1037 {32000, ENVY24_MT_RATE_32000
},
1038 {16000, ENVY24_MT_RATE_16000
},
1039 {8000, ENVY24_MT_RATE_8000
},
1040 {96000, ENVY24_MT_RATE_96000
},
1041 {64000, ENVY24_MT_RATE_64000
},
1042 {44100, ENVY24_MT_RATE_44100
},
1043 {22050, ENVY24_MT_RATE_22050
},
1044 {11025, ENVY24_MT_RATE_11025
},
1045 {88200, ENVY24_MT_RATE_88200
},
1050 envy24_setspeed(struct sc_info
*sc
, u_int32_t speed
) {
1055 device_printf(sc
->dev
, "envy24_setspeed(sc, %d)\n", speed
);
1058 code
= ENVY24_MT_RATE_SPDIF
; /* external master clock */
1062 for (i
= 0; envy24_speedtab
[i
].speed
!= 0; i
++) {
1063 if (envy24_speedtab
[i
].speed
== speed
)
1066 code
= envy24_speedtab
[i
].code
;
1069 device_printf(sc
->dev
, "envy24_setspeed(): speed %d/code 0x%04x\n", envy24_speedtab
[i
].speed
, code
);
1072 envy24_wrmt(sc
, ENVY24_MT_RATE
, code
, 1);
1073 code
= envy24_rdmt(sc
, ENVY24_MT_RATE
, 1);
1074 code
&= ENVY24_MT_RATE_MASK
;
1075 for (i
= 0; envy24_speedtab
[i
].code
< 0x10; i
++) {
1076 if (envy24_speedtab
[i
].code
== code
)
1079 speed
= envy24_speedtab
[i
].speed
;
1085 device_printf(sc
->dev
, "envy24_setspeed(): return %d\n", speed
);
1091 envy24_setvolume(struct sc_info
*sc
, unsigned ch
)
1094 device_printf(sc
->dev
, "envy24_setvolume(sc, %d)\n", ch
);
1096 if (sc
->cfg
->subvendor
==0x153b && sc
->cfg
->subdevice
==0x1138 ) {
1097 envy24_wrmt(sc
, ENVY24_MT_VOLIDX
, 16, 1);
1098 envy24_wrmt(sc
, ENVY24_MT_VOLUME
, 0x7f7f, 2);
1099 envy24_wrmt(sc
, ENVY24_MT_VOLIDX
, 17, 1);
1100 envy24_wrmt(sc
, ENVY24_MT_VOLUME
, 0x7f7f, 2);
1103 envy24_wrmt(sc
, ENVY24_MT_VOLIDX
, ch
* 2, 1);
1104 envy24_wrmt(sc
, ENVY24_MT_VOLUME
, 0x7f00 | sc
->left
[ch
], 2);
1105 envy24_wrmt(sc
, ENVY24_MT_VOLIDX
, ch
* 2 + 1, 1);
1106 envy24_wrmt(sc
, ENVY24_MT_VOLUME
, (sc
->right
[ch
] << 8) | 0x7f, 2);
1110 envy24_mutevolume(struct sc_info
*sc
, unsigned ch
)
1115 device_printf(sc
->dev
, "envy24_mutevolume(sc, %d)\n", ch
);
1117 vol
= ENVY24_VOL_MUTE
<< 8 | ENVY24_VOL_MUTE
;
1118 envy24_wrmt(sc
, ENVY24_MT_VOLIDX
, ch
* 2, 1);
1119 envy24_wrmt(sc
, ENVY24_MT_VOLUME
, vol
, 2);
1120 envy24_wrmt(sc
, ENVY24_MT_VOLIDX
, ch
* 2 + 1, 1);
1121 envy24_wrmt(sc
, ENVY24_MT_VOLUME
, vol
, 2);
1125 envy24_gethwptr(struct sc_info
*sc
, int dir
)
1131 device_printf(sc
->dev
, "envy24_gethwptr(sc, %d)\n", dir
);
1133 if (dir
== PCMDIR_PLAY
) {
1134 rtn
= sc
->psize
/ 4;
1135 unit
= ENVY24_PLAY_BUFUNIT
/ 4;
1136 regno
= ENVY24_MT_PCNT
;
1139 rtn
= sc
->rsize
/ 4;
1140 unit
= ENVY24_REC_BUFUNIT
/ 4;
1141 regno
= ENVY24_MT_RCNT
;
1144 ptr
= envy24_rdmt(sc
, regno
, 2);
1149 device_printf(sc
->dev
, "envy24_gethwptr(): return %d\n", rtn
);
1155 envy24_updintr(struct sc_info
*sc
, int dir
)
1157 int regptr
, regintr
;
1158 u_int32_t mask
, intr
;
1159 u_int32_t ptr
, size
, cnt
;
1163 device_printf(sc
->dev
, "envy24_updintr(sc, %d)\n", dir
);
1165 if (dir
== PCMDIR_PLAY
) {
1167 size
= sc
->psize
/ 4;
1168 regptr
= ENVY24_MT_PCNT
;
1169 regintr
= ENVY24_MT_PTERM
;
1170 mask
= ~ENVY24_MT_INT_PMASK
;
1174 size
= sc
->rsize
/ 4;
1175 regptr
= ENVY24_MT_RCNT
;
1176 regintr
= ENVY24_MT_RTERM
;
1177 mask
= ~ENVY24_MT_INT_RMASK
;
1180 ptr
= size
- envy24_rdmt(sc
, regptr
, 2) - 1;
1182 cnt = blk - ptr % blk - 1;
1188 device_printf(sc
->dev
, "envy24_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr
, blk
, cnt
);
1190 envy24_wrmt(sc
, regintr
, cnt
, 2);
1191 intr
= envy24_rdmt(sc
, ENVY24_MT_INT
, 1);
1193 device_printf(sc
->dev
, "envy24_updintr():intr = 0x%02x, mask = 0x%02x\n", intr
, mask
);
1195 envy24_wrmt(sc
, ENVY24_MT_INT
, intr
& mask
, 1);
1197 device_printf(sc
->dev
, "envy24_updintr():INT-->0x%02x\n",
1198 envy24_rdmt(sc
, ENVY24_MT_INT
, 1));
1206 envy24_maskintr(struct sc_info
*sc
, int dir
)
1208 u_int32_t mask
, intr
;
1211 device_printf(sc
->dev
, "envy24_maskintr(sc, %d)\n", dir
);
1213 if (dir
== PCMDIR_PLAY
)
1214 mask
= ENVY24_MT_INT_PMASK
;
1216 mask
= ENVY24_MT_INT_RMASK
;
1217 intr
= envy24_rdmt(sc
, ENVY24_MT_INT
, 1);
1218 envy24_wrmt(sc
, ENVY24_MT_INT
, intr
| mask
, 1);
1225 envy24_checkintr(struct sc_info
*sc
, int dir
)
1227 u_int32_t mask
, stat
, intr
, rtn
;
1230 device_printf(sc
->dev
, "envy24_checkintr(sc, %d)\n", dir
);
1232 intr
= envy24_rdmt(sc
, ENVY24_MT_INT
, 1);
1233 if (dir
== PCMDIR_PLAY
) {
1234 if ((rtn
= intr
& ENVY24_MT_INT_PSTAT
) != 0) {
1235 mask
= ~ENVY24_MT_INT_RSTAT
;
1236 stat
= ENVY24_MT_INT_PSTAT
| ENVY24_MT_INT_PMASK
;
1237 envy24_wrmt(sc
, ENVY24_MT_INT
, (intr
& mask
) | stat
, 1);
1241 if ((rtn
= intr
& ENVY24_MT_INT_RSTAT
) != 0) {
1242 mask
= ~ENVY24_MT_INT_PSTAT
;
1243 stat
= ENVY24_MT_INT_RSTAT
| ENVY24_MT_INT_RMASK
;
1244 envy24_wrmt(sc
, ENVY24_MT_INT
, (intr
& mask
) | stat
, 1);
1252 envy24_start(struct sc_info
*sc
, int dir
)
1257 device_printf(sc
->dev
, "envy24_start(sc, %d)\n", dir
);
1259 if (dir
== PCMDIR_PLAY
)
1260 sw
= ENVY24_MT_PCTL_PSTART
;
1262 sw
= ENVY24_MT_PCTL_RSTART
;
1264 stat
= envy24_rdmt(sc
, ENVY24_MT_PCTL
, 1);
1265 envy24_wrmt(sc
, ENVY24_MT_PCTL
, stat
| sw
, 1);
1268 device_printf(sc
->dev
, "PADDR:0x%08x\n", envy24_rdmt(sc
, ENVY24_MT_PADDR
, 4));
1269 device_printf(sc
->dev
, "PCNT:%ld\n", envy24_rdmt(sc
, ENVY24_MT_PCNT
, 2));
1276 envy24_stop(struct sc_info
*sc
, int dir
)
1281 device_printf(sc
->dev
, "envy24_stop(sc, %d)\n", dir
);
1283 if (dir
== PCMDIR_PLAY
)
1284 sw
= ~ENVY24_MT_PCTL_PSTART
;
1286 sw
= ~ENVY24_MT_PCTL_RSTART
;
1288 stat
= envy24_rdmt(sc
, ENVY24_MT_PCTL
, 1);
1289 envy24_wrmt(sc
, ENVY24_MT_PCTL
, stat
& sw
, 1);
1295 envy24_route(struct sc_info
*sc
, int dac
, int class, int adc
, int rev
)
1297 u_int32_t reg
, mask
;
1298 u_int32_t left
, right
;
1301 device_printf(sc
->dev
, "envy24_route(sc, %d, %d, %d, %d)\n",
1302 dac
, class, adc
, rev
);
1304 /* parameter pattern check */
1305 if (dac
< 0 || ENVY24_ROUTE_DAC_SPDIF
< dac
)
1307 if (class == ENVY24_ROUTE_CLASS_MIX
&&
1308 (dac
!= ENVY24_ROUTE_DAC_1
&& dac
!= ENVY24_ROUTE_DAC_SPDIF
))
1311 left
= ENVY24_ROUTE_RIGHT
;
1312 right
= ENVY24_ROUTE_LEFT
;
1315 left
= ENVY24_ROUTE_LEFT
;
1316 right
= ENVY24_ROUTE_RIGHT
;
1319 if (dac
== ENVY24_ROUTE_DAC_SPDIF
) {
1320 reg
= class | class << 2 |
1321 ((adc
<< 1 | left
) | left
<< 3) << 8 |
1322 ((adc
<< 1 | right
) | right
<< 3) << 12;
1324 device_printf(sc
->dev
, "envy24_route(): MT_SPDOUT-->0x%04x\n", reg
);
1326 envy24_wrmt(sc
, ENVY24_MT_SPDOUT
, reg
, 2);
1329 mask
= ~(0x0303 << dac
* 2);
1330 reg
= envy24_rdmt(sc
, ENVY24_MT_PSDOUT
, 2);
1331 reg
= (reg
& mask
) | ((class | class << 8) << dac
* 2);
1333 device_printf(sc
->dev
, "envy24_route(): MT_PSDOUT-->0x%04x\n", reg
);
1335 envy24_wrmt(sc
, ENVY24_MT_PSDOUT
, reg
, 2);
1336 mask
= ~(0xff << dac
* 8);
1337 reg
= envy24_rdmt(sc
, ENVY24_MT_RECORD
, 4);
1338 reg
= (reg
& mask
) |
1339 (((adc
<< 1 | left
) | left
<< 3) |
1340 ((adc
<< 1 | right
) | right
<< 3) << 4) << dac
* 8;
1342 device_printf(sc
->dev
, "envy24_route(): MT_RECORD-->0x%08x\n", reg
);
1344 envy24_wrmt(sc
, ENVY24_MT_RECORD
, reg
, 4);
1346 /* 6fire rear input init test */
1347 envy24_wrmt(sc
, ENVY24_MT_RECORD
, 0x00, 4);
1353 /* -------------------------------------------------------------------- */
1355 /* buffer copy routines */
1357 envy24_p32sl(struct sc_chinfo
*ch
)
1362 int src
, dst
, ssize
, dsize
, slot
;
1365 length
= sndbuf_getready(ch
->buffer
) / 8;
1366 dmabuf
= ch
->parent
->pbuf
;
1367 data
= (u_int32_t
*)ch
->data
;
1368 src
= sndbuf_getreadyptr(ch
->buffer
) / 4;
1369 dst
= src
/ 2 + ch
->offset
;
1370 ssize
= ch
->size
/ 4;
1371 dsize
= ch
->size
/ 8;
1374 for (i
= 0; i
< length
; i
++) {
1375 dmabuf
[dst
* ENVY24_PLAY_CHNUM
+ slot
].buffer
= data
[src
];
1376 dmabuf
[dst
* ENVY24_PLAY_CHNUM
+ slot
+ 1].buffer
= data
[src
+ 1];
1387 envy24_p16sl(struct sc_chinfo
*ch
)
1392 int src
, dst
, ssize
, dsize
, slot
;
1396 device_printf(ch
->parent
->dev
, "envy24_p16sl()\n");
1398 length
= sndbuf_getready(ch
->buffer
) / 4;
1399 dmabuf
= ch
->parent
->pbuf
;
1400 data
= (u_int16_t
*)ch
->data
;
1401 src
= sndbuf_getreadyptr(ch
->buffer
) / 2;
1402 dst
= src
/ 2 + ch
->offset
;
1403 ssize
= ch
->size
/ 2;
1404 dsize
= ch
->size
/ 4;
1407 device_printf(ch
->parent
->dev
, "envy24_p16sl():%lu-->%lu(%lu)\n", src
, dst
, length
);
1410 for (i
= 0; i
< length
; i
++) {
1411 dmabuf
[dst
* ENVY24_PLAY_CHNUM
+ slot
].buffer
= (u_int32_t
)data
[src
] << 16;
1412 dmabuf
[dst
* ENVY24_PLAY_CHNUM
+ slot
+ 1].buffer
= (u_int32_t
)data
[src
+ 1] << 16;
1415 printf("%08x", dmabuf
[dst
* ENVY24_PLAY_CHNUM
+ slot
]);
1416 printf("%08x", dmabuf
[dst
* ENVY24_PLAY_CHNUM
+ slot
+ 1]);
1432 envy24_p8u(struct sc_chinfo
*ch
)
1437 int src
, dst
, ssize
, dsize
, slot
;
1440 length
= sndbuf_getready(ch
->buffer
) / 2;
1441 dmabuf
= ch
->parent
->pbuf
;
1442 data
= (u_int8_t
*)ch
->data
;
1443 src
= sndbuf_getreadyptr(ch
->buffer
);
1444 dst
= src
/ 2 + ch
->offset
;
1446 dsize
= ch
->size
/ 4;
1449 for (i
= 0; i
< length
; i
++) {
1450 dmabuf
[dst
* ENVY24_PLAY_CHNUM
+ slot
].buffer
= ((u_int32_t
)data
[src
] ^ 0x80) << 24;
1451 dmabuf
[dst
* ENVY24_PLAY_CHNUM
+ slot
+ 1].buffer
= ((u_int32_t
)data
[src
+ 1] ^ 0x80) << 24;
1462 envy24_r32sl(struct sc_chinfo
*ch
)
1467 int src
, dst
, ssize
, dsize
, slot
;
1470 length
= sndbuf_getfree(ch
->buffer
) / 8;
1471 dmabuf
= ch
->parent
->rbuf
;
1472 data
= (u_int32_t
*)ch
->data
;
1473 dst
= sndbuf_getfreeptr(ch
->buffer
) / 4;
1474 src
= dst
/ 2 + ch
->offset
;
1475 dsize
= ch
->size
/ 4;
1476 ssize
= ch
->size
/ 8;
1477 slot
= (ch
->num
- ENVY24_CHAN_REC_ADC1
) * 2;
1479 for (i
= 0; i
< length
; i
++) {
1480 data
[dst
] = dmabuf
[src
* ENVY24_REC_CHNUM
+ slot
].buffer
;
1481 data
[dst
+ 1] = dmabuf
[src
* ENVY24_REC_CHNUM
+ slot
+ 1].buffer
;
1492 envy24_r16sl(struct sc_chinfo
*ch
)
1497 int src
, dst
, ssize
, dsize
, slot
;
1500 length
= sndbuf_getfree(ch
->buffer
) / 4;
1501 dmabuf
= ch
->parent
->rbuf
;
1502 data
= (u_int16_t
*)ch
->data
;
1503 dst
= sndbuf_getfreeptr(ch
->buffer
) / 2;
1504 src
= dst
/ 2 + ch
->offset
;
1505 dsize
= ch
->size
/ 2;
1506 ssize
= ch
->size
/ 8;
1507 slot
= (ch
->num
- ENVY24_CHAN_REC_ADC1
) * 2;
1509 for (i
= 0; i
< length
; i
++) {
1510 data
[dst
] = dmabuf
[src
* ENVY24_REC_CHNUM
+ slot
].buffer
;
1511 data
[dst
+ 1] = dmabuf
[src
* ENVY24_REC_CHNUM
+ slot
+ 1].buffer
;
1521 /* -------------------------------------------------------------------- */
1523 /* channel interface */
1525 envy24chan_init(kobj_t obj
, void *devinfo
, struct snd_dbuf
*b
, struct pcm_channel
*c
, int dir
)
1527 struct sc_info
*sc
= (struct sc_info
*)devinfo
;
1528 struct sc_chinfo
*ch
;
1532 device_printf(sc
->dev
, "envy24chan_init(obj, devinfo, b, c, %d)\n", dir
);
1534 snd_mtxlock(sc
->lock
);
1535 if ((sc
->chnum
> ENVY24_CHAN_PLAY_SPDIF
&& dir
!= PCMDIR_REC
) ||
1536 (sc
->chnum
< ENVY24_CHAN_REC_ADC1
&& dir
!= PCMDIR_PLAY
)) {
1537 snd_mtxunlock(sc
->lock
);
1542 ch
= &sc
->chan
[num
];
1543 ch
->size
= 8 * ENVY24_SAMPLE_NUM
;
1544 ch
->data
= kmalloc(ch
->size
, M_ENVY24
, M_NOWAIT
);
1545 if (ch
->data
== NULL
) {
1554 /* set channel map */
1555 ch
->num
= envy24_chanmap
[num
];
1556 snd_mtxunlock(sc
->lock
);
1557 sndbuf_setup(ch
->buffer
, ch
->data
, ch
->size
);
1558 snd_mtxlock(sc
->lock
);
1559 /* these 2 values are dummy */
1563 snd_mtxunlock(sc
->lock
);
1569 envy24chan_free(kobj_t obj
, void *data
)
1571 struct sc_chinfo
*ch
= data
;
1572 struct sc_info
*sc
= ch
->parent
;
1575 device_printf(sc
->dev
, "envy24chan_free()\n");
1577 snd_mtxlock(sc
->lock
);
1578 if (ch
->data
!= NULL
) {
1579 kfree(ch
->data
, M_ENVY24
);
1582 snd_mtxunlock(sc
->lock
);
1588 envy24chan_setformat(kobj_t obj
, void *data
, u_int32_t format
)
1590 struct sc_chinfo
*ch
= data
;
1591 struct sc_info
*sc
= ch
->parent
;
1592 struct envy24_emldma
*emltab
;
1593 /* unsigned int bcnt, bsize; */
1597 device_printf(sc
->dev
, "envy24chan_setformat(obj, data, 0x%08x)\n", format
);
1599 snd_mtxlock(sc
->lock
);
1600 /* check and get format related information */
1601 if (ch
->dir
== PCMDIR_PLAY
)
1602 emltab
= envy24_pemltab
;
1604 emltab
= envy24_remltab
;
1605 if (emltab
== NULL
) {
1606 snd_mtxunlock(sc
->lock
);
1609 for (i
= 0; emltab
[i
].format
!= 0; i
++)
1610 if (emltab
[i
].format
== format
)
1612 if (emltab
[i
].format
== 0) {
1613 snd_mtxunlock(sc
->lock
);
1617 /* set format information */
1618 ch
->format
= format
;
1619 ch
->emldma
= emltab
[i
].emldma
;
1620 if (ch
->unit
> emltab
[i
].unit
)
1621 ch
->blk
*= ch
->unit
/ emltab
[i
].unit
;
1623 ch
->blk
/= emltab
[i
].unit
/ ch
->unit
;
1624 ch
->unit
= emltab
[i
].unit
;
1626 /* set channel buffer information */
1627 ch
->size
= ch
->unit
* ENVY24_SAMPLE_NUM
;
1629 if (ch
->dir
== PCMDIR_PLAY
)
1630 bsize
= ch
->blk
* 4 / ENVY24_PLAY_BUFUNIT
;
1632 bsize
= ch
->blk
* 4 / ENVY24_REC_BUFUNIT
;
1634 bcnt
= ch
->size
/ bsize
;
1635 sndbuf_resize(ch
->buffer
, bcnt
, bsize
);
1637 snd_mtxunlock(sc
->lock
);
1640 device_printf(sc
->dev
, "envy24chan_setformat(): return 0x%08x\n", 0);
1646 IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1647 of speed information value. And real hardware speed setting is done
1648 at start triggered(see envy24chan_trigger()). So, at this function
1649 is called, any value that ENVY24 can use is able to set. But, at
1650 start triggerd, some other channel is running, and that channel's
1651 speed isn't same with, then trigger function will fail.
1654 envy24chan_setspeed(kobj_t obj
, void *data
, u_int32_t speed
)
1656 struct sc_chinfo
*ch
= data
;
1657 u_int32_t val
, prev
;
1661 device_printf(ch
->parent
->dev
, "envy24chan_setspeed(obj, data, %d)\n", speed
);
1664 for (i
= 0; (val
= envy24_speed
[i
]) != 0; i
++) {
1665 if (abs(val
- speed
) < abs(prev
- speed
))
1673 device_printf(ch
->parent
->dev
, "envy24chan_setspeed(): return %d\n", ch
->speed
);
1679 envy24chan_setblocksize(kobj_t obj
, void *data
, u_int32_t blocksize
)
1681 struct sc_chinfo
*ch
= data
;
1682 /* struct sc_info *sc = ch->parent; */
1683 u_int32_t size
, prev
;
1684 unsigned int bcnt
, bsize
;
1687 device_printf(sc
->dev
, "envy24chan_setblocksize(obj, data, %d)\n", blocksize
);
1690 /* snd_mtxlock(sc->lock); */
1691 for (size
= ch
->size
/ 2; size
> 0; size
/= 2) {
1692 if (abs(size
- blocksize
) < abs(prev
- blocksize
))
1698 ch
->blk
= prev
/ ch
->unit
;
1699 if (ch
->dir
== PCMDIR_PLAY
)
1700 ch
->blk
*= ENVY24_PLAY_BUFUNIT
/ 4;
1702 ch
->blk
*= ENVY24_REC_BUFUNIT
/ 4;
1703 /* set channel buffer information */
1704 /* ch->size = ch->unit * ENVY24_SAMPLE_NUM; */
1705 if (ch
->dir
== PCMDIR_PLAY
)
1706 bsize
= ch
->blk
* 4 / ENVY24_PLAY_BUFUNIT
;
1708 bsize
= ch
->blk
* 4 / ENVY24_REC_BUFUNIT
;
1710 bcnt
= ch
->size
/ bsize
;
1711 sndbuf_resize(ch
->buffer
, bcnt
, bsize
);
1712 /* snd_mtxunlock(sc->lock); */
1715 device_printf(sc
->dev
, "envy24chan_setblocksize(): return %d\n", prev
);
1720 /* semantic note: must start at beginning of buffer */
1722 envy24chan_trigger(kobj_t obj
, void *data
, int go
)
1724 struct sc_chinfo
*ch
= data
;
1725 struct sc_info
*sc
= ch
->parent
;
1731 device_printf(sc
->dev
, "envy24chan_trigger(obj, data, %d)\n", go
);
1733 snd_mtxlock(sc
->lock
);
1734 if (ch
->dir
== PCMDIR_PLAY
)
1741 device_printf(sc
->dev
, "envy24chan_trigger(): start\n");
1743 /* check or set channel speed */
1744 if (sc
->run
[0] == 0 && sc
->run
[1] == 0) {
1745 sc
->speed
= envy24_setspeed(sc
, ch
->speed
);
1746 sc
->caps
[0].minspeed
= sc
->caps
[0].maxspeed
= sc
->speed
;
1747 sc
->caps
[1].minspeed
= sc
->caps
[1].maxspeed
= sc
->speed
;
1749 else if (ch
->speed
!= 0 && ch
->speed
!= sc
->speed
)
1752 ch
->channel
->speed
= sc
->speed
;
1753 /* start or enable channel */
1755 if (sc
->run
[slot
] == 1) {
1758 sc
->blk
[slot
] = ch
->blk
;
1761 ptr
= envy24_gethwptr(sc
, ch
->dir
);
1762 ch
->offset
= ((ptr
/ ch
->blk
+ 1) * ch
->blk
%
1763 (ch
->size
/ 4)) * 4 / ch
->unit
;
1764 if (ch
->blk
< sc
->blk
[slot
])
1765 sc
->blk
[slot
] = ch
->blk
;
1767 if (ch
->dir
== PCMDIR_PLAY
) {
1769 envy24_setvolume(sc
, ch
->num
);
1771 envy24_updintr(sc
, ch
->dir
);
1772 if (sc
->run
[slot
] == 1)
1773 envy24_start(sc
, ch
->dir
);
1776 case PCMTRIG_EMLDMAWR
:
1778 device_printf(sc
->dev
, "envy24chan_trigger(): emldmawr\n");
1784 case PCMTRIG_EMLDMARD
:
1786 device_printf(sc
->dev
, "envy24chan_trigger(): emldmard\n");
1795 device_printf(sc
->dev
, "envy24chan_trigger(): abort\n");
1799 if (ch
->dir
== PCMDIR_PLAY
)
1800 envy24_mutevolume(sc
, ch
->num
);
1801 if (sc
->run
[slot
] == 0) {
1802 envy24_stop(sc
, ch
->dir
);
1806 else if (ch
->blk
== sc
->blk
[slot
]) {
1807 sc
->blk
[slot
] = ENVY24_SAMPLE_NUM
/ 2;
1808 for (i
= 0; i
< ENVY24_CHAN_NUM
; i
++) {
1809 if (sc
->chan
[i
].dir
== ch
->dir
&&
1810 sc
->chan
[i
].run
== 1 &&
1811 sc
->chan
[i
].blk
< sc
->blk
[slot
])
1812 sc
->blk
[slot
] = sc
->chan
[i
].blk
;
1814 if (ch
->blk
!= sc
->blk
[slot
])
1815 envy24_updintr(sc
, ch
->dir
);
1821 snd_mtxunlock(sc
->lock
);
1827 envy24chan_getptr(kobj_t obj
, void *data
)
1829 struct sc_chinfo
*ch
= data
;
1830 struct sc_info
*sc
= ch
->parent
;
1835 device_printf(sc
->dev
, "envy24chan_getptr()\n");
1837 snd_mtxlock(sc
->lock
);
1838 ptr
= envy24_gethwptr(sc
, ch
->dir
);
1839 rtn
= ptr
* ch
->unit
;
1840 snd_mtxunlock(sc
->lock
);
1843 device_printf(sc
->dev
, "envy24chan_getptr(): return %d\n",
1849 static struct pcmchan_caps
*
1850 envy24chan_getcaps(kobj_t obj
, void *data
)
1852 struct sc_chinfo
*ch
= data
;
1853 struct sc_info
*sc
= ch
->parent
;
1854 struct pcmchan_caps
*rtn
;
1857 device_printf(sc
->dev
, "envy24chan_getcaps()\n");
1859 snd_mtxlock(sc
->lock
);
1860 if (ch
->dir
== PCMDIR_PLAY
) {
1861 if (sc
->run
[0] == 0)
1862 rtn
= &envy24_playcaps
;
1867 if (sc
->run
[1] == 0)
1868 rtn
= &envy24_reccaps
;
1872 snd_mtxunlock(sc
->lock
);
1877 static kobj_method_t envy24chan_methods
[] = {
1878 KOBJMETHOD(channel_init
, envy24chan_init
),
1879 KOBJMETHOD(channel_free
, envy24chan_free
),
1880 KOBJMETHOD(channel_setformat
, envy24chan_setformat
),
1881 KOBJMETHOD(channel_setspeed
, envy24chan_setspeed
),
1882 KOBJMETHOD(channel_setblocksize
, envy24chan_setblocksize
),
1883 KOBJMETHOD(channel_trigger
, envy24chan_trigger
),
1884 KOBJMETHOD(channel_getptr
, envy24chan_getptr
),
1885 KOBJMETHOD(channel_getcaps
, envy24chan_getcaps
),
1888 CHANNEL_DECLARE(envy24chan
);
1890 /* -------------------------------------------------------------------- */
1892 /* mixer interface */
1895 envy24mixer_init(struct snd_mixer
*m
)
1897 struct sc_info
*sc
= mix_getdevinfo(m
);
1900 device_printf(sc
->dev
, "envy24mixer_init()\n");
1905 /* set volume control rate */
1906 snd_mtxlock(sc
->lock
);
1907 envy24_wrmt(sc
, ENVY24_MT_VOLRATE
, 0x30, 1); /* 0x30 is default value */
1909 mix_setdevs(m
, ENVY24_MIX_MASK
);
1910 mix_setrecdevs(m
, ENVY24_MIX_REC_MASK
);
1911 snd_mtxunlock(sc
->lock
);
1917 envy24mixer_reinit(struct snd_mixer
*m
)
1919 struct sc_info
*sc
= mix_getdevinfo(m
);
1924 device_printf(sc
->dev
, "envy24mixer_reinit()\n");
1931 envy24mixer_uninit(struct snd_mixer
*m
)
1933 struct sc_info
*sc
= mix_getdevinfo(m
);
1938 device_printf(sc
->dev
, "envy24mixer_uninit()\n");
1945 envy24mixer_set(struct snd_mixer
*m
, unsigned dev
, unsigned left
, unsigned right
)
1947 struct sc_info
*sc
= mix_getdevinfo(m
);
1948 int ch
= envy24_mixmap
[dev
];
1954 if (dev
== 0 && sc
->cfg
->codec
->setvolume
== NULL
)
1956 if (dev
!= 0 && ch
== -1)
1958 hwch
= envy24_chanmap
[ch
];
1960 device_printf(sc
->dev
, "envy24mixer_set(m, %d, %d, %d)\n",
1964 snd_mtxlock(sc
->lock
);
1966 for (i
= 0; i
< sc
->dacn
; i
++) {
1967 sc
->cfg
->codec
->setvolume(sc
->dac
[i
], PCMDIR_PLAY
, left
, right
);
1971 /* set volume value for hardware */
1972 if ((sc
->left
[hwch
] = 100 - left
) > ENVY24_VOL_MIN
)
1973 sc
->left
[hwch
] = ENVY24_VOL_MUTE
;
1974 if ((sc
->right
[hwch
] = 100 - right
) > ENVY24_VOL_MIN
)
1975 sc
->right
[hwch
] = ENVY24_VOL_MUTE
;
1977 /* set volume for record channel and running play channel */
1978 if (hwch
> ENVY24_CHAN_PLAY_SPDIF
|| sc
->chan
[ch
].run
)
1979 envy24_setvolume(sc
, hwch
);
1981 snd_mtxunlock(sc
->lock
);
1983 return right
<< 8 | left
;
1987 envy24mixer_setrecsrc(struct snd_mixer
*m
, u_int32_t src
)
1989 struct sc_info
*sc
= mix_getdevinfo(m
);
1990 int ch
= envy24_mixmap
[src
];
1992 device_printf(sc
->dev
, "envy24mixer_setrecsrc(m, %d)\n", src
);
1995 if (ch
> ENVY24_CHAN_PLAY_SPDIF
)
2000 static kobj_method_t envy24mixer_methods
[] = {
2001 KOBJMETHOD(mixer_init
, envy24mixer_init
),
2002 KOBJMETHOD(mixer_reinit
, envy24mixer_reinit
),
2003 KOBJMETHOD(mixer_uninit
, envy24mixer_uninit
),
2004 KOBJMETHOD(mixer_set
, envy24mixer_set
),
2005 KOBJMETHOD(mixer_setrecsrc
, envy24mixer_setrecsrc
),
2008 MIXER_DECLARE(envy24mixer
);
2010 /* -------------------------------------------------------------------- */
2012 /* The interrupt handler */
2014 envy24_intr(void *p
)
2016 struct sc_info
*sc
= (struct sc_info
*)p
;
2017 struct sc_chinfo
*ch
;
2018 u_int32_t ptr
, dsize
, feed
;
2022 device_printf(sc
->dev
, "envy24_intr()\n");
2024 snd_mtxlock(sc
->lock
);
2025 if (envy24_checkintr(sc
, PCMDIR_PLAY
)) {
2027 device_printf(sc
->dev
, "envy24_intr(): play\n");
2029 dsize
= sc
->psize
/ 4;
2030 ptr
= dsize
- envy24_rdmt(sc
, ENVY24_MT_PCNT
, 2) - 1;
2032 device_printf(sc
->dev
, "envy24_intr(): ptr = %d-->", ptr
);
2034 ptr
-= ptr
% sc
->blk
[0];
2035 feed
= (ptr
+ dsize
- sc
->intr
[0]) % dsize
;
2037 printf("%d intr = %d feed = %d\n", ptr
, sc
->intr
[0], feed
);
2039 for (i
= ENVY24_CHAN_PLAY_DAC1
; i
<= ENVY24_CHAN_PLAY_SPDIF
; i
++) {
2043 device_printf(sc
->dev
, "envy24_intr(): chan[%d].blk = %d\n", i
, ch
->blk
);
2045 if (ch
->run
&& ch
->blk
<= feed
) {
2046 snd_mtxunlock(sc
->lock
);
2047 chn_intr(ch
->channel
);
2048 snd_mtxlock(sc
->lock
);
2052 envy24_updintr(sc
, PCMDIR_PLAY
);
2054 if (envy24_checkintr(sc
, PCMDIR_REC
)) {
2056 device_printf(sc
->dev
, "envy24_intr(): rec\n");
2058 dsize
= sc
->rsize
/ 4;
2059 ptr
= dsize
- envy24_rdmt(sc
, ENVY24_MT_RCNT
, 2) - 1;
2060 ptr
-= ptr
% sc
->blk
[1];
2061 feed
= (ptr
+ dsize
- sc
->intr
[1]) % dsize
;
2062 for (i
= ENVY24_CHAN_REC_ADC1
; i
<= ENVY24_CHAN_REC_SPDIF
; i
++) {
2064 if (ch
->run
&& ch
->blk
<= feed
) {
2065 snd_mtxunlock(sc
->lock
);
2066 chn_intr(ch
->channel
);
2067 snd_mtxlock(sc
->lock
);
2071 envy24_updintr(sc
, PCMDIR_REC
);
2073 snd_mtxunlock(sc
->lock
);
2079 * Probe and attach the card
2083 envy24_pci_probe(device_t dev
)
2089 printf("envy24_pci_probe()\n");
2091 if (pci_get_device(dev
) == PCID_ENVY24
&&
2092 pci_get_vendor(dev
) == PCIV_ENVY24
) {
2093 sv
= pci_get_subvendor(dev
);
2094 sd
= pci_get_subdevice(dev
);
2095 for (i
= 0; cfg_table
[i
].subvendor
!= 0 || cfg_table
[i
].subdevice
!= 0; i
++) {
2096 if (cfg_table
[i
].subvendor
== sv
&&
2097 cfg_table
[i
].subdevice
== sd
) {
2101 device_set_desc(dev
, cfg_table
[i
].name
);
2103 printf("envy24_pci_probe(): return 0\n");
2109 printf("envy24_pci_probe(): return ENXIO\n");
2116 envy24_dmapsetmap(void *arg
, bus_dma_segment_t
*segs
, int nseg
, int error
)
2118 /* struct sc_info *sc = (struct sc_info *)arg; */
2121 device_printf(sc
->dev
, "envy24_dmapsetmap()\n");
2123 printf("envy24(play): setmap %lx, %lx; ",
2124 (unsigned long)segs
->ds_addr
,
2125 (unsigned long)segs
->ds_len
);
2126 printf("%p -> %lx\n", sc
->pmap
, (unsigned long)vtophys(sc
->pmap
));
2132 envy24_dmarsetmap(void *arg
, bus_dma_segment_t
*segs
, int nseg
, int error
)
2134 /* struct sc_info *sc = (struct sc_info *)arg; */
2137 device_printf(sc
->dev
, "envy24_dmarsetmap()\n");
2139 printf("envy24(record): setmap %lx, %lx; ",
2140 (unsigned long)segs
->ds_addr
,
2141 (unsigned long)segs
->ds_len
);
2142 printf("%p -> %lx\n", sc
->rmap
, (unsigned long)vtophys(sc
->pmap
));
2148 envy24_dmafree(struct sc_info
*sc
)
2151 device_printf(sc
->dev
, "envy24_dmafree():");
2152 if (sc
->rmap
) printf(" sc->rmap(0x%08x)", (u_int32_t
)sc
->rmap
);
2153 else printf(" sc->rmap(null)");
2154 if (sc
->pmap
) printf(" sc->pmap(0x%08x)", (u_int32_t
)sc
->pmap
);
2155 else printf(" sc->pmap(null)");
2156 if (sc
->rbuf
) printf(" sc->rbuf(0x%08x)", (u_int32_t
)sc
->rbuf
);
2157 else printf(" sc->rbuf(null)");
2158 if (sc
->pbuf
) printf(" sc->pbuf(0x%08x)\n", (u_int32_t
)sc
->pbuf
);
2159 else printf(" sc->pbuf(null)\n");
2163 bus_dmamap_unload(sc
->dmat
, sc
->rmap
);
2165 bus_dmamap_unload(sc
->dmat
, sc
->pmap
);
2167 bus_dmamem_free(sc
->dmat
, sc
->rbuf
, sc
->rmap
);
2169 bus_dmamem_free(sc
->dmat
, sc
->pbuf
, sc
->pmap
);
2171 bus_dmamap_unload(sc
->dmat
, sc
->rmap
);
2172 bus_dmamap_unload(sc
->dmat
, sc
->pmap
);
2173 bus_dmamem_free(sc
->dmat
, sc
->rbuf
, sc
->rmap
);
2174 bus_dmamem_free(sc
->dmat
, sc
->pbuf
, sc
->pmap
);
2177 sc
->rmap
= sc
->pmap
= NULL
;
2185 envy24_dmainit(struct sc_info
*sc
)
2190 device_printf(sc
->dev
, "envy24_dmainit()\n");
2193 sc
->psize
= ENVY24_PLAY_BUFUNIT
* ENVY24_SAMPLE_NUM
;
2194 sc
->rsize
= ENVY24_REC_BUFUNIT
* ENVY24_SAMPLE_NUM
;
2197 sc
->pmap
= sc
->rmap
= NULL
;
2198 sc
->blk
[0] = sc
->blk
[1] = 0;
2200 /* allocate DMA buffer */
2202 device_printf(sc
->dev
, "envy24_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2204 if (bus_dmamem_alloc(sc
->dmat
, (void **)&sc
->pbuf
, BUS_DMA_NOWAIT
, &sc
->pmap
))
2207 device_printf(sc
->dev
, "envy24_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2209 if (bus_dmamem_alloc(sc
->dmat
, (void **)&sc
->rbuf
, BUS_DMA_NOWAIT
, &sc
->rmap
))
2212 device_printf(sc
->dev
, "envy24_dmainit(): bus_dmamem_load(): sc->pmap\n");
2214 if (bus_dmamap_load(sc
->dmat
, sc
->pmap
, sc
->pbuf
, sc
->psize
, envy24_dmapsetmap
, sc
, 0))
2217 device_printf(sc
->dev
, "envy24_dmainit(): bus_dmamem_load(): sc->rmap\n");
2219 if (bus_dmamap_load(sc
->dmat
, sc
->rmap
, sc
->rbuf
, sc
->rsize
, envy24_dmarsetmap
, sc
, 0))
2221 bzero(sc
->pbuf
, sc
->psize
);
2222 bzero(sc
->rbuf
, sc
->rsize
);
2224 /* set values to register */
2225 addr
= vtophys(sc
->pbuf
);
2227 device_printf(sc
->dev
, "pbuf(0x%08x)\n", addr
);
2229 envy24_wrmt(sc
, ENVY24_MT_PADDR
, addr
, 4);
2231 device_printf(sc
->dev
, "PADDR-->(0x%08x)\n", envy24_rdmt(sc
, ENVY24_MT_PADDR
, 4));
2232 device_printf(sc
->dev
, "psize(%ld)\n", sc
->psize
/ 4 - 1);
2234 envy24_wrmt(sc
, ENVY24_MT_PCNT
, sc
->psize
/ 4 - 1, 2);
2236 device_printf(sc
->dev
, "PCNT-->(%ld)\n", envy24_rdmt(sc
, ENVY24_MT_PCNT
, 2));
2238 addr
= vtophys(sc
->rbuf
);
2239 envy24_wrmt(sc
, ENVY24_MT_RADDR
, addr
, 4);
2240 envy24_wrmt(sc
, ENVY24_MT_RCNT
, sc
->rsize
/ 4 - 1, 2);
2249 envy24_putcfg(struct sc_info
*sc
)
2251 device_printf(sc
->dev
, "system configuration\n");
2252 kprintf(" SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2253 sc
->cfg
->subvendor
, sc
->cfg
->subdevice
);
2254 kprintf(" XIN2 Clock Source: ");
2255 switch (sc
->cfg
->scfg
& PCIM_SCFG_XIN2
) {
2257 kprintf("22.5792MHz(44.1kHz*512)\n");
2260 kprintf("16.9344MHz(44.1kHz*384)\n");
2263 kprintf("from external clock synthesizer chip\n");
2266 kprintf("illeagal system setting\n");
2268 kprintf(" MPU-401 UART(s) #: ");
2269 if (sc
->cfg
->scfg
& PCIM_SCFG_MPU
)
2273 kprintf(" AC'97 codec: ");
2274 if (sc
->cfg
->scfg
& PCIM_SCFG_AC97
)
2275 kprintf("not exist\n");
2278 kprintf(" ADC #: ");
2279 kprintf("%d\n", sc
->adcn
);
2280 kprintf(" DAC #: ");
2281 kprintf("%d\n", sc
->dacn
);
2282 kprintf(" Multi-track converter type: ");
2283 if ((sc
->cfg
->acl
& PCIM_ACL_MTC
) == 0) {
2284 kprintf("AC'97(SDATA_OUT:");
2285 if (sc
->cfg
->acl
& PCIM_ACL_OMODE
)
2289 kprintf("|SDATA_IN:");
2290 if (sc
->cfg
->acl
& PCIM_ACL_IMODE
)
2298 if (sc
->cfg
->i2s
& PCIM_I2S_VOL
)
2299 kprintf("with volume, ");
2300 if (sc
->cfg
->i2s
& PCIM_I2S_96KHZ
)
2301 kprintf("96KHz support, ");
2302 switch (sc
->cfg
->i2s
& PCIM_I2S_RES
) {
2303 case PCIM_I2S_16BIT
:
2304 kprintf("16bit resolution, ");
2306 case PCIM_I2S_18BIT
:
2307 kprintf("18bit resolution, ");
2309 case PCIM_I2S_20BIT
:
2310 kprintf("20bit resolution, ");
2312 case PCIM_I2S_24BIT
:
2313 kprintf("24bit resolution, ");
2316 kprintf("ID#0x%x)\n", sc
->cfg
->i2s
& PCIM_I2S_ID
);
2318 kprintf(" S/PDIF(IN/OUT): ");
2319 if (sc
->cfg
->spdif
& PCIM_SPDIF_IN
)
2323 if (sc
->cfg
->spdif
& PCIM_SPDIF_OUT
)
2327 if (sc
->cfg
->spdif
& (PCIM_SPDIF_IN
| PCIM_SPDIF_OUT
))
2328 kprintf("ID# 0x%02x\n", (sc
->cfg
->spdif
& PCIM_SPDIF_ID
) >> 2);
2329 kprintf(" GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2330 sc
->cfg
->gpiomask
, sc
->cfg
->gpiodir
, sc
->cfg
->gpiostate
);
2334 envy24_init(struct sc_info
*sc
)
2345 device_printf(sc
->dev
, "envy24_init()\n");
2349 envy24_wrcs(sc
, ENVY24_CCS_CTL
, ENVY24_CCS_CTL_RESET
| ENVY24_CCS_CTL_NATIVE
, 1);
2351 envy24_wrcs(sc
, ENVY24_CCS_CTL
, ENVY24_CCS_CTL_NATIVE
, 1);
2354 /* legacy hardware disable */
2355 data
= pci_read_config(sc
->dev
, PCIR_LAC
, 2);
2356 data
|= PCIM_LAC_DISABLE
;
2357 pci_write_config(sc
->dev
, PCIR_LAC
, data
, 2);
2359 /* check system configuration */
2361 for (i
= 0; cfg_table
[i
].subvendor
!= 0 || cfg_table
[i
].subdevice
!= 0; i
++) {
2362 /* 1st: search configuration from table */
2363 sv
= pci_get_subvendor(sc
->dev
);
2364 sd
= pci_get_subdevice(sc
->dev
);
2365 if (sv
== cfg_table
[i
].subvendor
&& sd
== cfg_table
[i
].subdevice
) {
2367 device_printf(sc
->dev
, "Set configuration from table\n");
2369 sc
->cfg
= &cfg_table
[i
];
2373 if (sc
->cfg
== NULL
) {
2374 /* 2nd: read configuration from table */
2375 sc
->cfg
= envy24_rom2cfg(sc
);
2377 sc
->adcn
= ((sc
->cfg
->scfg
& PCIM_SCFG_ADC
) >> 2) + 1;
2378 sc
->dacn
= (sc
->cfg
->scfg
& PCIM_SCFG_DAC
) + 1;
2380 if (1 /* bootverbose */) {
2384 /* set system configuration */
2385 pci_write_config(sc
->dev
, PCIR_SCFG
, sc
->cfg
->scfg
, 1);
2386 pci_write_config(sc
->dev
, PCIR_ACL
, sc
->cfg
->acl
, 1);
2387 pci_write_config(sc
->dev
, PCIR_I2S
, sc
->cfg
->i2s
, 1);
2388 pci_write_config(sc
->dev
, PCIR_SPDIF
, sc
->cfg
->spdif
, 1);
2389 envy24_gpiosetmask(sc
, sc
->cfg
->gpiomask
);
2390 envy24_gpiosetdir(sc
, sc
->cfg
->gpiodir
);
2391 envy24_gpiowr(sc
, sc
->cfg
->gpiostate
);
2392 for (i
= 0; i
< sc
->adcn
; i
++) {
2393 sc
->adc
[i
] = sc
->cfg
->codec
->create(sc
->dev
, sc
, PCMDIR_REC
, i
);
2394 sc
->cfg
->codec
->init(sc
->adc
[i
]);
2396 for (i
= 0; i
< sc
->dacn
; i
++) {
2397 sc
->dac
[i
] = sc
->cfg
->codec
->create(sc
->dev
, sc
, PCMDIR_PLAY
, i
);
2398 sc
->cfg
->codec
->init(sc
->dac
[i
]);
2401 /* initialize DMA buffer */
2403 device_printf(sc
->dev
, "envy24_init(): initialize DMA buffer\n");
2405 if (envy24_dmainit(sc
))
2408 /* initialize status */
2409 sc
->run
[0] = sc
->run
[1] = 0;
2410 sc
->intr
[0] = sc
->intr
[1] = 0;
2412 sc
->caps
[0].fmtlist
= envy24_playfmt
;
2413 sc
->caps
[1].fmtlist
= envy24_recfmt
;
2415 /* set channel router */
2416 envy24_route(sc
, ENVY24_ROUTE_DAC_1
, ENVY24_ROUTE_CLASS_MIX
, 0, 0);
2417 envy24_route(sc
, ENVY24_ROUTE_DAC_SPDIF
, ENVY24_ROUTE_CLASS_DMA
, 0, 0);
2418 /* envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_MIX, 0, 0); */
2420 /* set macro interrupt mask */
2421 data
= envy24_rdcs(sc
, ENVY24_CCS_IMASK
, 1);
2422 envy24_wrcs(sc
, ENVY24_CCS_IMASK
, data
& ~ENVY24_CCS_IMASK_PMT
, 1);
2423 data
= envy24_rdcs(sc
, ENVY24_CCS_IMASK
, 1);
2425 device_printf(sc
->dev
, "envy24_init(): CCS_IMASK-->0x%02x\n", data
);
2432 envy24_alloc_resource(struct sc_info
*sc
)
2434 /* allocate I/O port resource */
2435 sc
->csid
= PCIR_CCS
;
2436 sc
->cs
= bus_alloc_resource(sc
->dev
, SYS_RES_IOPORT
,
2437 &sc
->csid
, 0, ~0, 1, RF_ACTIVE
);
2438 sc
->ddmaid
= PCIR_DDMA
;
2439 sc
->ddma
= bus_alloc_resource(sc
->dev
, SYS_RES_IOPORT
,
2440 &sc
->ddmaid
, 0, ~0, 1, RF_ACTIVE
);
2442 sc
->ds
= bus_alloc_resource(sc
->dev
, SYS_RES_IOPORT
,
2443 &sc
->dsid
, 0, ~0, 1, RF_ACTIVE
);
2445 sc
->mt
= bus_alloc_resource(sc
->dev
, SYS_RES_IOPORT
,
2446 &sc
->mtid
, 0, ~0, 1, RF_ACTIVE
);
2447 if (!sc
->cs
|| !sc
->ddma
|| !sc
->ds
|| !sc
->mt
) {
2448 device_printf(sc
->dev
, "unable to map IO port space\n");
2451 sc
->cst
= rman_get_bustag(sc
->cs
);
2452 sc
->csh
= rman_get_bushandle(sc
->cs
);
2453 sc
->ddmat
= rman_get_bustag(sc
->ddma
);
2454 sc
->ddmah
= rman_get_bushandle(sc
->ddma
);
2455 sc
->dst
= rman_get_bustag(sc
->ds
);
2456 sc
->dsh
= rman_get_bushandle(sc
->ds
);
2457 sc
->mtt
= rman_get_bustag(sc
->mt
);
2458 sc
->mth
= rman_get_bushandle(sc
->mt
);
2460 device_printf(sc
->dev
,
2461 "IO port register values\nCCS: 0x%lx\nDDMA: 0x%lx\nDS: 0x%lx\nMT: 0x%lx\n",
2462 pci_read_config(sc
->dev
, PCIR_CCS
, 4),
2463 pci_read_config(sc
->dev
, PCIR_DDMA
, 4),
2464 pci_read_config(sc
->dev
, PCIR_DS
, 4),
2465 pci_read_config(sc
->dev
, PCIR_MT
, 4));
2468 /* allocate interupt resource */
2470 sc
->irq
= bus_alloc_resource(sc
->dev
, SYS_RES_IRQ
, &sc
->irqid
,
2471 0, ~0, 1, RF_ACTIVE
| RF_SHAREABLE
);
2473 snd_setup_intr(sc
->dev
, sc
->irq
, INTR_MPSAFE
, envy24_intr
, sc
, &sc
->ih
)) {
2474 device_printf(sc
->dev
, "unable to map interrupt\n");
2478 /* allocate DMA resource */
2479 if (bus_dma_tag_create(/*parent*/NULL
,
2482 /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24
,
2483 /*highaddr*/BUS_SPACE_MAXADDR_ENVY24
,
2484 /*filter*/NULL
, /*filterarg*/NULL
,
2485 /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24
,
2486 /*nsegments*/1, /*maxsegsz*/0x3ffff,
2487 /*flags*/0, &sc
->dmat
) != 0) {
2488 device_printf(sc
->dev
, "unable to create dma tag\n");
2496 envy24_pci_attach(device_t dev
)
2500 char status
[SND_STATUSLEN
];
2505 device_printf(dev
, "envy24_pci_attach()\n");
2507 /* get sc_info data area */
2508 if ((sc
= kmalloc(sizeof(*sc
), M_ENVY24
, M_NOWAIT
| M_ZERO
)) == NULL
) {
2509 device_printf(dev
, "cannot allocate softc\n");
2513 sc
->lock
= snd_mtxcreate(device_get_nameunit(dev
), "snd_envy24 softc");
2516 /* initialize PCI interface */
2517 data
= pci_read_config(dev
, PCIR_COMMAND
, 2);
2518 data
|= (PCIM_CMD_PORTEN
| PCIM_CMD_BUSMASTEREN
);
2519 pci_write_config(dev
, PCIR_COMMAND
, data
, 2);
2520 data
= pci_read_config(dev
, PCIR_COMMAND
, 2);
2522 /* allocate resources */
2523 err
= envy24_alloc_resource(sc
);
2525 device_printf(dev
, "unable to allocate system resources\n");
2529 /* initialize card */
2530 err
= envy24_init(sc
);
2532 device_printf(dev
, "unable to initialize the card\n");
2536 /* set multi track mixer */
2537 mixer_init(dev
, &envy24mixer_class
, sc
);
2539 /* set channel information */
2540 err
= pcm_register(dev
, sc
, 5, 2 + sc
->adcn
);
2544 for (i
= 0; i
< 5; i
++) {
2545 pcm_addchan(dev
, PCMDIR_PLAY
, &envy24chan_class
, sc
);
2548 for (i
= 0; i
< 2 + sc
->adcn
; i
++) {
2549 pcm_addchan(dev
, PCMDIR_REC
, &envy24chan_class
, sc
);
2553 /* set status iformation */
2554 ksnprintf(status
, SND_STATUSLEN
,
2555 "at io 0x%lx:%ld,0x%lx:%ld,0x%lx:%ld,0x%lx:%ld irq %ld",
2556 rman_get_start(sc
->cs
),
2557 rman_get_end(sc
->cs
) - rman_get_start(sc
->cs
) + 1,
2558 rman_get_start(sc
->ddma
),
2559 rman_get_end(sc
->ddma
) - rman_get_start(sc
->ddma
) + 1,
2560 rman_get_start(sc
->ds
),
2561 rman_get_end(sc
->ds
) - rman_get_start(sc
->ds
) + 1,
2562 rman_get_start(sc
->mt
),
2563 rman_get_end(sc
->mt
) - rman_get_start(sc
->mt
) + 1,
2564 rman_get_start(sc
->irq
));
2565 pcm_setstatus(dev
, status
);
2571 bus_teardown_intr(dev
, sc
->irq
, sc
->ih
);
2573 bus_release_resource(dev
, SYS_RES_IRQ
, sc
->irqid
, sc
->irq
);
2576 bus_dma_tag_destroy(sc
->dmat
);
2577 if (sc
->cfg
->codec
->destroy
!= NULL
) {
2578 for (i
= 0; i
< sc
->adcn
; i
++)
2579 sc
->cfg
->codec
->destroy(sc
->adc
[i
]);
2580 for (i
= 0; i
< sc
->dacn
; i
++)
2581 sc
->cfg
->codec
->destroy(sc
->dac
[i
]);
2583 envy24_cfgfree(sc
->cfg
);
2585 bus_release_resource(dev
, SYS_RES_IOPORT
, sc
->csid
, sc
->cs
);
2587 bus_release_resource(dev
, SYS_RES_IOPORT
, sc
->ddmaid
, sc
->ddma
);
2589 bus_release_resource(dev
, SYS_RES_IOPORT
, sc
->dsid
, sc
->ds
);
2591 bus_release_resource(dev
, SYS_RES_IOPORT
, sc
->mtid
, sc
->mt
);
2593 snd_mtxfree(sc
->lock
);
2594 kfree(sc
, M_ENVY24
);
2599 envy24_pci_detach(device_t dev
)
2606 device_printf(dev
, "envy24_pci_detach()\n");
2608 sc
= pcm_getdevinfo(dev
);
2611 r
= pcm_unregister(dev
);
2616 if (sc
->cfg
->codec
->destroy
!= NULL
) {
2617 for (i
= 0; i
< sc
->adcn
; i
++)
2618 sc
->cfg
->codec
->destroy(sc
->adc
[i
]);
2619 for (i
= 0; i
< sc
->dacn
; i
++)
2620 sc
->cfg
->codec
->destroy(sc
->dac
[i
]);
2622 envy24_cfgfree(sc
->cfg
);
2623 bus_dma_tag_destroy(sc
->dmat
);
2624 bus_teardown_intr(dev
, sc
->irq
, sc
->ih
);
2625 bus_release_resource(dev
, SYS_RES_IRQ
, sc
->irqid
, sc
->irq
);
2626 bus_release_resource(dev
, SYS_RES_IOPORT
, sc
->csid
, sc
->cs
);
2627 bus_release_resource(dev
, SYS_RES_IOPORT
, sc
->ddmaid
, sc
->ddma
);
2628 bus_release_resource(dev
, SYS_RES_IOPORT
, sc
->dsid
, sc
->ds
);
2629 bus_release_resource(dev
, SYS_RES_IOPORT
, sc
->mtid
, sc
->mt
);
2630 snd_mtxfree(sc
->lock
);
2631 kfree(sc
, M_ENVY24
);
2635 static device_method_t envy24_methods
[] = {
2636 /* Device interface */
2637 DEVMETHOD(device_probe
, envy24_pci_probe
),
2638 DEVMETHOD(device_attach
, envy24_pci_attach
),
2639 DEVMETHOD(device_detach
, envy24_pci_detach
),
2643 static driver_t envy24_driver
= {
2646 #if __FreeBSD_version > 500000
2649 sizeof(struct snddev_info
),
2653 DRIVER_MODULE(snd_envy24
, pci
, envy24_driver
, pcm_devclass
, 0, 0);
2654 MODULE_DEPEND(snd_envy24
, sound
, SOUND_MINVER
, SOUND_PREFVER
, SOUND_MAXVER
);
2655 MODULE_DEPEND(snd_envy24
, snd_spicds
, 1, 1, 1);
2656 MODULE_VERSION(snd_envy24
, 1);