summaryrefslogtreecommitdiffstats
path: root/sys/dev/sound/pci/fm801.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/sound/pci/fm801.c')
-rw-r--r--sys/dev/sound/pci/fm801.c419
1 files changed, 207 insertions, 212 deletions
diff --git a/sys/dev/sound/pci/fm801.c b/sys/dev/sound/pci/fm801.c
index 2173c0a..a01ea8e 100644
--- a/sys/dev/sound/pci/fm801.c
+++ b/sys/dev/sound/pci/fm801.c
@@ -101,15 +101,6 @@
/* debug purposes */
#define DPRINT if(0) printf
-
-/* channel interface */
-static void *fm801ch_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir);
-static int fm801ch_setformat(void *data, u_int32_t format);
-static int fm801ch_setspeed(void *data, u_int32_t speed);
-static int fm801ch_setblocksize(void *data, u_int32_t blocksize);
-static int fm801ch_trigger(void *data, int go);
-static int fm801ch_getptr(void *data);
-static pcmchan_caps *fm801ch_getcaps(void *data);
/*
static int fm801ch_setup(pcm_channel *c);
*/
@@ -127,25 +118,6 @@ static pcmchan_caps fm801ch_caps = {
fmts, 0
};
-static pcm_channel fm801_chantemplate = {
- fm801ch_init,
- NULL, /* setdir */
- fm801ch_setformat,
- fm801ch_setspeed,
- fm801ch_setblocksize,
- fm801ch_trigger,
- fm801ch_getptr,
- fm801ch_getcaps,
- NULL, /* free */
- NULL, /* nop1 */
- NULL, /* nop2 */
- NULL, /* nop3 */
- NULL, /* nop4 */
- NULL, /* nop5 */
- NULL, /* nop6 */
- NULL, /* nop7 */
-};
-
struct fm801_info;
struct fm801_chinfo {
@@ -220,12 +192,13 @@ fm801_wr(struct fm801_info *fm801, int regno, u_int32_t data, int size)
}
}
+/* -------------------------------------------------------------------- */
/*
* ac97 codec routines
*/
#define TIMO 50
-static u_int32_t
-fm801_rdcd(void *devinfo, int regno)
+static int
+fm801_rdcd(kobj_t obj, void *devinfo, int regno)
{
struct fm801_info *fm801 = (struct fm801_info *)devinfo;
int i;
@@ -254,8 +227,8 @@ fm801_rdcd(void *devinfo, int regno)
return fm801_rd(fm801,FM_CODEC_DATA,2);
}
-static void
-fm801_wrcd(void *devinfo, int regno, u_int32_t data)
+static int
+fm801_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data)
{
struct fm801_info *fm801 = (struct fm801_info *)devinfo;
int i;
@@ -271,7 +244,7 @@ fm801_wrcd(void *devinfo, int regno, u_int32_t data)
}
if (i >= TIMO) {
printf("fm801 wrcd: read codec busy\n");
- return;
+ return -1;
}
fm801_wr(fm801,FM_CODEC_DATA,data, 2);
@@ -284,12 +257,21 @@ fm801_wrcd(void *devinfo, int regno, u_int32_t data)
}
if (i >= TIMO) {
printf("fm801 wrcd: read codec busy\n");
- return;
+ return -1;
}
DPRINT("fm801 wrcd release reg 0x%x val 0x%x\n",regno, data);
- return;
+ return 0;
}
+static kobj_method_t fm801_ac97_methods[] = {
+ KOBJMETHOD(ac97_read, fm801_rdcd),
+ KOBJMETHOD(ac97_write, fm801_wrcd),
+ { 0, 0 }
+};
+AC97_DECLARE(fm801_ac97);
+
+/* -------------------------------------------------------------------- */
+
/*
* The interrupt handler
*/
@@ -337,179 +319,10 @@ fm801_intr(void *p)
fm801_wr(fm801, FM_INTSTATUS, intsrc & (FM_INTSTATUS_PLAY | FM_INTSTATUS_REC), 2);
}
-/*
- * Init routine is taken from an original NetBSD driver
- */
-static int
-fm801_init(struct fm801_info *fm801)
-{
- u_int32_t k1;
-
- /* reset codec */
- fm801_wr(fm801, FM_CODEC_CTL, 0x0020,2);
- DELAY(100000);
- fm801_wr(fm801, FM_CODEC_CTL, 0x0000,2);
- DELAY(100000);
-
- fm801_wr(fm801, FM_PCM_VOLUME, 0x0808,2);
- fm801_wr(fm801, FM_FM_VOLUME, 0x0808,2);
- fm801_wr(fm801, FM_I2S_VOLUME, 0x0808,2);
- fm801_wr(fm801, 0x40,0x107f,2); /* enable legacy audio */
-
- fm801_wr((void *)fm801, FM_RECORD_SOURCE, 0x0000,2);
-
- /* Unmask playback, record and mpu interrupts, mask the rest */
- k1 = fm801_rd((void *)fm801, FM_INTMASK,2);
- fm801_wr(fm801, FM_INTMASK,
- (k1 & ~(FM_INTMASK_PLAY | FM_INTMASK_REC | FM_INTMASK_MPU)) |
- FM_INTMASK_VOL,2);
- fm801_wr(fm801, FM_INTSTATUS,
- FM_INTSTATUS_PLAY | FM_INTSTATUS_REC | FM_INTSTATUS_MPU |
- FM_INTSTATUS_VOL,2);
-
- DPRINT("FM801 init Ok\n");
- return 0;
-}
-
-static int
-fm801_pci_attach(device_t dev)
-{
- u_int32_t data;
- struct ac97_info *codec = 0;
- struct fm801_info *fm801;
- int i;
- int mapped = 0;
- char status[SND_STATUSLEN];
-
- if ((fm801 = (struct fm801_info *)malloc(sizeof(*fm801),M_DEVBUF, M_NOWAIT)) == NULL) {
- device_printf(dev, "cannot allocate softc\n");
- return ENXIO;
- }
-
- bzero(fm801, sizeof(*fm801));
- fm801->type = pci_get_devid(dev);
-
- data = pci_read_config(dev, PCIR_COMMAND, 2);
- data |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
- pci_write_config(dev, PCIR_COMMAND, data, 2);
- data = pci_read_config(dev, PCIR_COMMAND, 2);
-
- for (i = 0; (mapped == 0) && (i < PCI_MAXMAPS_0); i++) {
- fm801->regid = PCIR_MAPS + i*4;
- fm801->regtype = SYS_RES_MEMORY;
- fm801->reg = bus_alloc_resource(dev, fm801->regtype, &fm801->regid,
- 0, ~0, 1, RF_ACTIVE);
- if(!fm801->reg)
- {
- fm801->regtype = SYS_RES_IOPORT;
- fm801->reg = bus_alloc_resource(dev, fm801->regtype, &fm801->regid,
- 0, ~0, 1, RF_ACTIVE);
- }
-
- if(fm801->reg) {
- fm801->st = rman_get_bustag(fm801->reg);
- fm801->sh = rman_get_bushandle(fm801->reg);
- mapped++;
- }
- }
-
- if (mapped == 0) {
- device_printf(dev, "unable to map register space\n");
- goto oops;
- }
-
- fm801_init(fm801);
-
- codec = ac97_create(dev, (void *)fm801, NULL, fm801_rdcd, fm801_wrcd);
- if (codec == NULL) goto oops;
-
- if (mixer_init(dev, &ac97_mixer, codec) == -1) goto oops;
-
- fm801->irqid = 0;
- fm801->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &fm801->irqid,
- 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
- if (!fm801->irq ||
- bus_setup_intr(dev, fm801->irq, INTR_TYPE_TTY,
- fm801_intr, fm801, &fm801->ih)) {
- device_printf(dev, "unable to map interrupt\n");
- goto oops;
- }
-
- if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
- /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
- /*highaddr*/BUS_SPACE_MAXADDR,
- /*filter*/NULL, /*filterarg*/NULL,
- /*maxsize*/FM801_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff,
- /*flags*/0, &fm801->parent_dmat) != 0) {
- device_printf(dev, "unable to create dma tag\n");
- goto oops;
- }
-
- snprintf(status, 64, "at %s 0x%lx irq %ld",
- (fm801->regtype == SYS_RES_IOPORT)? "io" : "memory",
- rman_get_start(fm801->reg), rman_get_start(fm801->irq));
-
-#define FM801_MAXPLAYCH 1
- if (pcm_register(dev, fm801, FM801_MAXPLAYCH, 1)) goto oops;
- pcm_addchan(dev, PCMDIR_PLAY, &fm801_chantemplate, fm801);
- pcm_addchan(dev, PCMDIR_REC, &fm801_chantemplate, fm801);
- pcm_setstatus(dev, status);
-
- return 0;
-
-oops:
- if (codec) ac97_destroy(codec);
- if (fm801->reg) bus_release_resource(dev, fm801->regtype, fm801->regid, fm801->reg);
- if (fm801->ih) bus_teardown_intr(dev, fm801->irq, fm801->ih);
- if (fm801->irq) bus_release_resource(dev, SYS_RES_IRQ, fm801->irqid, fm801->irq);
- if (fm801->parent_dmat) bus_dma_tag_destroy(fm801->parent_dmat);
- free(fm801, M_DEVBUF);
- return ENXIO;
-}
-
-static int
-fm801_pci_detach(device_t dev)
-{
- int r;
- struct fm801_info *fm801;
-
- DPRINT("Forte Media FM801 detach\n");
-
- r = pcm_unregister(dev);
- if (r)
- return r;
-
- fm801 = pcm_getdevinfo(dev);
- bus_release_resource(dev, fm801->regtype, fm801->regid, fm801->reg);
- bus_teardown_intr(dev, fm801->irq, fm801->ih);
- bus_release_resource(dev, SYS_RES_IRQ, fm801->irqid, fm801->irq);
- bus_dma_tag_destroy(fm801->parent_dmat);
- free(fm801, M_DEVBUF);
- return 0;
-}
-
-static int
-fm801_pci_probe( device_t dev )
-{
- int id;
- if ((id = pci_get_devid(dev)) == PCI_DEVICE_FORTEMEDIA1 ) {
- device_set_desc(dev, "Forte Media FM801 Audio Controller");
- return 0;
- }
-/*
- if ((id = pci_get_devid(dev)) == PCI_DEVICE_FORTEMEDIA2 ) {
- device_set_desc(dev, "Forte Media FM801 Joystick (Not Supported)");
- return ENXIO;
- }
-*/
- return ENXIO;
-}
-
-
-
+/* -------------------------------------------------------------------- */
/* channel interface */
static void *
-fm801ch_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
+fm801ch_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
{
struct fm801_info *fm801 = (struct fm801_info *)devinfo;
struct fm801_chinfo *ch = (dir == PCMDIR_PLAY)? &fm801->pch : &fm801->rch;
@@ -525,7 +338,7 @@ fm801ch_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
}
static int
-fm801ch_setformat(void *data, u_int32_t format)
+fm801ch_setformat(kobj_t obj, void *data, u_int32_t format)
{
struct fm801_chinfo *ch = data;
struct fm801_info *fm801 = ch->parent;
@@ -570,7 +383,7 @@ struct {
};
static int
-fm801ch_setspeed(void *data, u_int32_t speed)
+fm801ch_setspeed(kobj_t obj, void *data, u_int32_t speed)
{
struct fm801_chinfo *ch = data;
struct fm801_info *fm801 = ch->parent;
@@ -597,7 +410,7 @@ fm801ch_setspeed(void *data, u_int32_t speed)
}
static int
-fm801ch_setblocksize(void *data, u_int32_t blocksize)
+fm801ch_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
{
struct fm801_chinfo *ch = data;
struct fm801_info *fm801 = ch->parent;
@@ -618,7 +431,7 @@ fm801ch_setblocksize(void *data, u_int32_t blocksize)
}
static int
-fm801ch_trigger(void *data, int go)
+fm801ch_trigger(kobj_t obj, void *data, int go)
{
struct fm801_chinfo *ch = data;
struct fm801_info *fm801 = ch->parent;
@@ -678,7 +491,7 @@ fm801ch_trigger(void *data, int go)
/* Almost ALSA copy */
static int
-fm801ch_getptr(void *data)
+fm801ch_getptr(kobj_t obj, void *data)
{
struct fm801_chinfo *ch = data;
struct fm801_info *fm801 = ch->parent;
@@ -704,11 +517,193 @@ fm801ch_getptr(void *data)
}
static pcmchan_caps *
-fm801ch_getcaps(void *data)
+fm801ch_getcaps(kobj_t obj, void *data)
{
return &fm801ch_caps;
}
+static kobj_method_t fm801ch_methods[] = {
+ KOBJMETHOD(channel_init, fm801ch_init),
+ KOBJMETHOD(channel_setformat, fm801ch_setformat),
+ KOBJMETHOD(channel_setspeed, fm801ch_setspeed),
+ KOBJMETHOD(channel_setblocksize, fm801ch_setblocksize),
+ KOBJMETHOD(channel_trigger, fm801ch_trigger),
+ KOBJMETHOD(channel_getptr, fm801ch_getptr),
+ KOBJMETHOD(channel_getcaps, fm801ch_getcaps),
+ { 0, 0 }
+};
+CHANNEL_DECLARE(fm801ch);
+
+/* -------------------------------------------------------------------- */
+
+/*
+ * Init routine is taken from an original NetBSD driver
+ */
+static int
+fm801_init(struct fm801_info *fm801)
+{
+ u_int32_t k1;
+
+ /* reset codec */
+ fm801_wr(fm801, FM_CODEC_CTL, 0x0020,2);
+ DELAY(100000);
+ fm801_wr(fm801, FM_CODEC_CTL, 0x0000,2);
+ DELAY(100000);
+
+ fm801_wr(fm801, FM_PCM_VOLUME, 0x0808,2);
+ fm801_wr(fm801, FM_FM_VOLUME, 0x0808,2);
+ fm801_wr(fm801, FM_I2S_VOLUME, 0x0808,2);
+ fm801_wr(fm801, 0x40,0x107f,2); /* enable legacy audio */
+
+ fm801_wr((void *)fm801, FM_RECORD_SOURCE, 0x0000,2);
+
+ /* Unmask playback, record and mpu interrupts, mask the rest */
+ k1 = fm801_rd((void *)fm801, FM_INTMASK,2);
+ fm801_wr(fm801, FM_INTMASK,
+ (k1 & ~(FM_INTMASK_PLAY | FM_INTMASK_REC | FM_INTMASK_MPU)) |
+ FM_INTMASK_VOL,2);
+ fm801_wr(fm801, FM_INTSTATUS,
+ FM_INTSTATUS_PLAY | FM_INTSTATUS_REC | FM_INTSTATUS_MPU |
+ FM_INTSTATUS_VOL,2);
+
+ DPRINT("FM801 init Ok\n");
+ return 0;
+}
+
+static int
+fm801_pci_attach(device_t dev)
+{
+ u_int32_t data;
+ struct ac97_info *codec = 0;
+ struct fm801_info *fm801;
+ int i;
+ int mapped = 0;
+ char status[SND_STATUSLEN];
+
+ if ((fm801 = (struct fm801_info *)malloc(sizeof(*fm801),M_DEVBUF, M_NOWAIT)) == NULL) {
+ device_printf(dev, "cannot allocate softc\n");
+ return ENXIO;
+ }
+
+ bzero(fm801, sizeof(*fm801));
+ fm801->type = pci_get_devid(dev);
+
+ data = pci_read_config(dev, PCIR_COMMAND, 2);
+ data |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
+ pci_write_config(dev, PCIR_COMMAND, data, 2);
+ data = pci_read_config(dev, PCIR_COMMAND, 2);
+
+ for (i = 0; (mapped == 0) && (i < PCI_MAXMAPS_0); i++) {
+ fm801->regid = PCIR_MAPS + i*4;
+ fm801->regtype = SYS_RES_MEMORY;
+ fm801->reg = bus_alloc_resource(dev, fm801->regtype, &fm801->regid,
+ 0, ~0, 1, RF_ACTIVE);
+ if(!fm801->reg)
+ {
+ fm801->regtype = SYS_RES_IOPORT;
+ fm801->reg = bus_alloc_resource(dev, fm801->regtype, &fm801->regid,
+ 0, ~0, 1, RF_ACTIVE);
+ }
+
+ if(fm801->reg) {
+ fm801->st = rman_get_bustag(fm801->reg);
+ fm801->sh = rman_get_bushandle(fm801->reg);
+ mapped++;
+ }
+ }
+
+ if (mapped == 0) {
+ device_printf(dev, "unable to map register space\n");
+ goto oops;
+ }
+
+ fm801_init(fm801);
+
+ codec = AC97_CREATE(dev, fm801, fm801_ac97);
+ if (codec == NULL) goto oops;
+
+ if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) goto oops;
+
+ fm801->irqid = 0;
+ fm801->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &fm801->irqid,
+ 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
+ if (!fm801->irq ||
+ bus_setup_intr(dev, fm801->irq, INTR_TYPE_TTY,
+ fm801_intr, fm801, &fm801->ih)) {
+ device_printf(dev, "unable to map interrupt\n");
+ goto oops;
+ }
+
+ if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
+ /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
+ /*highaddr*/BUS_SPACE_MAXADDR,
+ /*filter*/NULL, /*filterarg*/NULL,
+ /*maxsize*/FM801_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff,
+ /*flags*/0, &fm801->parent_dmat) != 0) {
+ device_printf(dev, "unable to create dma tag\n");
+ goto oops;
+ }
+
+ snprintf(status, 64, "at %s 0x%lx irq %ld",
+ (fm801->regtype == SYS_RES_IOPORT)? "io" : "memory",
+ rman_get_start(fm801->reg), rman_get_start(fm801->irq));
+
+#define FM801_MAXPLAYCH 1
+ if (pcm_register(dev, fm801, FM801_MAXPLAYCH, 1)) goto oops;
+ pcm_addchan(dev, PCMDIR_PLAY, &fm801ch_class, fm801);
+ pcm_addchan(dev, PCMDIR_REC, &fm801ch_class, fm801);
+ pcm_setstatus(dev, status);
+
+ return 0;
+
+oops:
+ if (codec) ac97_destroy(codec);
+ if (fm801->reg) bus_release_resource(dev, fm801->regtype, fm801->regid, fm801->reg);
+ if (fm801->ih) bus_teardown_intr(dev, fm801->irq, fm801->ih);
+ if (fm801->irq) bus_release_resource(dev, SYS_RES_IRQ, fm801->irqid, fm801->irq);
+ if (fm801->parent_dmat) bus_dma_tag_destroy(fm801->parent_dmat);
+ free(fm801, M_DEVBUF);
+ return ENXIO;
+}
+
+static int
+fm801_pci_detach(device_t dev)
+{
+ int r;
+ struct fm801_info *fm801;
+
+ DPRINT("Forte Media FM801 detach\n");
+
+ r = pcm_unregister(dev);
+ if (r)
+ return r;
+
+ fm801 = pcm_getdevinfo(dev);
+ bus_release_resource(dev, fm801->regtype, fm801->regid, fm801->reg);
+ bus_teardown_intr(dev, fm801->irq, fm801->ih);
+ bus_release_resource(dev, SYS_RES_IRQ, fm801->irqid, fm801->irq);
+ bus_dma_tag_destroy(fm801->parent_dmat);
+ free(fm801, M_DEVBUF);
+ return 0;
+}
+
+static int
+fm801_pci_probe( device_t dev )
+{
+ int id;
+ if ((id = pci_get_devid(dev)) == PCI_DEVICE_FORTEMEDIA1 ) {
+ device_set_desc(dev, "Forte Media FM801 Audio Controller");
+ return 0;
+ }
+/*
+ if ((id = pci_get_devid(dev)) == PCI_DEVICE_FORTEMEDIA2 ) {
+ device_set_desc(dev, "Forte Media FM801 Joystick (Not Supported)");
+ return ENXIO;
+ }
+*/
+ return ENXIO;
+}
+
static device_method_t fm801_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, fm801_pci_probe),
OpenPOWER on IntegriCloud