2 * Copyright (c) 2001 Orion Hodson <oho@acm.org>
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/als4000.c,v 1.18.2.1 2005/12/30 19:55:53 netchild Exp $
27 * $DragonFly: src/sys/dev/sound/pci/als4000.c,v 1.11 2007/06/16 20:07:19 dillon Exp $
31 * als4000.c - driver for the Avance Logic ALS 4000 chipset.
33 * The ALS4000 is effectively an SB16 with a PCI interface.
35 * This driver derives from ALS4000a.PDF, Bart Hartgers alsa driver, and
36 * SB16 register descriptions.
39 #include <dev/sound/pcm/sound.h>
40 #include <dev/sound/isa/sb.h>
41 #include <dev/sound/pci/als4000.h>
43 #include <bus/pci/pcireg.h>
44 #include <bus/pci/pcivar.h>
48 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pci/als4000.c,v 1.11 2007/06/16 20:07:19 dillon Exp $");
50 /* Debugging macro's */
53 #define DEB(x) /* x */
56 #define ALS_DEFAULT_BUFSZ 16384
58 /* ------------------------------------------------------------------------- */
64 struct sc_info
*parent
;
65 struct pcm_channel
*channel
;
66 struct snd_dbuf
*buffer
;
67 u_int32_t format
, speed
, phys_buf
, bps
;
68 u_int32_t dma_active
:1, dma_was_active
:1;
69 u_int8_t gcr_fifo_status
;
76 bus_space_handle_t sh
;
77 bus_dma_tag_t parent_dmat
;
78 struct resource
*reg
, *irq
;
84 struct sc_chinfo pch
, rch
;
89 static u_int32_t als_format
[] = {
91 AFMT_STEREO
| AFMT_U8
,
93 AFMT_STEREO
| AFMT_S16_LE
,
98 * I don't believe this rotten soundcard can do 48k, really,
101 static struct pcmchan_caps als_caps
= { 4000, 44100, als_format
, 0 };
103 /* ------------------------------------------------------------------------- */
104 /* Register Utilities */
107 als_gcr_rd(struct sc_info
*sc
, int index
)
109 bus_space_write_1(sc
->st
, sc
->sh
, ALS_GCR_INDEX
, index
);
110 return bus_space_read_4(sc
->st
, sc
->sh
, ALS_GCR_DATA
);
114 als_gcr_wr(struct sc_info
*sc
, int index
, int data
)
116 bus_space_write_1(sc
->st
, sc
->sh
, ALS_GCR_INDEX
, index
);
117 bus_space_write_4(sc
->st
, sc
->sh
, ALS_GCR_DATA
, data
);
121 als_intr_rd(struct sc_info
*sc
)
123 return bus_space_read_1(sc
->st
, sc
->sh
, ALS_SB_MPU_IRQ
);
127 als_intr_wr(struct sc_info
*sc
, u_int8_t data
)
129 bus_space_write_1(sc
->st
, sc
->sh
, ALS_SB_MPU_IRQ
, data
);
133 als_mix_rd(struct sc_info
*sc
, u_int8_t index
)
135 bus_space_write_1(sc
->st
, sc
->sh
, ALS_MIXER_INDEX
, index
);
136 return bus_space_read_1(sc
->st
, sc
->sh
, ALS_MIXER_DATA
);
140 als_mix_wr(struct sc_info
*sc
, u_int8_t index
, u_int8_t data
)
142 bus_space_write_1(sc
->st
, sc
->sh
, ALS_MIXER_INDEX
, index
);
143 bus_space_write_1(sc
->st
, sc
->sh
, ALS_MIXER_DATA
, data
);
147 als_esp_wr(struct sc_info
*sc
, u_int8_t data
)
153 v
= bus_space_read_1(sc
->st
, sc
->sh
, ALS_ESP_WR_STATUS
);
157 } while (--tries
!= 0);
160 device_printf(sc
->dev
, "als_esp_wr timeout");
162 bus_space_write_1(sc
->st
, sc
->sh
, ALS_ESP_WR_DATA
, data
);
166 als_esp_reset(struct sc_info
*sc
)
168 u_int32_t tries
, u
, v
;
170 bus_space_write_1(sc
->st
, sc
->sh
, ALS_ESP_RST
, 1);
172 bus_space_write_1(sc
->st
, sc
->sh
, ALS_ESP_RST
, 0);
177 u
= bus_space_read_1(sc
->st
, sc
->sh
, ALS_ESP_RD_STATUS8
);
179 v
= bus_space_read_1(sc
->st
, sc
->sh
, ALS_ESP_RD_DATA
);
186 } while (--tries
!= 0);
189 device_printf(sc
->dev
, "als_esp_reset timeout");
194 als_ack_read(struct sc_info
*sc
, u_int8_t addr
)
196 u_int8_t r
= bus_space_read_1(sc
->st
, sc
->sh
, addr
);
200 /* ------------------------------------------------------------------------- */
201 /* Common pcm channel implementation */
204 alschan_init(kobj_t obj
, void *devinfo
,
205 struct snd_dbuf
*b
, struct pcm_channel
*c
, int dir
)
207 struct sc_info
*sc
= devinfo
;
208 struct sc_chinfo
*ch
;
210 snd_mtxlock(sc
->lock
);
211 if (dir
== PCMDIR_PLAY
) {
213 ch
->gcr_fifo_status
= ALS_GCR_FIFO0_STATUS
;
216 ch
->gcr_fifo_status
= ALS_GCR_FIFO1_STATUS
;
222 ch
->format
= AFMT_U8
;
223 ch
->speed
= DSP_DEFAULT_SPEED
;
225 snd_mtxunlock(sc
->lock
);
227 if (sndbuf_alloc(ch
->buffer
, sc
->parent_dmat
, sc
->bufsz
) != 0)
234 alschan_setformat(kobj_t obj
, void *data
, u_int32_t format
)
236 struct sc_chinfo
*ch
= data
;
243 alschan_setspeed(kobj_t obj
, void *data
, u_int32_t speed
)
245 struct sc_chinfo
*ch
= data
, *other
;
246 struct sc_info
*sc
= ch
->parent
;
248 other
= (ch
->dir
== PCMDIR_PLAY
) ? &sc
->rch
: &sc
->pch
;
250 /* Deny request if other dma channel is active */
251 if (other
->dma_active
) {
252 ch
->speed
= other
->speed
;
261 alschan_setblocksize(kobj_t obj
, void *data
, u_int32_t blocksize
)
263 struct sc_chinfo
*ch
= data
;
264 struct sc_info
*sc
= ch
->parent
;
266 if (blocksize
> sc
->bufsz
/ 2) {
267 blocksize
= sc
->bufsz
/ 2;
269 sndbuf_resize(ch
->buffer
, 2, blocksize
);
274 alschan_getptr(kobj_t obj
, void *data
)
276 struct sc_chinfo
*ch
= data
;
277 struct sc_info
*sc
= ch
->parent
;
280 snd_mtxlock(sc
->lock
);
281 pos
= als_gcr_rd(ch
->parent
, ch
->gcr_fifo_status
) & 0xffff;
282 snd_mtxunlock(sc
->lock
);
283 sz
= sndbuf_getsize(ch
->buffer
);
284 return (2 * sz
- pos
- 1) % sz
;
287 static struct pcmchan_caps
*
288 alschan_getcaps(kobj_t obj
, void *data
)
294 als_set_speed(struct sc_chinfo
*ch
)
296 struct sc_info
*sc
= ch
->parent
;
297 struct sc_chinfo
*other
;
299 other
= (ch
->dir
== PCMDIR_PLAY
) ? &sc
->rch
: &sc
->pch
;
300 if (other
->dma_active
== 0) {
301 als_esp_wr(sc
, ALS_ESP_SAMPLE_RATE
);
302 als_esp_wr(sc
, ch
->speed
>> 8);
303 als_esp_wr(sc
, ch
->speed
& 0xff);
305 DEB(kprintf("speed locked at %d (tried %d)\n",
306 other
->speed
, ch
->speed
));
310 /* ------------------------------------------------------------------------- */
311 /* Playback channel implementation */
313 #define ALS_8BIT_CMD(x, y) { (x), (y), DSP_DMA8, DSP_CMD_DMAPAUSE_8 }
314 #define ALS_16BIT_CMD(x, y) { (x), (y), DSP_DMA16, DSP_CMD_DMAPAUSE_16 }
316 struct playback_command
{
317 u_int32_t pcm_format
; /* newpcm format */
318 u_int8_t format_val
; /* sb16 format value */
319 u_int8_t dma_prog
; /* sb16 dma program */
320 u_int8_t dma_stop
; /* sb16 stop register */
321 } static const playback_cmds
[] = {
322 ALS_8BIT_CMD(AFMT_U8
, DSP_MODE_U8MONO
),
323 ALS_8BIT_CMD(AFMT_U8
| AFMT_STEREO
, DSP_MODE_U8STEREO
),
324 ALS_16BIT_CMD(AFMT_S16_LE
, DSP_MODE_S16MONO
),
325 ALS_16BIT_CMD(AFMT_S16_LE
| AFMT_STEREO
, DSP_MODE_S16STEREO
),
328 static const struct playback_command
*
329 als_get_playback_command(u_int32_t format
)
333 n
= sizeof(playback_cmds
) / sizeof(playback_cmds
[0]);
334 for (i
= 0; i
< n
; i
++) {
335 if (playback_cmds
[i
].pcm_format
== format
) {
336 return &playback_cmds
[i
];
339 DEB(kprintf("als_get_playback_command: invalid format 0x%08x\n",
341 return &playback_cmds
[0];
345 als_playback_start(struct sc_chinfo
*ch
)
347 const struct playback_command
*p
;
348 struct sc_info
*sc
= ch
->parent
;
349 u_int32_t buf
, bufsz
, count
, dma_prog
;
351 buf
= sndbuf_getbufaddr(ch
->buffer
);
352 bufsz
= sndbuf_getsize(ch
->buffer
);
354 if (ch
->format
& AFMT_16BIT
)
358 als_esp_wr(sc
, DSP_CMD_SPKON
);
361 als_gcr_wr(sc
, ALS_GCR_DMA0_START
, buf
);
362 als_gcr_wr(sc
, ALS_GCR_DMA0_MODE
, (bufsz
- 1) | 0x180000);
364 p
= als_get_playback_command(ch
->format
);
365 dma_prog
= p
->dma_prog
| DSP_F16_DAC
| DSP_F16_AUTO
| DSP_F16_FIFO_ON
;
367 als_esp_wr(sc
, dma_prog
);
368 als_esp_wr(sc
, p
->format_val
);
369 als_esp_wr(sc
, count
& 0xff);
370 als_esp_wr(sc
, count
>> 8);
376 als_playback_stop(struct sc_chinfo
*ch
)
378 const struct playback_command
*p
;
379 struct sc_info
*sc
= ch
->parent
;
382 active
= ch
->dma_active
;
384 p
= als_get_playback_command(ch
->format
);
385 als_esp_wr(sc
, p
->dma_stop
);
392 alspchan_trigger(kobj_t obj
, void *data
, int go
)
394 struct sc_chinfo
*ch
= data
;
395 struct sc_info
*sc
= ch
->parent
;
397 snd_mtxlock(sc
->lock
);
400 als_playback_start(ch
);
403 als_playback_stop(ch
);
406 snd_mtxunlock(sc
->lock
);
410 static kobj_method_t alspchan_methods
[] = {
411 KOBJMETHOD(channel_init
, alschan_init
),
412 KOBJMETHOD(channel_setformat
, alschan_setformat
),
413 KOBJMETHOD(channel_setspeed
, alschan_setspeed
),
414 KOBJMETHOD(channel_setblocksize
, alschan_setblocksize
),
415 KOBJMETHOD(channel_trigger
, alspchan_trigger
),
416 KOBJMETHOD(channel_getptr
, alschan_getptr
),
417 KOBJMETHOD(channel_getcaps
, alschan_getcaps
),
420 CHANNEL_DECLARE(alspchan
);
422 /* ------------------------------------------------------------------------- */
423 /* Capture channel implementation */
426 als_get_fifo_format(struct sc_info
*sc
, u_int32_t format
)
430 return ALS_FIFO1_8BIT
;
431 case AFMT_U8
| AFMT_STEREO
:
432 return ALS_FIFO1_8BIT
| ALS_FIFO1_STEREO
;
434 return ALS_FIFO1_SIGNED
;
435 case AFMT_S16_LE
| AFMT_STEREO
:
436 return ALS_FIFO1_SIGNED
| ALS_FIFO1_STEREO
;
438 device_printf(sc
->dev
, "format not found: 0x%08x\n", format
);
439 return ALS_FIFO1_8BIT
;
443 als_capture_start(struct sc_chinfo
*ch
)
445 struct sc_info
*sc
= ch
->parent
;
446 u_int32_t buf
, bufsz
, count
, dma_prog
;
448 buf
= sndbuf_getbufaddr(ch
->buffer
);
449 bufsz
= sndbuf_getsize(ch
->buffer
);
451 if (ch
->format
& AFMT_16BIT
)
455 als_esp_wr(sc
, DSP_CMD_SPKON
);
458 als_gcr_wr(sc
, ALS_GCR_FIFO1_START
, buf
);
459 als_gcr_wr(sc
, ALS_GCR_FIFO1_COUNT
, (bufsz
- 1));
461 als_mix_wr(sc
, ALS_FIFO1_LENGTH_LO
, count
& 0xff);
462 als_mix_wr(sc
, ALS_FIFO1_LENGTH_HI
, count
>> 8);
464 dma_prog
= ALS_FIFO1_RUN
| als_get_fifo_format(sc
, ch
->format
);
465 als_mix_wr(sc
, ALS_FIFO1_CONTROL
, dma_prog
);
471 als_capture_stop(struct sc_chinfo
*ch
)
473 struct sc_info
*sc
= ch
->parent
;
476 active
= ch
->dma_active
;
478 als_mix_wr(sc
, ALS_FIFO1_CONTROL
, ALS_FIFO1_STOP
);
485 alsrchan_trigger(kobj_t obj
, void *data
, int go
)
487 struct sc_chinfo
*ch
= data
;
488 struct sc_info
*sc
= ch
->parent
;
490 snd_mtxlock(sc
->lock
);
493 als_capture_start(ch
);
496 als_capture_stop(ch
);
499 snd_mtxunlock(sc
->lock
);
503 static kobj_method_t alsrchan_methods
[] = {
504 KOBJMETHOD(channel_init
, alschan_init
),
505 KOBJMETHOD(channel_setformat
, alschan_setformat
),
506 KOBJMETHOD(channel_setspeed
, alschan_setspeed
),
507 KOBJMETHOD(channel_setblocksize
, alschan_setblocksize
),
508 KOBJMETHOD(channel_trigger
, alsrchan_trigger
),
509 KOBJMETHOD(channel_getptr
, alschan_getptr
),
510 KOBJMETHOD(channel_getcaps
, alschan_getcaps
),
513 CHANNEL_DECLARE(alsrchan
);
515 /* ------------------------------------------------------------------------- */
519 * ALS4000 has an sb16 mixer, with some additional controls that we do
520 * not yet a means to support.
528 u_int8_t iselect
; /* left input mask */
529 } static const amt
[SOUND_MIXER_NRDEVICES
] = {
530 [SOUND_MIXER_VOLUME
] = { 0x30, 0x31, 5, 0x00, 0x00 },
531 [SOUND_MIXER_PCM
] = { 0x32, 0x33, 5, 0x00, 0x00 },
532 [SOUND_MIXER_SYNTH
] = { 0x34, 0x35, 5, 0x60, 0x40 },
533 [SOUND_MIXER_CD
] = { 0x36, 0x37, 5, 0x06, 0x04 },
534 [SOUND_MIXER_LINE
] = { 0x38, 0x39, 5, 0x18, 0x10 },
535 [SOUND_MIXER_MIC
] = { 0x3a, 0x00, 5, 0x01, 0x01 },
536 [SOUND_MIXER_SPEAKER
] = { 0x3b, 0x00, 2, 0x00, 0x00 },
537 [SOUND_MIXER_IGAIN
] = { 0x3f, 0x40, 2, 0x00, 0x00 },
538 [SOUND_MIXER_OGAIN
] = { 0x41, 0x42, 2, 0x00, 0x00 },
539 /* The following have register values but no h/w implementation */
540 [SOUND_MIXER_TREBLE
] = { 0x44, 0x45, 4, 0x00, 0x00 },
541 [SOUND_MIXER_BASS
] = { 0x46, 0x47, 4, 0x00, 0x00 }
545 alsmix_init(struct snd_mixer
*m
)
549 for (i
= v
= 0; i
< SOUND_MIXER_NRDEVICES
; i
++) {
550 if (amt
[i
].bits
) v
|= 1 << i
;
554 for (i
= v
= 0; i
< SOUND_MIXER_NRDEVICES
; i
++) {
555 if (amt
[i
].iselect
) v
|= 1 << i
;
557 mix_setrecdevs(m
, v
);
562 alsmix_set(struct snd_mixer
*m
, unsigned dev
, unsigned left
, unsigned right
)
564 struct sc_info
*sc
= mix_getdevinfo(m
);
565 u_int32_t r
, l
, v
, mask
;
567 /* Fill upper n bits in mask with 1's */
568 mask
= ((1 << amt
[dev
].bits
) - 1) << (8 - amt
[dev
].bits
);
570 l
= (left
* mask
/ 100) & mask
;
571 v
= als_mix_rd(sc
, amt
[dev
].lreg
) & ~mask
;
572 als_mix_wr(sc
, amt
[dev
].lreg
, l
| v
);
575 r
= (right
* mask
/ 100) & mask
;
576 v
= als_mix_rd(sc
, amt
[dev
].rreg
) & ~mask
;
577 als_mix_wr(sc
, amt
[dev
].rreg
, r
| v
);
582 /* Zero gain does not mute channel from output, but this does. */
583 v
= als_mix_rd(sc
, SB16_OMASK
);
584 if (l
== 0 && r
== 0) {
585 v
&= ~amt
[dev
].oselect
;
587 v
|= amt
[dev
].oselect
;
589 als_mix_wr(sc
, SB16_OMASK
, v
);
594 alsmix_setrecsrc(struct snd_mixer
*m
, u_int32_t src
)
596 struct sc_info
*sc
= mix_getdevinfo(m
);
599 for (i
= l
= r
= 0; i
< SOUND_MIXER_NRDEVICES
; i
++) {
600 if (src
& (1 << i
)) {
601 if (amt
[i
].iselect
== 1) { /* microphone */
606 r
|= amt
[i
].iselect
>> 1;
611 als_mix_wr(sc
, SB16_IMASK_L
, l
);
612 als_mix_wr(sc
, SB16_IMASK_R
, r
);
616 static kobj_method_t als_mixer_methods
[] = {
617 KOBJMETHOD(mixer_init
, alsmix_init
),
618 KOBJMETHOD(mixer_set
, alsmix_set
),
619 KOBJMETHOD(mixer_setrecsrc
, alsmix_setrecsrc
),
622 MIXER_DECLARE(als_mixer
);
624 /* ------------------------------------------------------------------------- */
625 /* Interrupt Handler */
630 struct sc_info
*sc
= (struct sc_info
*)p
;
631 u_int8_t intr
, sb_status
;
633 snd_mtxlock(sc
->lock
);
634 intr
= als_intr_rd(sc
);
637 snd_mtxunlock(sc
->lock
);
638 chn_intr(sc
->pch
.channel
);
639 snd_mtxlock(sc
->lock
);
643 snd_mtxunlock(sc
->lock
);
644 chn_intr(sc
->rch
.channel
);
645 snd_mtxlock(sc
->lock
);
648 /* ACK interrupt in PCI core */
649 als_intr_wr(sc
, intr
);
651 /* ACK interrupt in SB core */
652 sb_status
= als_mix_rd(sc
, IRQ_STAT
);
654 if (sb_status
& ALS_IRQ_STATUS8
)
655 als_ack_read(sc
, ALS_ESP_RD_STATUS8
);
656 if (sb_status
& ALS_IRQ_STATUS16
)
657 als_ack_read(sc
, ALS_ESP_RD_STATUS16
);
658 if (sb_status
& ALS_IRQ_MPUIN
)
659 als_ack_read(sc
, ALS_MIDI_DATA
);
660 if (sb_status
& ALS_IRQ_CR1E
)
661 als_ack_read(sc
, ALS_CR1E_ACK_PORT
);
663 snd_mtxunlock(sc
->lock
);
667 /* ------------------------------------------------------------------------- */
668 /* H/W initialization */
671 als_init(struct sc_info
*sc
)
676 if (als_esp_reset(sc
)) {
680 /* Enable write on DMA_SETUP register */
681 v
= als_mix_rd(sc
, ALS_SB16_CONFIG
);
682 als_mix_wr(sc
, ALS_SB16_CONFIG
, v
| 0x80);
685 als_mix_wr(sc
, ALS_SB16_DMA_SETUP
, 0x01);
687 /* Disable write on DMA_SETUP register */
688 als_mix_wr(sc
, ALS_SB16_CONFIG
, v
& 0x7f);
690 /* Enable interrupts */
691 v
= als_gcr_rd(sc
, ALS_GCR_MISC
);
692 als_gcr_wr(sc
, ALS_GCR_MISC
, v
| 0x28000);
694 /* Black out GCR DMA registers */
695 for (i
= 0x91; i
<= 0x96; i
++) {
696 als_gcr_wr(sc
, i
, 0);
700 v
= als_gcr_rd(sc
, ALS_GCR_DMA_EMULATION
);
701 als_gcr_wr(sc
, ALS_GCR_DMA_EMULATION
, v
);
702 DEB(kprintf("GCR_DMA_EMULATION 0x%08x\n", v
));
707 als_uninit(struct sc_info
*sc
)
709 /* Disable interrupts */
710 als_gcr_wr(sc
, ALS_GCR_MISC
, 0);
713 /* ------------------------------------------------------------------------- */
714 /* Probe and attach card */
717 als_pci_probe(device_t dev
)
719 if (pci_get_devid(dev
) == ALS_PCI_ID0
) {
720 device_set_desc(dev
, "Avance Logic ALS4000");
721 return BUS_PROBE_DEFAULT
;
727 als_resource_free(device_t dev
, struct sc_info
*sc
)
730 bus_release_resource(dev
, SYS_RES_IOPORT
, sc
->regid
, sc
->reg
);
734 bus_teardown_intr(dev
, sc
->irq
, sc
->ih
);
738 bus_release_resource(dev
, SYS_RES_IRQ
, sc
->irqid
, sc
->irq
);
741 if (sc
->parent_dmat
) {
742 bus_dma_tag_destroy(sc
->parent_dmat
);
746 snd_mtxfree(sc
->lock
);
752 als_resource_grab(device_t dev
, struct sc_info
*sc
)
754 sc
->regid
= PCIR_BAR(0);
755 sc
->reg
= bus_alloc_resource(dev
, SYS_RES_IOPORT
, &sc
->regid
, 0, ~0,
756 ALS_CONFIG_SPACE_BYTES
, RF_ACTIVE
);
758 device_printf(dev
, "unable to allocate register space\n");
761 sc
->st
= rman_get_bustag(sc
->reg
);
762 sc
->sh
= rman_get_bushandle(sc
->reg
);
764 sc
->irq
= bus_alloc_resource_any(dev
, SYS_RES_IRQ
, &sc
->irqid
,
765 RF_ACTIVE
| RF_SHAREABLE
);
767 device_printf(dev
, "unable to allocate interrupt\n");
771 if (snd_setup_intr(dev
, sc
->irq
, INTR_MPSAFE
, als_intr
,
773 device_printf(dev
, "unable to setup interrupt\n");
777 sc
->bufsz
= pcm_getbuffersize(dev
, 4096, ALS_DEFAULT_BUFSZ
, 65536);
779 if (bus_dma_tag_create(/*parent*/NULL
,
780 /*alignment*/2, /*boundary*/0,
781 /*lowaddr*/BUS_SPACE_MAXADDR_24BIT
,
782 /*highaddr*/BUS_SPACE_MAXADDR
,
783 /*filter*/NULL
, /*filterarg*/NULL
,
784 /*maxsize*/sc
->bufsz
,
785 /*nsegments*/1, /*maxsegz*/0x3ffff,
787 &sc
->parent_dmat
) != 0) {
788 device_printf(dev
, "unable to create dma tag\n");
793 als_resource_free(dev
, sc
);
798 als_pci_attach(device_t dev
)
802 char status
[SND_STATUSLEN
];
804 if ((sc
= kmalloc(sizeof(*sc
), M_DEVBUF
, M_NOWAIT
| M_ZERO
)) == NULL
) {
805 device_printf(dev
, "cannot allocate softc\n");
809 sc
->lock
= snd_mtxcreate(device_get_nameunit(dev
), "sound softc");
812 data
= pci_read_config(dev
, PCIR_COMMAND
, 2);
813 data
|= (PCIM_CMD_PORTEN
| PCIM_CMD_MEMEN
| PCIM_CMD_BUSMASTEREN
);
814 pci_write_config(dev
, PCIR_COMMAND
, data
, 2);
816 * By default the power to the various components on the
817 * ALS4000 is entirely controlled by the pci powerstate. We
818 * could attempt finer grained control by setting GCR6.31.
820 #if __FreeBSD_version > 500000
821 if (pci_get_powerstate(dev
) != PCI_POWERSTATE_D0
) {
822 /* Reset the power state. */
823 device_printf(dev
, "chip is in D%d power mode "
824 "-- setting to D0\n", pci_get_powerstate(dev
));
825 pci_set_powerstate(dev
, PCI_POWERSTATE_D0
);
828 data
= pci_read_config(dev
, ALS_PCI_POWERREG
, 2);
829 if ((data
& 0x03) != 0) {
830 device_printf(dev
, "chip is in D%d power mode "
831 "-- setting to D0\n", data
& 0x03);
833 pci_write_config(dev
, ALS_PCI_POWERREG
, data
, 2);
837 if (als_resource_grab(dev
, sc
)) {
838 device_printf(dev
, "failed to allocate resources\n");
843 device_printf(dev
, "failed to initialize hardware\n");
847 if (mixer_init(dev
, &als_mixer_class
, sc
)) {
848 device_printf(dev
, "failed to initialize mixer\n");
852 if (pcm_register(dev
, sc
, 1, 1)) {
853 device_printf(dev
, "failed to register pcm entries\n");
857 pcm_addchan(dev
, PCMDIR_PLAY
, &alspchan_class
, sc
);
858 pcm_addchan(dev
, PCMDIR_REC
, &alsrchan_class
, sc
);
860 ksnprintf(status
, SND_STATUSLEN
, "at io 0x%lx irq %ld %s",
861 rman_get_start(sc
->reg
), rman_get_start(sc
->irq
),PCM_KLDSTRING(snd_als4000
));
862 pcm_setstatus(dev
, status
);
866 als_resource_free(dev
, sc
);
872 als_pci_detach(device_t dev
)
877 r
= pcm_unregister(dev
);
881 sc
= pcm_getdevinfo(dev
);
883 als_resource_free(dev
, sc
);
889 als_pci_suspend(device_t dev
)
891 struct sc_info
*sc
= pcm_getdevinfo(dev
);
893 snd_mtxlock(sc
->lock
);
894 sc
->pch
.dma_was_active
= als_playback_stop(&sc
->pch
);
895 sc
->rch
.dma_was_active
= als_capture_stop(&sc
->rch
);
897 snd_mtxunlock(sc
->lock
);
902 als_pci_resume(device_t dev
)
904 struct sc_info
*sc
= pcm_getdevinfo(dev
);
907 snd_mtxlock(sc
->lock
);
908 if (als_init(sc
) != 0) {
909 device_printf(dev
, "unable to reinitialize the card\n");
910 snd_mtxunlock(sc
->lock
);
914 if (mixer_reinit(dev
) != 0) {
915 device_printf(dev
, "unable to reinitialize the mixer\n");
916 snd_mtxunlock(sc
->lock
);
920 if (sc
->pch
.dma_was_active
) {
921 als_playback_start(&sc
->pch
);
924 if (sc
->rch
.dma_was_active
) {
925 als_capture_start(&sc
->rch
);
927 snd_mtxunlock(sc
->lock
);
932 static device_method_t als_methods
[] = {
933 /* Device interface */
934 DEVMETHOD(device_probe
, als_pci_probe
),
935 DEVMETHOD(device_attach
, als_pci_attach
),
936 DEVMETHOD(device_detach
, als_pci_detach
),
937 DEVMETHOD(device_suspend
, als_pci_suspend
),
938 DEVMETHOD(device_resume
, als_pci_resume
),
942 static driver_t als_driver
= {
948 DRIVER_MODULE(snd_als4000
, pci
, als_driver
, pcm_devclass
, 0, 0);
949 MODULE_DEPEND(snd_als4000
, sound
, SOUND_MINVER
, SOUND_PREFVER
, SOUND_MAXVER
);
950 MODULE_VERSION(snd_als4000
, 1);