summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcg <cg@FreeBSD.org>2001-07-03 17:27:13 +0000
committercg <cg@FreeBSD.org>2001-07-03 17:27:13 +0000
commit5a82aadeb1b9d81151a5e1d339e517dd4bc477e7 (patch)
tree3c935f8916ed7f6706a0c1a886f588d0fd6998ec
parent19461a1e25b2ed79c83c9b80c62fb272df5ec443 (diff)
downloadFreeBSD-src-5a82aadeb1b9d81151a5e1d339e517dd4bc477e7.zip
FreeBSD-src-5a82aadeb1b9d81151a5e1d339e517dd4bc477e7.tar.gz
* simplify
* add support for mic record channel * add support for setblocksize * make mpsafe * make getptr accurate * reduce buffer size from 64k to 16k for better synchronisation
-rw-r--r--sys/dev/sound/pci/ich.c1056
-rw-r--r--sys/dev/sound/pci/ich.h92
2 files changed, 325 insertions, 823 deletions
diff --git a/sys/dev/sound/pci/ich.c b/sys/dev/sound/pci/ich.c
index 714d3ef..1031536 100644
--- a/sys/dev/sound/pci/ich.c
+++ b/sys/dev/sound/pci/ich.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2000 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
+ * Copyright (c) 2001 Cameron Grant <cg@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,92 +29,17 @@
#include <dev/sound/pcm/sound.h>
#include <dev/sound/pcm/ac97.h>
+#include <dev/sound/pci/ich.h>
#include <pci/pcireg.h>
#include <pci/pcivar.h>
-
/* -------------------------------------------------------------------- */
-#define ICH_RECPRIMARY 0
-
#define ICH_TIMEOUT 1000 /* semaphore timeout polling count */
+#define ICH_DTBL_LENGTH 32
+#define ICH_DEFAULT_BUFSZ 16384
-#define PCIR_NAMBAR 0x10
-#define PCIR_NABMBAR 0x14
-
-/* Native Audio Bus Master Control Registers */
-#define ICH_REG_PI_BDBAR 0x00
-#define ICH_REG_PI_CIV 0x04
-#define ICH_REG_PI_LVI 0x05
-#define ICH_REG_PI_SR 0x06
-#define ICH_REG_PI_PICB 0x08
-#define ICH_REG_PI_PIV 0x0a
-#define ICH_REG_PI_CR 0x0b
-#define ICH_REG_PO_BDBAR 0x10
-#define ICH_REG_PO_CIV 0x14
-#define ICH_REG_PO_LVI 0x15
-#define ICH_REG_PO_SR 0x16
-#define ICH_REG_PO_PICB 0x18
-#define ICH_REG_PO_PIV 0x1a
-#define ICH_REG_PO_CR 0x1b
-#define ICH_REG_MC_BDBAR 0x20
-#define ICH_REG_MC_CIV 0x24
-#define ICH_REG_MC_LVI 0x25
-#define ICH_REG_MC_SR 0x26
-#define ICH_REG_MC_PICB 0x28
-#define ICH_REG_MC_PIV 0x2a
-#define ICH_REG_MC_CR 0x2b
-#define ICH_REG_GLOB_CNT 0x2c
-#define ICH_REG_GLOB_STA 0x30
-#define ICH_REG_ACC_SEMA 0x34
-/* Status Register Values */
-#define ICH_X_SR_DCH 0x0001
-#define ICH_X_SR_CELV 0x0002
-#define ICH_X_SR_LVBCI 0x0004
-#define ICH_X_SR_BCIS 0x0008
-#define ICH_X_SR_FIFOE 0x0010
-/* Control Register Values */
-#define ICH_X_CR_RPBM 0x01
-#define ICH_X_CR_RR 0x02
-#define ICH_X_CR_LVBIE 0x04
-#define ICH_X_CR_FEIE 0x08
-#define ICH_X_CR_IOCE 0x10
-/* Global Control Register Values */
-#define ICH_GLOB_CTL_GIE 0x00000001
-#define ICH_GLOB_CTL_COLD 0x00000002 /* negate */
-#define ICH_GLOB_CTL_WARM 0x00000004
-#define ICH_GLOB_CTL_SHUT 0x00000008
-#define ICH_GLOB_CTL_PRES 0x00000010
-#define ICH_GLOB_CTL_SRES 0x00000020
-/* Global Status Register Values */
-#define ICH_GLOB_STA_GSCI 0x00000001
-#define ICH_GLOB_STA_MIINT 0x00000002
-#define ICH_GLOB_STA_MOINT 0x00000004
-#define ICH_GLOB_STA_PIINT 0x00000020
-#define ICH_GLOB_STA_POINT 0x00000040
-#define ICH_GLOB_STA_MINT 0x00000080
-#define ICH_GLOB_STA_PCR 0x00000100
-#define ICH_GLOB_STA_SCR 0x00000200
-#define ICH_GLOB_STA_PRES 0x00000400
-#define ICH_GLOB_STA_SRES 0x00000800
-#define ICH_GLOB_STA_SLOT12 0x00007000
-#define ICH_GLOB_STA_RCODEC 0x00008000
-#define ICH_GLOB_STA_AD3 0x00010000
-#define ICH_GLOB_STA_MD3 0x00020000
-#define ICH_GLOB_STA_IMASK (ICH_GLOB_STA_MIINT | ICH_GLOB_STA_MOINT | ICH_GLOB_STA_PIINT | ICH_GLOB_STA_POINT | ICH_GLOB_STA_MINT | ICH_GLOB_STA_PRES | ICH_GLOB_STA_SRES)
-
-/* AC'97 power/ready functions */
-#define AC97_POWER_PINPOWER 0x0100
-#define AC97_POWER_PINREADY 0x0001
-#define AC97_POWER_POUTPOWER 0x0200
-#define AC97_POWER_POUTREADY 0x0002
-
-/* play/record buffer */
-#define ICH_FIFOINDEX 32
-#define ICH_BDC_IOC 0x80000000
-#define ICH_BDC_BUP 0x40000000
-#define ICH_DEFAULT_BLOCKSZ 2048
/* buffer descriptor */
struct ich_desc {
volatile u_int32_t buffer;
@@ -124,91 +50,44 @@ struct sc_info;
/* channel registers */
struct sc_chinfo {
- int run, spd, dir, fmt;
+ u_int32_t num, run;
+ u_int32_t blksz, blkcnt;
+ u_int32_t regbase, spdreg;
+
struct snd_dbuf *buffer;
struct pcm_channel *channel;
struct sc_info *parent;
- struct ich_desc *index;
- bus_dmamap_t imap;
- u_int32_t lvi;
+
+ struct ich_desc *dtbl;
};
/* device private data */
struct sc_info {
- device_t dev;
- u_int32_t type, rev;
- u_int32_t cd2id, ctrlbase;
+ device_t dev;
+ int hasvra, hasvrm;
+ int chnum;
- struct resource *nambar, *nabmbar;
- int nambarid, nabmbarid;
+ struct resource *nambar, *nabmbar, *irq;
+ int nambarid, nabmbarid, irqid;
bus_space_tag_t nambart, nabmbart;
bus_space_handle_t nambarh, nabmbarh;
bus_dma_tag_t dmat;
- struct resource *irq;
- int irqid;
- void *ih;
+ bus_dmamap_t dtmap;
+ void *ih;
struct ac97_info *codec;
- struct sc_chinfo *pi, *po;
-};
-
-struct {
- u_int32_t dev, subdev;
- char *name;
-} ich_devs[] = {
- {0x71958086, 0, "Intel 443MX"},
- {0x24138086, 0, "Intel 82801AA (ICH)"},
- {0x24158086, 0, "Intel 82801AA (ICH)"},
- {0x24258086, 0, "Intel 82901AB (ICH)"},
- {0x24458086, 0, "Intel 82801BA (ICH2)"},
- {0, 0, NULL}
-};
-
-/* variable rate audio */
-static u_int32_t ich_rate[] = {
- 48000, 44100, 22050, 16000, 11025, 8000, 0
+ struct sc_chinfo ch[3];
+ struct ich_desc *dtbl;
};
/* -------------------------------------------------------------------- */
-/*
- * prototypes
- */
-
-/* channel interface */
-static void *ichpchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
-static int ichpchan_setformat(kobj_t, void *, u_int32_t);
-static int ichpchan_setspeed(kobj_t, void *, u_int32_t);
-static int ichpchan_setblocksize(kobj_t, void *, u_int32_t);
-static int ichpchan_trigger(kobj_t, void *, int);
-static int ichpchan_getptr(kobj_t, void *);
-static struct pcmchan_caps *ichpchan_getcaps(kobj_t, void *);
-
-static void *ichrchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
-static int ichrchan_setformat(kobj_t, void *, u_int32_t);
-static int ichrchan_setspeed(kobj_t, void *, u_int32_t);
-static int ichrchan_setblocksize(kobj_t, void *, u_int32_t);
-static int ichrchan_trigger(kobj_t, void *, int);
-static int ichrchan_getptr(kobj_t, void *);
-static struct pcmchan_caps *ichrchan_getcaps(kobj_t, void *);
-
-/* stuff */
-static int ich_init(struct sc_info *);
-static void ich_intr(void *);
-
-/* -------------------------------------------------------------------- */
-
-static u_int32_t ich_recfmt[] = {
- AFMT_STEREO | AFMT_S16_LE,
- 0
-};
-static struct pcmchan_caps ich_reccaps = {8000, 48000, ich_recfmt, 0};
-
-static u_int32_t ich_playfmt[] = {
+static u_int32_t ich_fmt[] = {
AFMT_STEREO | AFMT_S16_LE,
0
};
-static struct pcmchan_caps ich_playcaps = {8000, 48000, ich_playfmt, 0};
+static struct pcmchan_caps ich_vrcaps = {8000, 48000, ich_fmt, 0};
+static struct pcmchan_caps ich_caps = {48000, 48000, ich_fmt, 0};
/* -------------------------------------------------------------------- */
/* Hardware */
@@ -217,11 +96,11 @@ ich_rd(struct sc_info *sc, int regno, int size)
{
switch (size) {
case 1:
- return bus_space_read_1(sc->nambart, sc->nambarh, regno);
+ return bus_space_read_1(sc->nabmbart, sc->nabmbarh, regno);
case 2:
- return bus_space_read_2(sc->nambart, sc->nambarh, regno);
+ return bus_space_read_2(sc->nabmbart, sc->nabmbarh, regno);
case 4:
- return bus_space_read_4(sc->nambart, sc->nambarh, regno);
+ return bus_space_read_4(sc->nabmbart, sc->nabmbarh, regno);
default:
return 0xffffffff;
}
@@ -232,13 +111,13 @@ ich_wr(struct sc_info *sc, int regno, u_int32_t data, int size)
{
switch (size) {
case 1:
- bus_space_write_1(sc->nambart, sc->nambarh, regno, data);
+ bus_space_write_1(sc->nabmbart, sc->nabmbarh, regno, data);
break;
case 2:
- bus_space_write_2(sc->nambart, sc->nambarh, regno, data);
+ bus_space_write_2(sc->nabmbart, sc->nabmbarh, regno, data);
break;
case 4:
- bus_space_write_4(sc->nambart, sc->nambarh, regno, data);
+ bus_space_write_4(sc->nabmbart, sc->nabmbarh, regno, data);
break;
}
}
@@ -250,9 +129,9 @@ ich_waitcd(void *devinfo)
int i;
u_int32_t data;
struct sc_info *sc = (struct sc_info *)devinfo;
- for (i = 0;i < ICH_TIMEOUT;i++) {
- data = bus_space_read_1(sc->nabmbart, sc->nabmbarh,
- ICH_REG_ACC_SEMA);
+
+ for (i = 0; i < ICH_TIMEOUT; i++) {
+ data = ich_rd(sc, ICH_REG_ACC_SEMA, 1);
if ((data & 0x01) == 0)
return 0;
}
@@ -264,18 +143,22 @@ static int
ich_rdcd(kobj_t obj, void *devinfo, int regno)
{
struct sc_info *sc = (struct sc_info *)devinfo;
+
regno &= 0xff;
ich_waitcd(sc);
- return ich_rd(sc, regno, 2);
+
+ return bus_space_read_2(sc->nambart, sc->nambarh, regno);
}
static int
-ich_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data)
+ich_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data)
{
struct sc_info *sc = (struct sc_info *)devinfo;
+
regno &= 0xff;
ich_waitcd(sc);
- ich_wr(sc, regno, data, 2);
+ bus_space_write_2(sc->nambart, sc->nambarh, regno, data);
+
return 0;
}
@@ -287,758 +170,299 @@ static kobj_method_t ich_ac97_methods[] = {
AC97_DECLARE(ich_ac97);
/* -------------------------------------------------------------------- */
+/* common routines */
-/* channel common routines */
static void
-ichchan_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+ich_filldtbl(struct sc_chinfo *ch)
{
- struct sc_chinfo *ch = arg;
-
- if (bootverbose) {
- device_printf(ch->parent->dev, "setmap(0x%lx, 0x%lx)\n", (unsigned long)segs->ds_addr, (unsigned long)segs->ds_len);
- }
-}
-
-static int
-ichchan_initbuf(struct sc_chinfo *ch)
-{
- struct sc_info *sc = ch->parent;
+ u_int32_t base;
int i;
- if (sndbuf_alloc(ch->buffer, sc->dmat, ICH_DEFAULT_BLOCKSZ * ICH_FIFOINDEX)) {
- return ENOSPC;
- }
- if (bus_dmamem_alloc(sc->dmat,(void **)&ch->index, BUS_DMA_NOWAIT, &ch->imap)) {
- sndbuf_free(ch->buffer);
- return ENOSPC;
+ base = vtophys(sndbuf_getbuf(ch->buffer));
+ ch->blkcnt = sndbuf_getsize(ch->buffer) / ch->blksz;
+ if (ch->blkcnt != 2 && ch->blkcnt != 4 && ch->blkcnt != 8 && ch->blkcnt != 16 && ch->blkcnt != 32) {
+ ch->blkcnt = 2;
+ ch->blksz = sndbuf_getsize(ch->buffer) / ch->blkcnt;
}
- if (bus_dmamap_load(sc->dmat, ch->imap, ch->index,
- sizeof(struct ich_desc) * ICH_FIFOINDEX, ichchan_setmap, ch, 0)) {
- bus_dmamem_free(sc->dmat, (void **)&ch->index, ch->imap);
- sndbuf_free(ch->buffer);
- return ENOSPC;
- }
- for (i = 0;i < ICH_FIFOINDEX;i++) {
- ch->index[i].buffer = vtophys(sndbuf_getbuf(ch->buffer)) +
- ICH_DEFAULT_BLOCKSZ * i;
- if (ch->dir == PCMDIR_PLAY)
- ch->index[i].length = 0;
- else
- ch->index[i].length = ICH_BDC_IOC +
- ICH_DEFAULT_BLOCKSZ / 2;
- }
- return 0;
-}
-
-static void
-ichchan_free(struct sc_chinfo *ch)
-{
- struct sc_info *sc = ch->parent;
- bus_dmamap_unload(sc->dmat, ch->imap);
- bus_dmamem_free(sc->dmat, (void **)&ch->index, ch->imap);
- sndbuf_free(ch->buffer);
+ for (i = 0; i < ICH_DTBL_LENGTH; i++) {
+ ch->dtbl[i].buffer = base + (ch->blksz * (i % ch->blkcnt));
+ ch->dtbl[i].length = ICH_BDC_IOC | (ch->blksz / 2);
+ }
}
-/* play channel interface */
static int
-ichpchan_power(kobj_t obj, struct sc_info *sc, int sw)
+ich_resetchan(struct sc_info *sc, int num)
{
- u_int32_t cr;
- int i;
+ int i, cr, regbase;
- cr = ich_rdcd(obj, sc, AC97_REG_POWER);
- if (sw) { /* power on */
- cr &= ~AC97_POWER_POUTPOWER;
- ich_wrcd(obj, sc, AC97_REG_POWER, cr);
- for (i = 0;i < ICH_TIMEOUT;i++) {
- cr = ich_rdcd(obj, sc, AC97_REG_POWER);
- if ((cr & AC97_POWER_POUTREADY) != 0)
- break;
- }
- }
- else { /* power off */
- cr |= AC97_POWER_POUTPOWER;
- ich_wrcd(obj, sc, AC97_REG_POWER, cr);
- for (i = 0;i < ICH_TIMEOUT;i++) {
- cr = ich_rdcd(obj, sc, AC97_REG_POWER);
- if ((cr & AC97_POWER_POUTREADY) == 0)
- break;
- }
- }
- if (i == ICH_TIMEOUT)
- return -1;
- return 0;
-}
+ if (num == 0)
+ regbase = ICH_REG_PO_BASE;
+ else if (num == 1)
+ regbase = ICH_REG_PI_BASE;
+ else if (num == 2)
+ regbase = ICH_REG_MC_BASE;
+ else
+ return ENXIO;
-static u_int32_t
-ichpchan_getminspeed(kobj_t obj, void *data)
-{
- struct sc_chinfo *ch = data;
- u_int32_t extcap;
- u_int32_t minspeed = 48000; /* before AC'97 R2.0 */
- int i = 0;
-
- extcap = ac97_getextmode(ch->parent->codec);
- if (extcap & AC97_EXTCAP_VRA) {
- for (i = 0;ich_rate[i] != 0;i++) {
- if (ac97_setrate(ch->parent->codec, AC97_REGEXT_FDACRATE, ich_rate[i]) == ich_rate[i])
- minspeed = ich_rate[i];
- }
+ ich_wr(sc, regbase + ICH_REG_X_CR, 0, 1);
+ DELAY(100);
+ ich_wr(sc, regbase + ICH_REG_X_CR, ICH_X_CR_RR, 1);
+ for (i = 0; i < ICH_TIMEOUT; i++) {
+ cr = ich_rd(sc, regbase + ICH_REG_X_CR, 1);
+ if (cr == 0)
+ return 0;
}
- return minspeed;
+
+ device_printf(sc->dev, "cannot reset channel %d\n", num);
+ return ENXIO;
}
+/* -------------------------------------------------------------------- */
+/* channel interface */
+
static void *
-ichpchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
+ichchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct sc_info *sc = devinfo;
struct sc_chinfo *ch;
- u_int32_t cr;
- int i;
+ int num;
- bus_space_write_1(sc->nabmbart, sc->nabmbarh, ICH_REG_PO_CR, 0);
- bus_space_write_1(sc->nabmbart, sc->nabmbarh, ICH_REG_PO_CR,
- ICH_X_CR_RR);
- for (i = 0;i < ICH_TIMEOUT;i++) {
- cr = bus_space_read_1(sc->nabmbart, sc->nabmbarh,
- ICH_REG_PO_CR);
- if (cr == 0)
- break;
- }
- if (i == ICH_TIMEOUT) {
- device_printf(sc->dev, "cannot reset play codec\n");
- return NULL;
- }
- if (ichpchan_power(obj, sc, 1) == -1) {
- device_printf(sc->dev, "play DAC not ready\n");
- return NULL;
- }
- ichpchan_power(obj, sc, 0);
- if ((ch = malloc(sizeof(*ch), M_DEVBUF, M_NOWAIT)) == NULL) {
- device_printf(sc->dev, "cannot allocate channel info area\n");
- return NULL;
- }
+ num = sc->chnum++;
+ ch = &sc->ch[num];
+ ch->num = num;
ch->buffer = b;
ch->channel = c;
ch->parent = sc;
- ch->dir = PCMDIR_PLAY;
ch->run = 0;
- ch->lvi = 0;
- if (ichchan_initbuf(ch)) {
- device_printf(sc->dev, "cannot allocate channel buffer\n");
- free(ch, M_DEVBUF);
- return NULL;
- }
- bus_space_write_4(sc->nabmbart, sc->nabmbarh, ICH_REG_PO_BDBAR,
- (u_int32_t)vtophys(ch->index));
- sc->po = ch;
- if (bootverbose) {
- device_printf(sc->dev,"Play codec support rate(Hz): ");
- for (i = 0;ich_rate[i] != 0;i++) {
- if (ichpchan_setspeed(obj, ch, ich_rate[i]) == ich_rate[i]) {
- printf("%d ", ich_rate[i]);
- }
- }
- printf("\n");
- }
- ich_playcaps.minspeed = ichpchan_getminspeed(obj, ch);
- return ch;
-}
-
-static int
-ichpchan_free(kobj_t obj, void *data)
-{
- struct sc_chinfo *ch = data;
- ichchan_free(ch);
- return ichpchan_power(obj, ch->parent, 0);
-}
-
-static int
-ichpchan_setformat(kobj_t obj, void *data, u_int32_t format)
-{
- struct sc_chinfo *ch = data;
-
- ch->fmt = format;
- return 0;
-}
-
-static int
-ichpchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
-{
- struct sc_chinfo *ch = data;
- u_int32_t extcap;
-
- extcap = ac97_getextmode(ch->parent->codec);
- if (extcap & AC97_EXTCAP_VRA) {
- ch->spd = (u_int32_t)ac97_setrate(ch->parent->codec, AC97_REGEXT_FDACRATE, speed);
- }
- else {
- ch->spd = 48000; /* before AC'97 R2.0 */
- }
-#if(0)
- device_printf(ch->parent->dev, "ichpchan_setspeed():ch->spd = %d\n", ch->spd);
-#endif
- return ch->spd;
-}
-
-static int
-ichpchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
-{
- return blocksize;
-}
-
-/* update index */
-static void
-ichpchan_update(struct sc_chinfo *ch)
-{
- struct sc_info *sc = ch->parent;
- u_int32_t lvi;
- int fp;
- int last;
- int i;
-
- fp = sndbuf_getfreeptr(ch->buffer);
- last = fp - 1;
- if (last < 0)
- last = ICH_DEFAULT_BLOCKSZ * ICH_FIFOINDEX - 1;
- lvi = last / ICH_DEFAULT_BLOCKSZ;
- if (lvi >= ch->lvi) {
- for (i = ch->lvi;i < lvi;i++)
- ch->index[i].length =
- ICH_BDC_IOC + ICH_DEFAULT_BLOCKSZ / 2;
- ch->index[i].length = ICH_BDC_IOC + ICH_BDC_BUP
- + (last % ICH_DEFAULT_BLOCKSZ + 1) / 2;
- }
- else {
- for (i = ch->lvi;i < ICH_FIFOINDEX;i++)
- ch->index[i].length =
- ICH_BDC_IOC + ICH_DEFAULT_BLOCKSZ / 2;
- for (i = 0;i < lvi;i++)
- ch->index[i].length =
- ICH_BDC_IOC + ICH_DEFAULT_BLOCKSZ / 2;
- ch->index[i].length = ICH_BDC_IOC + ICH_BDC_BUP
- + (last % ICH_DEFAULT_BLOCKSZ + 1) / 2;
- }
- bus_space_write_1(sc->nabmbart, sc->nabmbarh, ICH_REG_PO_LVI, lvi);
- ch->lvi = lvi;
-#if(0)
- device_printf(ch->parent->dev, "ichpchan_update():fp = %d, lvi = %d\n", fp, lvi);
-#endif
- return;
-}
-static void
-ichpchan_fillblank(struct sc_chinfo *ch)
-{
- struct sc_info *sc = ch->parent;
-
- ch->lvi++;
- if (ch->lvi == ICH_FIFOINDEX)
- ch->lvi = 0;
- ch->index[ch->lvi].length = ICH_BDC_BUP + ICH_DEFAULT_BLOCKSZ / 2;
- bus_space_write_1(sc->nabmbart, sc->nabmbarh, ICH_REG_PO_LVI, ch->lvi);
- return;
-}
-/* semantic note: must start at beginning of buffer */
-static int
-ichpchan_trigger(kobj_t obj, void *data, int go)
-{
- struct sc_chinfo *ch = data;
- struct sc_info *sc = ch->parent;
- u_int32_t cr;
- int i;
-
-#if(0)
- device_printf(ch->parent->dev, "ichpchan_trigger(0x%08x, %d)\n", data, go);
-#endif
- switch (go) {
- case PCMTRIG_START:
-#if(0)
- device_printf(ch->parent->dev, "ichpchan_trigger():PCMTRIG_START\n");
-#endif
- ch->run = 1;
- ichpchan_power(obj, sc, 1);
- bus_space_write_4(sc->nabmbart, sc->nabmbarh, ICH_REG_PO_BDBAR,
- (u_int32_t)vtophys(ch->index));
- ch->lvi = ICH_FIFOINDEX - 1;
- ichpchan_update(ch);
- bus_space_write_1(sc->nabmbart, sc->nabmbarh, ICH_REG_PO_CR,
- ICH_X_CR_RPBM | ICH_X_CR_LVBIE | ICH_X_CR_IOCE |
- ICH_X_CR_FEIE);
- break;
- case PCMTRIG_STOP:
-#if(0)
- device_printf(ch->parent->dev, "ichpchan_trigger():PCMTRIG_STOP\n");
-#endif
- cr = bus_space_read_1(sc->nabmbart, sc->nabmbarh,
- ICH_REG_PO_CR);
- bus_space_write_1(sc->nabmbart, sc->nabmbarh, ICH_REG_PO_CR,
- cr & ~ICH_X_CR_RPBM);
- ichpchan_power(obj, sc, 0);
- ch->run = 0;
- break;
- case PCMTRIG_ABORT:
-#if(0)
- device_printf(ch->parent->dev, "ichpchan_trigger():PCMTRIG_ABORT\n");
-#endif
- bus_space_write_1(sc->nabmbart, sc->nabmbarh, ICH_REG_PO_CR,
- 0);
- bus_space_write_1(sc->nabmbart, sc->nabmbarh, ICH_REG_PO_CR,
- ICH_X_CR_RR);
- for (i = 0;i < ICH_TIMEOUT;i++) {
- cr = bus_space_read_1(sc->nabmbart, sc->nabmbarh,
- ICH_REG_PO_CR);
- if (cr == 0)
- break;
- }
- ichpchan_power(obj, sc, 0);
- ch->run = 0;
- ch->lvi = 0;
+ ch->dtbl = sc->dtbl + (ch->num * ICH_DTBL_LENGTH);
+ ch->blkcnt = 2;
+ ch->blksz = ICH_DEFAULT_BUFSZ / ch->blkcnt;
+
+ switch(ch->num) {
+ case 0: /* play */
+ KASSERT(dir == PCMDIR_PLAY, ("wrong direction"));
+ ch->regbase = ICH_REG_PO_BASE;
+ ch->spdreg = sc->hasvra? AC97_REGEXT_FDACRATE : 0;
break;
- default:
- break;
- }
- return 0;
-}
-static int
-ichpchan_getptr(kobj_t obj, void *data)
-{
- struct sc_chinfo *ch = data;
- struct sc_info *sc = ch->parent;
- u_int32_t ci;
-
-#if(0)
- device_printf(ch->parent->dev, "ichpchan_getptr(0x%08x)\n", data);
-#endif
- ci = bus_space_read_1(sc->nabmbart, sc->nabmbarh, ICH_REG_PO_CIV);
-#if(0)
- device_printf(ch->parent->dev, "ichpchan_getptr():ICH_REG_PO_CIV = %d\n", ci);
-#endif
- return ICH_DEFAULT_BLOCKSZ * ci;
-}
-
-static struct pcmchan_caps *
-ichpchan_getcaps(kobj_t obj, void *data)
-{
- return &ich_playcaps;
-}
-
-static kobj_method_t ichpchan_methods[] = {
- KOBJMETHOD(channel_init, ichpchan_init),
- KOBJMETHOD(channel_free, ichpchan_free),
- KOBJMETHOD(channel_setformat, ichpchan_setformat),
- KOBJMETHOD(channel_setspeed, ichpchan_setspeed),
- KOBJMETHOD(channel_setblocksize, ichpchan_setblocksize),
- KOBJMETHOD(channel_trigger, ichpchan_trigger),
- KOBJMETHOD(channel_getptr, ichpchan_getptr),
- KOBJMETHOD(channel_getcaps, ichpchan_getcaps),
- { 0, 0 }
-};
-CHANNEL_DECLARE(ichpchan);
+ case 1: /* mic */
+ KASSERT(dir == PCMDIR_REC, ("wrong direction"));
+ ch->regbase = ICH_REG_MC_BASE;
+ ch->spdreg = sc->hasvrm? AC97_REGEXT_MADCRATE : 0;
+ break;
-/* -------------------------------------------------------------------- */
-/* record channel interface */
-static int
-ichrchan_power(kobj_t obj, struct sc_info *sc, int sw)
-{
- u_int32_t cr;
- int i;
+ case 2: /* record */
+ KASSERT(dir == PCMDIR_REC, ("wrong direction"));
+ ch->regbase = ICH_REG_PI_BASE;
+ ch->spdreg = sc->hasvra? AC97_REGEXT_LADCRATE : 0;
+ break;
- cr = ich_rdcd(obj, sc, AC97_REG_POWER);
- if (sw) { /* power on */
- cr &= ~AC97_POWER_PINPOWER;
- ich_wrcd(obj, sc, AC97_REG_POWER, cr);
- for (i = 0;i < ICH_TIMEOUT;i++) {
- cr = ich_rdcd(obj, sc, AC97_REG_POWER);
- if ((cr & AC97_POWER_PINREADY) != 0)
- break;
- }
- }
- else { /* power off */
- cr |= AC97_POWER_PINPOWER;
- ich_wrcd(obj, sc, AC97_REG_POWER, cr);
- for (i = 0;i < ICH_TIMEOUT;i++) {
- cr = ich_rdcd(obj, sc, AC97_REG_POWER);
- if ((cr & AC97_POWER_PINREADY) == 0)
- break;
- }
+ default:
+ return NULL;
}
- if (i == ICH_TIMEOUT)
- return -1;
- return 0;
-}
-static u_int32_t
-ichrchan_getminspeed(kobj_t obj, void *data)
-{
- struct sc_chinfo *ch = data;
- u_int32_t extcap;
- u_int32_t minspeed = 48000; /* before AC'97 R2.0 */
- int i = 0;
-
- extcap = ac97_getextmode(ch->parent->codec);
- if (extcap & AC97_EXTCAP_VRM) {
- for (i = 0;ich_rate[i] != 0;i++) {
- if (ac97_setrate(ch->parent->codec, AC97_REGEXT_LADCRATE, ich_rate[i]) == ich_rate[i])
- minspeed = ich_rate[i];
- }
- }
- return minspeed;
-}
+ if (sndbuf_alloc(ch->buffer, sc->dmat, ICH_DEFAULT_BUFSZ))
+ return NULL;
-static void *
-ichrchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
-{
- struct sc_info *sc = devinfo;
- struct sc_chinfo *ch;
- u_int32_t cr;
- int i;
+ ich_wr(sc, ch->regbase + ICH_REG_X_BDBAR, (u_int32_t)vtophys(ch->dtbl), 4);
- /* reset codec */
- bus_space_write_1(sc->nabmbart, sc->nabmbarh, ICH_REG_PI_CR, 0);
- bus_space_write_1(sc->nabmbart, sc->nabmbarh, ICH_REG_PI_CR,
- ICH_X_CR_RR);
- for (i = 0;i < ICH_TIMEOUT;i++) {
- cr = bus_space_read_1(sc->nabmbart, sc->nabmbarh,
- ICH_REG_PI_CR);
- if (cr == 0)
- break;
- }
- if (i == ICH_TIMEOUT) {
- device_printf(sc->dev, "cannot reset record codec\n");
- return NULL;
- }
- if (ichrchan_power(obj, sc, 1) == -1) {
- device_printf(sc->dev, "record ADC not ready\n");
- return NULL;
- }
- ichrchan_power(obj, sc, 0);
- if ((ch = malloc(sizeof(*ch), M_DEVBUF, M_NOWAIT)) == NULL) {
- device_printf(sc->dev, "cannot allocate channel info area\n");
- return NULL;
- }
- ch->buffer = b;
- ch->channel = c;
- ch->parent = sc;
- ch->dir = PCMDIR_REC;
- ch->run = 0;
- ch->lvi = 0;
- if (ichchan_initbuf(ch)) {
- device_printf(sc->dev, "cannot allocate channel buffer\n");
- free(ch, M_DEVBUF);
- return NULL;
- }
- bus_space_write_4(sc->nabmbart, sc->nabmbarh, ICH_REG_PI_BDBAR,
- (u_int32_t)vtophys(ch->index));
- sc->pi = ch;
- if (bootverbose) {
- device_printf(sc->dev,"Record codec support rate(Hz): ");
- for (i = 0;ich_rate[i] != 0;i++) {
- if (ichrchan_setspeed(obj, ch, ich_rate[i]) == ich_rate[i]) {
- printf("%d ", ich_rate[i]);
- }
- }
- printf("\n");
- }
- ich_reccaps.minspeed = ichrchan_getminspeed(obj, ch);
return ch;
}
static int
-ichrchan_free(kobj_t obj, void *data)
+ichchan_setformat(kobj_t obj, void *data, u_int32_t format)
{
- struct sc_chinfo *ch = data;
- ichchan_free(ch);
- return ichrchan_power(obj, ch->parent, 0);
+ return 0;
}
static int
-ichrchan_setformat(kobj_t obj, void *data, u_int32_t format)
+ichchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
{
struct sc_chinfo *ch = data;
+ struct sc_info *sc = ch->parent;
- ch->fmt = format;
-
- return 0;
+ if (ch->spdreg)
+ return ac97_setrate(sc->codec, ch->spdreg, speed);
+ else
+ return 48000;
}
static int
-ichrchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
+ichchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
{
struct sc_chinfo *ch = data;
- u_int32_t extcap;
-
- extcap = ac97_getextmode(ch->parent->codec);
- if (extcap & AC97_EXTCAP_VRM) {
- ch->spd = (u_int32_t)ac97_setrate(ch->parent->codec, AC97_REGEXT_LADCRATE, speed);
- }
- else {
- ch->spd = 48000; /* before AC'97 R2.0 */
- }
+ struct sc_info *sc = ch->parent;
- return ch->spd;
-}
+ ch->blksz = blocksize;
+ ich_filldtbl(ch);
+ ich_wr(sc, ch->regbase + ICH_REG_X_LVI, ICH_DTBL_LENGTH - 1, 1);
-static int
-ichrchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
-{
- return blocksize;
+ return ch->blksz;
}
-/* semantic note: must start at beginning of buffer */
static int
-ichrchan_trigger(kobj_t obj, void *data, int go)
+ichchan_trigger(kobj_t obj, void *data, int go)
{
struct sc_chinfo *ch = data;
struct sc_info *sc = ch->parent;
- u_int32_t cr;
- int i;
switch (go) {
case PCMTRIG_START:
ch->run = 1;
- ichrchan_power(obj, sc, 1);
- bus_space_write_4(sc->nabmbart, sc->nabmbarh, ICH_REG_PI_BDBAR,
- (u_int32_t)vtophys(ch->index));
- ch->lvi = ICH_FIFOINDEX - 1;
- bus_space_write_1(sc->nabmbart, sc->nabmbarh, ICH_REG_PI_LVI,
- ch->lvi);
- bus_space_write_1(sc->nabmbart, sc->nabmbarh, ICH_REG_PI_CR,
- ICH_X_CR_RPBM | ICH_X_CR_LVBIE | ICH_X_CR_IOCE |
- ICH_X_CR_FEIE);
- break;
- case PCMTRIG_STOP:
- cr = bus_space_read_1(sc->nabmbart, sc->nabmbarh,
- ICH_REG_PI_CR);
- bus_space_write_1(sc->nabmbart, sc->nabmbarh, ICH_REG_PI_CR,
- cr & ~ICH_X_CR_RPBM);
- ichrchan_power(obj, sc, 0);
- ch->run = 0;
+ ich_wr(sc, ch->regbase + ICH_REG_X_BDBAR, (u_int32_t)vtophys(ch->dtbl), 4);
+ ich_wr(sc, ch->regbase + ICH_REG_X_CR, ICH_X_CR_RPBM | ICH_X_CR_LVBIE | ICH_X_CR_IOCE | ICH_X_CR_FEIE, 1);
break;
+
case PCMTRIG_ABORT:
- bus_space_write_1(sc->nabmbart, sc->nabmbarh, ICH_REG_PI_CR,
- 0);
- bus_space_write_1(sc->nabmbart, sc->nabmbarh, ICH_REG_PI_CR,
- ICH_X_CR_RR);
- for (i = 0;i < ICH_TIMEOUT;i++) {
- cr = bus_space_read_1(sc->nabmbart, sc->nabmbarh,
- ICH_REG_PI_CR);
- if (cr == 0)
- break;
- }
- ichrchan_power(obj, sc, 0);
+ ich_resetchan(sc, ch->num);
ch->run = 0;
- ch->lvi = 0;
- break;
- default:
break;
}
return 0;
}
static int
-ichrchan_getptr(kobj_t obj, void *data)
+ichchan_getptr(kobj_t obj, void *data)
{
struct sc_chinfo *ch = data;
struct sc_info *sc = ch->parent;
- u_int32_t ci;
+ u_int32_t ci, ofs, pos;
+
+ ofs = 0;
+ ci = 1234;
+ while (ci != ich_rd(sc, ch->regbase + ICH_REG_X_CIV, 1)) {
+ ci = ich_rd(sc, ch->regbase + ICH_REG_X_CIV, 1);
+ ofs = ich_rd(sc, ch->regbase + ICH_REG_X_PICB, 2) * 2;
+ }
- ci = bus_space_read_1(sc->nabmbart, sc->nabmbarh, ICH_REG_PI_CIV);
- return ci * ICH_DEFAULT_BLOCKSZ;
+ ofs = ch->blksz - ofs;
+ ci %= ch->blkcnt;
+ pos = (ch->blksz * ci) + ofs;
+
+ return pos;
}
static struct pcmchan_caps *
-ichrchan_getcaps(kobj_t obj, void *data)
+ichchan_getcaps(kobj_t obj, void *data)
{
- return &ich_reccaps;
+ struct sc_chinfo *ch = data;
+
+ return ch->spdreg? &ich_vrcaps : &ich_caps;
}
-static kobj_method_t ichrchan_methods[] = {
- KOBJMETHOD(channel_init, ichrchan_init),
- KOBJMETHOD(channel_free, ichrchan_free),
- KOBJMETHOD(channel_setformat, ichrchan_setformat),
- KOBJMETHOD(channel_setspeed, ichrchan_setspeed),
- KOBJMETHOD(channel_setblocksize, ichrchan_setblocksize),
- KOBJMETHOD(channel_trigger, ichrchan_trigger),
- KOBJMETHOD(channel_getptr, ichrchan_getptr),
- KOBJMETHOD(channel_getcaps, ichrchan_getcaps),
+static kobj_method_t ichchan_methods[] = {
+ KOBJMETHOD(channel_init, ichchan_init),
+ KOBJMETHOD(channel_setformat, ichchan_setformat),
+ KOBJMETHOD(channel_setspeed, ichchan_setspeed),
+ KOBJMETHOD(channel_setblocksize, ichchan_setblocksize),
+ KOBJMETHOD(channel_trigger, ichchan_trigger),
+ KOBJMETHOD(channel_getptr, ichchan_getptr),
+ KOBJMETHOD(channel_getcaps, ichchan_getcaps),
{ 0, 0 }
};
-CHANNEL_DECLARE(ichrchan);
+CHANNEL_DECLARE(ichchan);
/* -------------------------------------------------------------------- */
/* The interrupt handler */
+
static void
ich_intr(void *p)
{
struct sc_info *sc = (struct sc_info *)p;
struct sc_chinfo *ch;
- u_int32_t cp;
- u_int32_t sg;
- u_int32_t st;
- u_int32_t lvi = 0;
-
-#if(0)
- device_printf(sc->dev, "ich_intr(0x%08x)\n", p);
-#endif
- /* check interface status */
- sg = bus_space_read_4(sc->nabmbart, sc->nabmbarh, ICH_REG_GLOB_STA);
-#if(0)
- device_printf(sc->dev, "ich_intr():REG_GLOB_STA = 0x%08x\n", sg);
-#endif
- if (sg & ICH_GLOB_STA_POINT) {
- /* PCM Out INTerrupt */
- /* mask interrupt */
- cp = bus_space_read_1(sc->nabmbart, sc->nabmbarh,
- ICH_REG_PO_CR);
- cp &= ~(ICH_X_CR_LVBIE | ICH_X_CR_IOCE | ICH_X_CR_FEIE);
- bus_space_write_1(sc->nabmbart, sc->nabmbarh, ICH_REG_PO_CR,
- cp);
- /* check channel status */
- ch = sc->po;
- st = bus_space_read_2(sc->nabmbart, sc->nabmbarh,
- ICH_REG_PO_SR);
-#if(0)
- device_printf(sc->dev, "ich_intr():REG_PO_SR = 0x%02x\n", st);
-#endif
- if (st & (ICH_X_SR_BCIS | ICH_X_SR_LVBCI)) {
- /* play buffer block complete */
- if (st & ICH_X_SR_LVBCI)
- lvi = ch->lvi;
- /* update buffer */
- chn_intr(ch->channel);
- ichpchan_update(ch);
- if (st & ICH_X_SR_LVBCI) {
- /* re-check underflow status */
- if (lvi == ch->lvi) {
- /* ch->buffer->underflow = 1; */
- ichpchan_fillblank(ch);
- }
- }
- }
- /* clear status bit */
- bus_space_write_2(sc->nabmbart, sc->nabmbarh, ICH_REG_PO_SR,
- st & (ICH_X_SR_FIFOE | ICH_X_SR_BCIS | ICH_X_SR_LVBCI));
- /* set interrupt */
- cp |= (ICH_X_CR_LVBIE | ICH_X_CR_IOCE | ICH_X_CR_FEIE);
- bus_space_write_1(sc->nabmbart, sc->nabmbarh, ICH_REG_PO_CR,
- cp);
- }
- if (sg & ICH_GLOB_STA_PIINT) {
- /* PCM In INTerrupt */
- /* mask interrupt */
- cp = bus_space_read_1(sc->nabmbart, sc->nabmbarh,
- ICH_REG_PI_CR);
- cp &= ~(ICH_X_CR_LVBIE | ICH_X_CR_IOCE | ICH_X_CR_FEIE);
- bus_space_write_1(sc->nabmbart, sc->nabmbarh, ICH_REG_PI_CR,
- cp);
+ u_int32_t st, lvi;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ ch = &sc->ch[i];
/* check channel status */
- ch = sc->pi;
- st = bus_space_read_2(sc->nabmbart, sc->nabmbarh,
- ICH_REG_PI_SR);
-#if(0)
- device_printf(sc->dev, "ich_intr():REG_PI_SR = 0x%02x\n", st);
-#endif
- if (st & (ICH_X_SR_BCIS | ICH_X_SR_LVBCI)) {
- /* record buffer block filled */
- if (st & ICH_X_SR_LVBCI)
- lvi = ch->lvi;
- /* update space */
- chn_intr(ch->channel);
- ch->lvi = sndbuf_getreadyptr(ch->buffer) / ICH_DEFAULT_BLOCKSZ - 1;
- if (ch->lvi < 0)
- ch->lvi = ICH_FIFOINDEX - 1;
- bus_space_write_1(sc->nabmbart, sc->nabmbarh,
- ICH_REG_PI_LVI, ch->lvi);
- if (st & ICH_X_SR_LVBCI) {
- /* re-check underflow status */
- if (lvi == ch->lvi) {
- ch->lvi++;
- if (ch->lvi == ICH_FIFOINDEX)
- ch->lvi = 0;
- bus_space_write_1(sc->nabmbart,
- sc->nabmbarh, ICH_REG_PI_LVI,
- ch->lvi);
- }
+ st = ich_rd(sc, ch->regbase + ICH_REG_X_SR, 2);
+ st &= ICH_X_SR_FIFOE | ICH_X_SR_BCIS | ICH_X_SR_LVBCI;
+ if (st != 0) {
+ if (st & (ICH_X_SR_BCIS | ICH_X_SR_LVBCI)) {
+ /* block complete - update buffer */
+ if (ch->run)
+ chn_intr(ch->channel);
+ lvi = ich_rd(sc, ch->regbase + ICH_REG_X_LVI, 1);
+ lvi++;
+ lvi %= ICH_DTBL_LENGTH;
+ ich_wr(sc, ch->regbase + ICH_REG_X_LVI, lvi, 1);
}
+ /* clear status bit */
+ ich_wr(sc, ch->regbase + ICH_REG_X_SR, st, 2);
}
- /* clear status bit */
- bus_space_write_2(sc->nabmbart, sc->nabmbarh, ICH_REG_PI_SR,
- st & (ICH_X_SR_FIFOE | ICH_X_SR_BCIS | ICH_X_SR_LVBCI));
- /* set interrupt */
- cp |= (ICH_X_CR_LVBIE | ICH_X_CR_IOCE | ICH_X_CR_FEIE);
- bus_space_write_1(sc->nabmbart, sc->nabmbarh, ICH_REG_PI_CR,
- cp);
}
}
/* -------------------------------------------------------------------- */
+/* Probe and attach the card */
-/*
- * Probe and attach the card
- */
+static void
+ich_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ return;
+}
static int
ich_init(struct sc_info *sc)
{
u_int32_t stat;
- u_int32_t save;
+ int sz;
- bus_space_write_4(sc->nabmbart, sc->nabmbarh,
- ICH_REG_GLOB_CNT, ICH_GLOB_CTL_COLD);
+ ich_wr(sc, ICH_REG_GLOB_CNT, ICH_GLOB_CTL_COLD, 4);
DELAY(600000);
- stat = bus_space_read_4(sc->nabmbart, sc->nabmbarh, ICH_REG_GLOB_STA);
+ stat = ich_rd(sc, ICH_REG_GLOB_STA, 4);
+
if ((stat & ICH_GLOB_STA_PCR) == 0)
- return -1;
- bus_space_write_4(sc->nabmbart, sc->nabmbarh,
- ICH_REG_GLOB_CNT, ICH_GLOB_CTL_COLD | ICH_GLOB_CTL_PRES);
- save = bus_space_read_2(sc->nambart, sc->nambarh, AC97_MIX_MASTER);
- bus_space_write_2(sc->nambart, sc->nambarh, AC97_MIX_MASTER,
- AC97_MUTE);
- if (ich_waitcd(sc) == ETIMEDOUT)
- return -1;
- DELAY(600); /* it is need for some system */
- stat = bus_space_read_2(sc->nambart, sc->nambarh, AC97_MIX_MASTER);
- if (stat != AC97_MUTE)
- return -1;
- bus_space_write_2(sc->nambart, sc->nambarh, AC97_MIX_MASTER, save);
- return 0;
-}
+ return ENXIO;
-static int
-ich_finddev(u_int32_t dev, u_int32_t subdev)
-{
- int i;
+ ich_wr(sc, ICH_REG_GLOB_CNT, ICH_GLOB_CTL_COLD | ICH_GLOB_CTL_PRES, 4);
- for (i = 0; ich_devs[i].dev; i++) {
- if (ich_devs[i].dev == dev &&
- (ich_devs[i].subdev == subdev || ich_devs[i].subdev == 0))
- return i;
+ if (ich_resetchan(sc, 0) || ich_resetchan(sc, 0))
+ return ENXIO;
+
+ if (bus_dmamem_alloc(sc->dmat, (void **)&sc->dtbl, BUS_DMA_NOWAIT, &sc->dtmap))
+ return ENOSPC;
+
+ sz = sizeof(struct ich_desc) * ICH_DTBL_LENGTH * 3;
+ if (bus_dmamap_load(sc->dmat, sc->dtmap, sc->dtbl, sz, ich_setmap, NULL, 0)) {
+ bus_dmamem_free(sc->dmat, (void **)&sc->dtbl, sc->dtmap);
+ return ENOSPC;
}
- return -1;
+
+ return 0;
}
static int
ich_pci_probe(device_t dev)
{
- int i;
- u_int32_t subdev;
+ switch(pci_get_devid(dev)) {
+ case 0x71958086:
+ device_set_desc(dev, "Intel 443MX");
+ return 0;
+
+ case 0x24158086:
+ device_set_desc(dev, "Intel 82801AA (ICH)");
+ return 0;
- subdev = (pci_get_subdevice(dev) << 16) | pci_get_subvendor(dev);
- i = ich_finddev(pci_get_devid(dev), subdev);
- if (i >= 0) {
- device_set_desc(dev, ich_devs[i].name);
+ case 0x24258086:
+ device_set_desc(dev, "Intel 82901AB (ICH)");
return 0;
- } else
+
+ case 0x24458086:
+ device_set_desc(dev, "Intel 82801BA (ICH2)");
+ return 0;
+
+ default:
return ENXIO;
+ }
}
static int
ich_pci_attach(device_t dev)
{
u_int32_t data;
- u_int32_t subdev;
struct sc_info *sc;
char status[SND_STATUSLEN];
@@ -1049,9 +473,6 @@ ich_pci_attach(device_t dev)
bzero(sc, sizeof(*sc));
sc->dev = dev;
- subdev = (pci_get_subdevice(dev) << 16) | pci_get_subvendor(dev);
- sc->type = ich_finddev(pci_get_devid(dev), subdev);
- sc->rev = pci_get_revid(dev);
data = pci_read_config(dev, PCIR_COMMAND, 2);
data |= (PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
@@ -1060,30 +481,26 @@ ich_pci_attach(device_t dev)
sc->nambarid = PCIR_NAMBAR;
sc->nabmbarid = PCIR_NABMBAR;
- sc->nambar = bus_alloc_resource(dev, SYS_RES_IOPORT,
- &sc->nambarid, 0, ~0, 256, RF_ACTIVE);
- sc->nabmbar = bus_alloc_resource(dev, SYS_RES_IOPORT,
- &sc->nabmbarid, 0, ~0, 64, RF_ACTIVE);
+ sc->nambar = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->nambarid, 0, ~0, 1, RF_ACTIVE);
+ sc->nabmbar = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->nabmbarid, 0, ~0, 1, RF_ACTIVE);
+
if (!sc->nambar || !sc->nabmbar) {
device_printf(dev, "unable to map IO port space\n");
goto bad;
}
+
sc->nambart = rman_get_bustag(sc->nambar);
sc->nambarh = rman_get_bushandle(sc->nambar);
sc->nabmbart = rman_get_bustag(sc->nabmbar);
sc->nabmbarh = rman_get_bushandle(sc->nabmbar);
- if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/4, /*boundary*/0,
- /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
- /*highaddr*/BUS_SPACE_MAXADDR,
- /*filter*/NULL, /*filterarg*/NULL,
- /*maxsize*/65536, /*nsegments*/1, /*maxsegsz*/0x3ffff,
- /*flags*/0, &sc->dmat) != 0) {
+ if (bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
+ NULL, NULL, ICH_DEFAULT_BUFSZ, 1, 0x3ffff, 0, &sc->dmat) != 0) {
device_printf(dev, "unable to create dma tag\n");
goto bad;
}
- if (ich_init(sc) == -1) {
+ if (ich_init(sc)) {
device_printf(dev, "unable to initialize the card\n");
goto bad;
}
@@ -1092,37 +509,30 @@ ich_pci_attach(device_t dev)
if (sc->codec == NULL)
goto bad;
mixer_init(dev, ac97_getmixerclass(), sc->codec);
+
/* check and set VRA function */
- if (ac97_setextmode(sc->codec, AC97_EXTCAP_VRA) == 0) {
- if (bootverbose) {
- device_printf(sc->dev, "set VRA function\n");
- }
- }
- if (ac97_setextmode(sc->codec, AC97_EXTCAP_VRM) == 0) {
- if (bootverbose) {
- device_printf(sc->dev, "set VRM function\n");
- }
- }
+ if (ac97_setextmode(sc->codec, AC97_EXTCAP_VRA) == 0)
+ sc->hasvra = 1;
+ if (ac97_setextmode(sc->codec, AC97_EXTCAP_VRM) == 0)
+ sc->hasvrm = 1;
sc->irqid = 0;
- sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irqid,
- 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
- if (!sc->irq ||
- bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, ich_intr, sc, &sc->ih)) {
+ sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irqid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
+ if (!sc->irq || snd_setup_intr(dev, sc->irq, INTR_MPSAFE, ich_intr, sc, &sc->ih)) {
device_printf(dev, "unable to map interrupt\n");
goto bad;
}
- snprintf(status, SND_STATUSLEN,
- "at io 0x%lx-0x%lx, 0x%lx-0x%lx irq %ld",
- rman_get_start(sc->nambar), rman_get_end(sc->nambar),
- rman_get_start(sc->nabmbar), rman_get_end(sc->nabmbar),
- rman_get_start(sc->irq));
-
- if (pcm_register(dev, sc, 1, 1))
+ if (pcm_register(dev, sc, 1, 2))
goto bad;
- pcm_addchan(dev, PCMDIR_PLAY, &ichpchan_class, sc);
- pcm_addchan(dev, PCMDIR_REC, &ichrchan_class, sc);
+
+ pcm_addchan(dev, PCMDIR_PLAY, &ichchan_class, sc);
+ pcm_addchan(dev, PCMDIR_REC, &ichchan_class, sc);
+ pcm_addchan(dev, PCMDIR_REC, &ichchan_class, sc);
+
+ snprintf(status, SND_STATUSLEN, "at io 0x%lx, 0x%lx irq %ld",
+ rman_get_start(sc->nambar), rman_get_start(sc->nabmbar), rman_get_start(sc->irq));
+
pcm_setstatus(dev, status);
return 0;
@@ -1155,11 +565,11 @@ ich_pci_detach(device_t dev)
return r;
sc = pcm_getdevinfo(dev);
+ bus_teardown_intr(dev, sc->irq, sc->ih);
+ bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
bus_release_resource(dev, SYS_RES_IOPORT, sc->nambarid, sc->nambar);
bus_release_resource(dev, SYS_RES_IOPORT, sc->nabmbarid, sc->nabmbar);
bus_dma_tag_destroy(sc->dmat);
- bus_teardown_intr(dev, sc->irq, sc->ih);
- bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
free(sc, M_DEVBUF);
return 0;
}
diff --git a/sys/dev/sound/pci/ich.h b/sys/dev/sound/pci/ich.h
new file mode 100644
index 0000000..78ecd8b
--- /dev/null
+++ b/sys/dev/sound/pci/ich.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2000 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
+ * Copyright (c) 2001 Cameron Grant <cg@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#define PCIR_NAMBAR 0x10
+#define PCIR_NABMBAR 0x14
+
+/* Native Audio Bus Master Control Registers */
+#define ICH_REG_X_BDBAR 0x00
+#define ICH_REG_X_CIV 0x04
+#define ICH_REG_X_LVI 0x05
+#define ICH_REG_X_SR 0x06
+#define ICH_REG_X_PICB 0x08
+#define ICH_REG_X_PIV 0x0a
+#define ICH_REG_X_CR 0x0b
+
+#define ICH_REG_PI_BASE 0x00
+#define ICH_REG_PO_BASE 0x10
+#define ICH_REG_MC_BASE 0x20
+
+#define ICH_REG_GLOB_CNT 0x2c
+#define ICH_REG_GLOB_STA 0x30
+#define ICH_REG_ACC_SEMA 0x34
+
+/* Status Register Values */
+#define ICH_X_SR_DCH 0x0001
+#define ICH_X_SR_CELV 0x0002
+#define ICH_X_SR_LVBCI 0x0004
+#define ICH_X_SR_BCIS 0x0008
+#define ICH_X_SR_FIFOE 0x0010
+
+/* Control Register Values */
+#define ICH_X_CR_RPBM 0x01
+#define ICH_X_CR_RR 0x02
+#define ICH_X_CR_LVBIE 0x04
+#define ICH_X_CR_FEIE 0x08
+#define ICH_X_CR_IOCE 0x10
+
+/* Global Control Register Values */
+#define ICH_GLOB_CTL_GIE 0x00000001
+#define ICH_GLOB_CTL_COLD 0x00000002 /* negate */
+#define ICH_GLOB_CTL_WARM 0x00000004
+#define ICH_GLOB_CTL_SHUT 0x00000008
+#define ICH_GLOB_CTL_PRES 0x00000010
+#define ICH_GLOB_CTL_SRES 0x00000020
+
+/* Global Status Register Values */
+#define ICH_GLOB_STA_GSCI 0x00000001
+#define ICH_GLOB_STA_MIINT 0x00000002
+#define ICH_GLOB_STA_MOINT 0x00000004
+#define ICH_GLOB_STA_PIINT 0x00000020
+#define ICH_GLOB_STA_POINT 0x00000040
+#define ICH_GLOB_STA_MINT 0x00000080
+#define ICH_GLOB_STA_PCR 0x00000100
+#define ICH_GLOB_STA_SCR 0x00000200
+#define ICH_GLOB_STA_PRES 0x00000400
+#define ICH_GLOB_STA_SRES 0x00000800
+#define ICH_GLOB_STA_SLOT12 0x00007000
+#define ICH_GLOB_STA_RCODEC 0x00008000
+#define ICH_GLOB_STA_AD3 0x00010000
+#define ICH_GLOB_STA_MD3 0x00020000
+#define ICH_GLOB_STA_IMASK (ICH_GLOB_STA_MIINT | ICH_GLOB_STA_MOINT | ICH_GLOB_STA_PIINT | ICH_GLOB_STA_POINT | ICH_GLOB_STA_MINT | ICH_GLOB_STA_PRES | ICH_GLOB_STA_SRES)
+
+/* play/record buffer */
+#define ICH_BDC_IOC 0x80000000
+#define ICH_BDC_BUP 0x40000000
+
OpenPOWER on IntegriCloud