2006-03-26 22:07:51

by Rene Herman

[permalink] [raw]
Subject: [ALSA] AdLib FM card driver

Index: local/sound/isa/adlib.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ local/sound/isa/adlib.c 2006-03-26 21:38:02.000000000 +0200
@@ -0,0 +1,154 @@
+/*
+ * AdLib FM card driver.
+ */
+
+#include <sound/driver.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/opl3.h>
+
+#define CRD_NAME "AdLib FM"
+#define DRV_NAME "snd_adlib"
+
+MODULE_DESCRIPTION(CRD_NAME);
+MODULE_AUTHOR("Rene Herman");
+MODULE_LICENSE("GPL");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
+static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
+module_param_array(port, long, NULL, 0444);
+MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
+
+static struct platform_device *devices[SNDRV_CARDS];
+
+static void snd_adlib_free(struct snd_card *card)
+{
+ release_and_free_resource(card->private_data);
+}
+
+static int __devinit snd_adlib_probe(struct platform_device *device)
+{
+ struct snd_card *card;
+ struct snd_opl3 *opl3;
+
+ int i = device->id;
+
+ if (port[i] == SNDRV_AUTO_PORT) {
+ snd_printk(KERN_ERR DRV_NAME ": please specify port\n");
+ return -EINVAL;
+ }
+
+ card = snd_card_new(index[i], id[i], THIS_MODULE, 0);
+ if (!card) {
+ snd_printk(KERN_ERR DRV_NAME ": could not create card\n");
+ return -EINVAL;
+ }
+
+ card->private_data = request_region(port[i], 4, CRD_NAME);
+ if (!card->private_data) {
+ snd_printk(KERN_ERR DRV_NAME ": could not grab ports\n");
+ snd_card_free(card);
+ return -EINVAL;
+ }
+ card->private_free = snd_adlib_free;
+
+ if (snd_opl3_create(card, port[i], port[i] + 2, OPL3_HW_AUTO, 1, &opl3) < 0) {
+ snd_printk(KERN_ERR DRV_NAME ": could not create OPL\n");
+ snd_card_free(card);
+ return -EINVAL;
+ }
+
+ if (snd_opl3_hwdep_new(opl3, 0, 0, NULL) < 0) {
+ snd_printk(KERN_ERR DRV_NAME ": could not create FM\n");
+ snd_card_free(card);
+ return -EINVAL;
+ }
+
+ strcpy(card->driver, DRV_NAME);
+ strcpy(card->shortname, CRD_NAME);
+ sprintf(card->longname, CRD_NAME " at %#lx", port[i]);
+
+ snd_card_set_dev(card, &device->dev);
+
+ if (snd_card_register(card) < 0) {
+ snd_printk(KERN_ERR DRV_NAME ": could not register card\n");
+ snd_card_free(card);
+ return -EINVAL;
+ }
+
+ platform_set_drvdata(device, card);
+ return 0;
+}
+
+static int __devexit snd_adlib_remove(struct platform_device *device)
+{
+ snd_card_free(platform_get_drvdata(device));
+ platform_set_drvdata(device, NULL);
+ return 0;
+}
+
+static struct platform_driver snd_adlib_driver = {
+ .probe = snd_adlib_probe,
+ .remove = __devexit_p(snd_adlib_remove),
+
+ .driver = {
+ .name = DRV_NAME
+ }
+};
+
+static int __init alsa_card_adlib_init(void)
+{
+ int i, cards;
+
+ if (platform_driver_register(&snd_adlib_driver) < 0) {
+ snd_printk(KERN_ERR DRV_NAME ": could not register driver\n");
+ return -ENODEV;
+ }
+
+ for (cards = 0, i = 0; i < SNDRV_CARDS; i++) {
+ struct platform_device *device;
+
+ if (!enable[i])
+ continue;
+
+ device = platform_device_register_simple(DRV_NAME, i, NULL, 0);
+ if (IS_ERR(device))
+ continue;
+
+ devices[i] = device;
+ cards++;
+ }
+
+ if (!cards) {
+#ifdef MODULE
+ printk(KERN_ERR CRD_NAME " soundcard not found or device busy\n");
+#endif
+ platform_driver_unregister(&snd_adlib_driver);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void __exit alsa_card_adlib_exit(void)
+{
+ int i;
+
+ for (i = 0; i < SNDRV_CARDS; i++)
+ platform_device_unregister(devices[i]);
+ platform_driver_unregister(&snd_adlib_driver);
+}
+
+module_init(alsa_card_adlib_init);
+module_exit(alsa_card_adlib_exit);
Index: local/sound/isa/Kconfig
===================================================================
--- local.orig/sound/isa/Kconfig 2006-03-26 14:58:00.000000000 +0200
+++ local/sound/isa/Kconfig 2006-03-26 14:58:24.000000000 +0200
@@ -11,6 +11,15 @@ config SND_CS4231_LIB
tristate
select SND_PCM

+config SND_ADLIB
+ tristate "AdLib FM card"
+ select SND_OPL3_LIB
+ help
+ Say Y here to include support for AdLib FM cards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-adlib.
+
config SND_AD1816A
tristate "Analog Devices SoundPort AD1816A"
depends on SND && PNP && ISA
Index: local/sound/isa/Makefile
===================================================================
--- local.orig/sound/isa/Makefile 2006-03-26 14:58:00.000000000 +0200
+++ local/sound/isa/Makefile 2006-03-26 14:58:24.000000000 +0200
@@ -3,6 +3,7 @@
# Copyright (c) 2001 by Jaroslav Kysela <[email protected]>
#

+snd-adlib-objs := adlib.o
snd-als100-objs := als100.o
snd-azt2320-objs := azt2320.o
snd-cmi8330-objs := cmi8330.o
@@ -13,6 +14,7 @@ snd-sgalaxy-objs := sgalaxy.o
snd-sscape-objs := sscape.o

# Toplevel Module Dependency
+obj-$(CONFIG_SND_ADLIB) += snd-adlib.o
obj-$(CONFIG_SND_ALS100) += snd-als100.o
obj-$(CONFIG_SND_AZT2320) += snd-azt2320.o
obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o
Index: local/Documentation/sound/alsa/ALSA-Configuration.txt
===================================================================
--- local.orig/Documentation/sound/alsa/ALSA-Configuration.txt 2006-02-27 19:22:00.000000000 +0100
+++ local/Documentation/sound/alsa/ALSA-Configuration.txt 2006-03-26 23:14:06.000000000 +0200
@@ -120,6 +120,34 @@ Prior to version 0.9.0rc4 options had a
enable - enable card
- Default: enabled, for PCI and ISA PnP cards

+ Module snd-adlib
+ ----------------
+
+ Module for AdLib FM cards.
+
+ port - port # for OPL chip
+
+ This module supports multiple cards. It does not support autoprobe, so
+ the port must be specified. For actual AdLib FM cards it will be 0x388.
+ Note that this card does not have PCM support and no mixer; only FM
+ synthesis.
+
+ Make sure you have "sbiload" from the alsa-tools package available and,
+ after loading the module, find out the assigned ALSA sequencer port
+ number through "sbiload -l". Example output:
+
+ Port Client name Port name
+ 64:0 OPL2 FM synth OPL2 FM Port
+
+ Load the std.sb and drums.sb patches also supplied by sbiload:
+
+ sbiload -p 64:0 std.sb drums.sb
+
+ If you use this driver to drive an OPL3, you can use std.o3 and drums.o3
+ instead. To have the card produce sound, use aplaymidi from alsa-utils:
+
+ aplaymidi -p 64:0 foo.mid
+
Module snd-ad1816a
------------------


Attachments:
adlib.diff (6.80 kB)

2006-03-27 08:32:04

by Clemens Ladisch

[permalink] [raw]
Subject: Re: [Alsa-devel] [ALSA] AdLib FM card driver

Rene Herman wrote:
> [...]
> I also stuck a very tiny HOWTO in ALSA-Configuration.txt, assuming quite
> a few people would have no idea how to operate the thing, even if they
> do happen across a card. Is it okay there?

It should probably go into a seperate file below Documentation/.

> + This module supports multiple cards. It does not support autoprobe, so
> + the port must be specified. For actual AdLib FM cards it will be 0x388.

Does it make sense to support more than one card or a non-default port
address? I.e., is there any card using an OPL2/3 that we do not have a
driver for (except the AdLib FM)?

I think at least the port address for the first card should be defaulted
to 0x388.


Regards,
Clemens

2006-03-27 13:15:19

by Rene Herman

[permalink] [raw]
Subject: Re: [Alsa-devel] [ALSA] AdLib FM card driver

Clemens Ladisch wrote:

> Rene Herman wrote:

>> I also stuck a very tiny HOWTO in ALSA-Configuration.txt, assuming
>> quite a few people would have no idea how to operate the thing,
>> even if they do happen across a card. Is it okay there?
>
> It should probably go into a seperate file below Documentation/.

Probably. Documentation/sound/alsa/adlib.txt is ofcourse okay but I saw
a few other remark type things in ALSA-Configuration as well. Seeing as
how it's very small, and given the tendency of Documentation/ to not be
updated alongside code itself, I thought I'd try to get away with just
keeping things in the one file...

>> + This module supports multiple cards. It does not support autoprobe, so
>> + the port must be specified. For actual AdLib FM cards it will be 0x388.
>
> Does it make sense to support more than one card or a non-default port
> address?

Yes. Ofcourse, in a practical sense not many people will desperately
want to have multiple AdLib cards installed in one machine (and mine
doesn't actually have a jumper to set it to a different address; maybe
others do) but this driver could also be used to drive the AdLib part of
a SoundBlaster for example, which would live at 0x220, 0x240, ...

Sure, not many people will want to do _that_ either, but it is most
importantly more effort to not support multiple cards than it is
supporting them. Not so much while writing, but when updating these old,
largely unused, drivers to new infrastructure work you want things to
look as alsa-generic as possible.

The only ALSA ISA card driver that does not support multiple cards is
opti9xx and, sure enough, when changing over to the platform_driver
interface recently, it came out wrong(-ish). I actually offered to
update it to the generic form already a while ago (will be getting
around to that).

> I think at least the port address for the first card should be
> defaulted to 0x388.

No, you never want to autoprobe ISA due to the non-discoverability of
the old non-PnP ISA bus. If you just start poking at addresses you might
touch something sensitive. The generic example of this is screwing over
a Novell NIC and while there are still some ALSA drivers that do ISA
autoprobing (es1688, es18xx, gus, opti9xx, sb8, sb16) this has been
verboten in the tree in general for some time now.

Hardcoding addresses and probing there might be a bit more userfriendly
but people who install an 8-bit ISA AdLib FM in this day and age are
likely not the type to care deeply about userfriendlyness anyway...

Note lastly that the adlib_card OSS driver also needed the address
passed in.

Many thanks for the comments though!

Rene.

2006-03-27 13:45:04

by Takashi Iwai

[permalink] [raw]
Subject: Re: [ALSA] AdLib FM card driver

At Mon, 27 Mar 2006 00:07:29 +0200,
Rene Herman wrote:
>
> Hi Takashi
>
> Adrian: this was one of the cards you listed as having an OSS but not an
> ALSA driver a while ago.
>
> Attached you'll find an ALSA driver for AdLib FM cards. An AdLib card is
> just an OPL2, which was already supported by sound/drivers/opl3, so only
> very minimal bus-glue is needed. The patch applies cleanly to both
> 2.6.16 and 2.6.16-mm1.
>
> The driver has been tested with an actual ancient 8-bit ISA AdLib card
> and works fine. It also works fine for an OPL3 {,emulation} as still
> found on many ISA soundcards but given that AdLib cards don't have their
> own mixer, upping the volume from 0 might be a problem without the card
> driver already loaded and driving the OPL3.
>
> As far as I am concerned, this does not need additional testing and can
> go to alsa-kernel after a review. It's very unlikely that anyone still
> has this ancient card installed anyway. The one I have here was lent to
> me and will be returned shortly, but given the minimal nature of this
> driver, maintenance should not be a problem.
>
> I also stuck a very tiny HOWTO in ALSA-Configuration.txt, assuming quite
> a few people would have no idea how to operate the thing, even if they
> do happen across a card. Is it okay there?

This amount of description should be OK.

> Takashi: As the card->shortname, I use "AdLib FM", which includes a
> space. sound/core/init.c:choose_default_id() goes to lengths to not
> allow this (it turns it into "FM") but when I manually give:
>
> modprobe snd-adlib id="AdLib FM" port=0x388
>
> then the ID is used as is and everything seems fine. I assume that
> either the space check could go or that a passed in ID should be
> subjected to it as well? (that function also deletes all !isalnum's from
> the shortname such as <underscore> which, again, is fine when passed in
> manually).

The space check is there to retrieve the second word from the
shortname, because the length of id string is much shorter. In most
cases, you likely have names like "Vendor DeviceXXXX". Then only
DeviceXXX is extracted. If it matters, pass a string without space in
the shortname field.

> Comments appreciated. I'll go listen to this AdLib render "Master of
> Puppets" again now. Heavens, what fun...

> +static int __devinit snd_adlib_probe(struct platform_device *device)
(snip)
> + card->private_data = request_region(port[i], 4, CRD_NAME);
> + if (!card->private_data) {
> + snd_printk(KERN_ERR DRV_NAME ": could not grab ports\n");
> + snd_card_free(card);
> + return -EINVAL;
> + }

-EBUSY would be more suitable (although it's ignored later).

> + card->private_free = snd_adlib_free;
> +
> + if (snd_opl3_create(card, port[i], port[i] + 2, OPL3_HW_AUTO, 1, &opl3) < 0) {
> + snd_printk(KERN_ERR DRV_NAME ": could not create OPL\n");
> + snd_card_free(card);
> + return -EINVAL;
> + }

Better to keep the original error value?

> +
> + if (snd_opl3_hwdep_new(opl3, 0, 0, NULL) < 0) {
> + snd_printk(KERN_ERR DRV_NAME ": could not create FM\n");
> + snd_card_free(card);
> + return -EINVAL;
> + }

Ditto.

> +
> + strcpy(card->driver, DRV_NAME);
> + strcpy(card->shortname, CRD_NAME);
> + sprintf(card->longname, CRD_NAME " at %#lx", port[i]);
> +
> + snd_card_set_dev(card, &device->dev);
> +
> + if (snd_card_register(card) < 0) {
> + snd_printk(KERN_ERR DRV_NAME ": could not register card\n");
> + snd_card_free(card);
> + return -EINVAL;
> + }

Ditto. Maybe better to have a single error exit with snd_card_free()?


The other parts look good to me.


Takashi

2006-03-27 13:49:17

by Takashi Iwai

[permalink] [raw]
Subject: Re: [Alsa-devel] [ALSA] AdLib FM card driver

At Mon, 27 Mar 2006 15:15:12 +0200,
Rene Herman wrote:
>
> Clemens Ladisch wrote:
>
> > Rene Herman wrote:
>
> >> I also stuck a very tiny HOWTO in ALSA-Configuration.txt, assuming
> >> quite a few people would have no idea how to operate the thing,
> >> even if they do happen across a card. Is it okay there?
> >
> > It should probably go into a seperate file below Documentation/.
>
> Probably. Documentation/sound/alsa/adlib.txt is ofcourse okay but I saw
> a few other remark type things in ALSA-Configuration as well. Seeing as
> how it's very small, and given the tendency of Documentation/ to not be
> updated alongside code itself, I thought I'd try to get away with just
> keeping things in the one file...

Yes, it's not so big, so could be embedded in that file.

> > I think at least the port address for the first card should be
> > defaulted to 0x388.
>
> No, you never want to autoprobe ISA due to the non-discoverability of
> the old non-PnP ISA bus. If you just start poking at addresses you might
> touch something sensitive. The generic example of this is screwing over
> a Novell NIC and while there are still some ALSA drivers that do ISA
> autoprobing (es1688, es18xx, gus, opti9xx, sb8, sb16) this has been
> verboten in the tree in general for some time now.
>
> Hardcoding addresses and probing there might be a bit more userfriendly
> but people who install an 8-bit ISA AdLib FM in this day and age are
> likely not the type to care deeply about userfriendlyness anyway...
>
> Note lastly that the adlib_card OSS driver also needed the address
> passed in.

OK, we'd need an autoprobe if the old system were capable, but it's
not the case.


Takashi

2006-03-27 16:23:51

by Rene Herman

[permalink] [raw]
Subject: Re: [ALSA] AdLib FM card driver

Index: local/sound/isa/adlib.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ local/sound/isa/adlib.c 2006-03-27 17:03:08.000000000 +0200
@@ -0,0 +1,153 @@
+/*
+ * AdLib FM card driver.
+ */
+
+#include <sound/driver.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/opl3.h>
+
+#define CRD_NAME "AdLib FM"
+#define DRV_NAME "snd_adlib"
+
+MODULE_DESCRIPTION(CRD_NAME);
+MODULE_AUTHOR("Rene Herman");
+MODULE_LICENSE("GPL");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
+static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
+module_param_array(port, long, NULL, 0444);
+MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
+
+static struct platform_device *devices[SNDRV_CARDS];
+
+static void snd_adlib_free(struct snd_card *card)
+{
+ release_and_free_resource(card->private_data);
+}
+
+static int __devinit snd_adlib_probe(struct platform_device *device)
+{
+ struct snd_card *card;
+ struct snd_opl3 *opl3;
+
+ int i = device->id;
+
+ if (port[i] == SNDRV_AUTO_PORT) {
+ snd_printk(KERN_ERR DRV_NAME ": please specify port\n");
+ goto out0;
+ }
+
+ card = snd_card_new(index[i], id[i], THIS_MODULE, 0);
+ if (!card) {
+ snd_printk(KERN_ERR DRV_NAME ": could not create card\n");
+ goto out0;
+ }
+
+ card->private_data = request_region(port[i], 4, CRD_NAME);
+ if (!card->private_data) {
+ snd_printk(KERN_ERR DRV_NAME ": could not grab ports\n");
+ goto out1;
+ }
+ card->private_free = snd_adlib_free;
+
+ if (snd_opl3_create(card, port[i], port[i] + 2, OPL3_HW_AUTO, 1, &opl3) < 0) {
+ snd_printk(KERN_ERR DRV_NAME ": could not create OPL\n");
+ goto out1;
+ }
+
+ if (snd_opl3_hwdep_new(opl3, 0, 0, NULL) < 0) {
+ snd_printk(KERN_ERR DRV_NAME ": could not create FM\n");
+ goto out1;
+ }
+
+ strcpy(card->driver, DRV_NAME);
+ strcpy(card->shortname, CRD_NAME);
+ sprintf(card->longname, CRD_NAME " at %#lx", port[i]);
+
+ snd_card_set_dev(card, &device->dev);
+
+ if (snd_card_register(card) < 0) {
+ snd_printk(KERN_ERR DRV_NAME ": could not register card\n");
+ goto out1;
+ }
+
+ platform_set_drvdata(device, card);
+ return 0;
+
+out1: snd_card_free(card);
+out0: return -EINVAL;
+}
+
+static int __devexit snd_adlib_remove(struct platform_device *device)
+{
+ snd_card_free(platform_get_drvdata(device));
+ platform_set_drvdata(device, NULL);
+ return 0;
+}
+
+static struct platform_driver snd_adlib_driver = {
+ .probe = snd_adlib_probe,
+ .remove = __devexit_p(snd_adlib_remove),
+
+ .driver = {
+ .name = DRV_NAME
+ }
+};
+
+static int __init alsa_card_adlib_init(void)
+{
+ int i, cards;
+
+ if (platform_driver_register(&snd_adlib_driver) < 0) {
+ snd_printk(KERN_ERR DRV_NAME ": could not register driver\n");
+ return -ENODEV;
+ }
+
+ for (cards = 0, i = 0; i < SNDRV_CARDS; i++) {
+ struct platform_device *device;
+
+ if (!enable[i])
+ continue;
+
+ device = platform_device_register_simple(DRV_NAME, i, NULL, 0);
+ if (IS_ERR(device))
+ continue;
+
+ devices[i] = device;
+ cards++;
+ }
+
+ if (!cards) {
+#ifdef MODULE
+ printk(KERN_ERR CRD_NAME " soundcard not found or device busy\n");
+#endif
+ platform_driver_unregister(&snd_adlib_driver);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void __exit alsa_card_adlib_exit(void)
+{
+ int i;
+
+ for (i = 0; i < SNDRV_CARDS; i++)
+ platform_device_unregister(devices[i]);
+ platform_driver_unregister(&snd_adlib_driver);
+}
+
+module_init(alsa_card_adlib_init);
+module_exit(alsa_card_adlib_exit);
Index: local/sound/isa/Kconfig
===================================================================
--- local.orig/sound/isa/Kconfig 2006-03-27 16:53:56.000000000 +0200
+++ local/sound/isa/Kconfig 2006-03-27 16:54:25.000000000 +0200
@@ -11,6 +11,15 @@ config SND_CS4231_LIB
tristate
select SND_PCM

+config SND_ADLIB
+ tristate "AdLib FM card"
+ select SND_OPL3_LIB
+ help
+ Say Y here to include support for AdLib FM cards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-adlib.
+
config SND_AD1816A
tristate "Analog Devices SoundPort AD1816A"
depends on SND && PNP && ISA
Index: local/sound/isa/Makefile
===================================================================
--- local.orig/sound/isa/Makefile 2006-03-27 16:53:56.000000000 +0200
+++ local/sound/isa/Makefile 2006-03-27 16:54:25.000000000 +0200
@@ -3,6 +3,7 @@
# Copyright (c) 2001 by Jaroslav Kysela <[email protected]>
#

+snd-adlib-objs := adlib.o
snd-als100-objs := als100.o
snd-azt2320-objs := azt2320.o
snd-cmi8330-objs := cmi8330.o
@@ -13,6 +14,7 @@ snd-sgalaxy-objs := sgalaxy.o
snd-sscape-objs := sscape.o

# Toplevel Module Dependency
+obj-$(CONFIG_SND_ADLIB) += snd-adlib.o
obj-$(CONFIG_SND_ALS100) += snd-als100.o
obj-$(CONFIG_SND_AZT2320) += snd-azt2320.o
obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o
Index: local/Documentation/sound/alsa/ALSA-Configuration.txt
===================================================================
--- local.orig/Documentation/sound/alsa/ALSA-Configuration.txt 2006-03-27 16:53:56.000000000 +0200
+++ local/Documentation/sound/alsa/ALSA-Configuration.txt 2006-03-27 16:54:25.000000000 +0200
@@ -120,6 +120,34 @@ Prior to version 0.9.0rc4 options had a
enable - enable card
- Default: enabled, for PCI and ISA PnP cards

+ Module snd-adlib
+ ----------------
+
+ Module for AdLib FM cards.
+
+ port - port # for OPL chip
+
+ This module supports multiple cards. It does not support autoprobe, so
+ the port must be specified. For actual AdLib FM cards it will be 0x388.
+ Note that this card does not have PCM support and no mixer; only FM
+ synthesis.
+
+ Make sure you have "sbiload" from the alsa-tools package available and,
+ after loading the module, find out the assigned ALSA sequencer port
+ number through "sbiload -l". Example output:
+
+ Port Client name Port name
+ 64:0 OPL2 FM synth OPL2 FM Port
+
+ Load the std.sb and drums.sb patches also supplied by sbiload:
+
+ sbiload -p 64:0 std.sb drums.sb
+
+ If you use this driver to drive an OPL3, you can use std.o3 and drums.o3
+ instead. To have the card produce sound, use aplaymidi from alsa-utils:
+
+ aplaymidi -p 64:0 foo.mid
+
Module snd-ad1816a
------------------


Attachments:
adlib-2.diff (6.73 kB)

2006-03-27 16:29:27

by Rene Herman

[permalink] [raw]
Subject: Re: [ALSA] AdLib FM card driver

Index: local/sound/isa/adlib.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ local/sound/isa/adlib.c 2006-03-27 16:47:21.000000000 +0200
@@ -0,0 +1,163 @@
+/*
+ * AdLib FM card driver.
+ */
+
+#include <sound/driver.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/opl3.h>
+
+#define CRD_NAME "AdLib FM"
+#define DRV_NAME "snd_adlib"
+
+MODULE_DESCRIPTION(CRD_NAME);
+MODULE_AUTHOR("Rene Herman");
+MODULE_LICENSE("GPL");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
+static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
+module_param_array(port, long, NULL, 0444);
+MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
+
+static struct platform_device *devices[SNDRV_CARDS];
+
+static void snd_adlib_free(struct snd_card *card)
+{
+ release_and_free_resource(card->private_data);
+}
+
+static int __devinit snd_adlib_probe(struct platform_device *device)
+{
+ struct snd_card *card;
+ struct snd_opl3 *opl3;
+
+ int error;
+ int i = device->id;
+
+ if (port[i] == SNDRV_AUTO_PORT) {
+ snd_printk(KERN_ERR DRV_NAME ": please specify port\n");
+ error = -EINVAL;
+ goto out0;
+ }
+
+ card = snd_card_new(index[i], id[i], THIS_MODULE, 0);
+ if (!card) {
+ snd_printk(KERN_ERR DRV_NAME ": could not create card\n");
+ error = -EINVAL;
+ goto out0;
+ }
+
+ card->private_data = request_region(port[i], 4, CRD_NAME);
+ if (!card->private_data) {
+ snd_printk(KERN_ERR DRV_NAME ": could not grab ports\n");
+ error = -EBUSY;
+ goto out1;
+ }
+ card->private_free = snd_adlib_free;
+
+ error = snd_opl3_create(card, port[i], port[i] + 2, OPL3_HW_AUTO, 1, &opl3);
+ if (error < 0) {
+ snd_printk(KERN_ERR DRV_NAME ": could not create OPL\n");
+ error = -EINVAL;
+ goto out1;
+ }
+
+ error = snd_opl3_hwdep_new(opl3, 0, 0, NULL);
+ if (error < 0) {
+ snd_printk(KERN_ERR DRV_NAME ": could not create FM\n");
+ error = -EINVAL;
+ goto out1;
+ }
+
+ strcpy(card->driver, DRV_NAME);
+ strcpy(card->shortname, CRD_NAME);
+ sprintf(card->longname, CRD_NAME " at %#lx", port[i]);
+
+ snd_card_set_dev(card, &device->dev);
+
+ error = snd_card_register(card);
+ if (error < 0) {
+ snd_printk(KERN_ERR DRV_NAME ": could not register card\n");
+ error = -EINVAL;
+ goto out1;
+ }
+
+ platform_set_drvdata(device, card);
+ return 0;
+
+out1: snd_card_free(card);
+out0: return error;
+}
+
+static int __devexit snd_adlib_remove(struct platform_device *device)
+{
+ snd_card_free(platform_get_drvdata(device));
+ platform_set_drvdata(device, NULL);
+ return 0;
+}
+
+static struct platform_driver snd_adlib_driver = {
+ .probe = snd_adlib_probe,
+ .remove = __devexit_p(snd_adlib_remove),
+
+ .driver = {
+ .name = DRV_NAME
+ }
+};
+
+static int __init alsa_card_adlib_init(void)
+{
+ int i, cards;
+
+ if (platform_driver_register(&snd_adlib_driver) < 0) {
+ snd_printk(KERN_ERR DRV_NAME ": could not register driver\n");
+ return -ENODEV;
+ }
+
+ for (cards = 0, i = 0; i < SNDRV_CARDS; i++) {
+ struct platform_device *device;
+
+ if (!enable[i])
+ continue;
+
+ device = platform_device_register_simple(DRV_NAME, i, NULL, 0);
+ if (IS_ERR(device))
+ continue;
+
+ devices[i] = device;
+ cards++;
+ }
+
+ if (!cards) {
+#ifdef MODULE
+ printk(KERN_ERR CRD_NAME " soundcard not found or device busy\n");
+#endif
+ platform_driver_unregister(&snd_adlib_driver);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void __exit alsa_card_adlib_exit(void)
+{
+ int i;
+
+ for (i = 0; i < SNDRV_CARDS; i++)
+ platform_device_unregister(devices[i]);
+ platform_driver_unregister(&snd_adlib_driver);
+}
+
+module_init(alsa_card_adlib_init);
+module_exit(alsa_card_adlib_exit);
Index: local/sound/isa/Kconfig
===================================================================
--- local.orig/sound/isa/Kconfig 2006-03-26 14:58:00.000000000 +0200
+++ local/sound/isa/Kconfig 2006-03-26 14:58:24.000000000 +0200
@@ -11,6 +11,15 @@ config SND_CS4231_LIB
tristate
select SND_PCM

+config SND_ADLIB
+ tristate "AdLib FM card"
+ select SND_OPL3_LIB
+ help
+ Say Y here to include support for AdLib FM cards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-adlib.
+
config SND_AD1816A
tristate "Analog Devices SoundPort AD1816A"
depends on SND && PNP && ISA
Index: local/sound/isa/Makefile
===================================================================
--- local.orig/sound/isa/Makefile 2006-03-26 14:58:00.000000000 +0200
+++ local/sound/isa/Makefile 2006-03-26 14:58:24.000000000 +0200
@@ -3,6 +3,7 @@
# Copyright (c) 2001 by Jaroslav Kysela <[email protected]>
#

+snd-adlib-objs := adlib.o
snd-als100-objs := als100.o
snd-azt2320-objs := azt2320.o
snd-cmi8330-objs := cmi8330.o
@@ -13,6 +14,7 @@ snd-sgalaxy-objs := sgalaxy.o
snd-sscape-objs := sscape.o

# Toplevel Module Dependency
+obj-$(CONFIG_SND_ADLIB) += snd-adlib.o
obj-$(CONFIG_SND_ALS100) += snd-als100.o
obj-$(CONFIG_SND_AZT2320) += snd-azt2320.o
obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o
Index: local/Documentation/sound/alsa/ALSA-Configuration.txt
===================================================================
--- local.orig/Documentation/sound/alsa/ALSA-Configuration.txt 2006-02-27 19:22:00.000000000 +0100
+++ local/Documentation/sound/alsa/ALSA-Configuration.txt 2006-03-26 23:14:06.000000000 +0200
@@ -120,6 +120,34 @@ Prior to version 0.9.0rc4 options had a
enable - enable card
- Default: enabled, for PCI and ISA PnP cards

+ Module snd-adlib
+ ----------------
+
+ Module for AdLib FM cards.
+
+ port - port # for OPL chip
+
+ This module supports multiple cards. It does not support autoprobe, so
+ the port must be specified. For actual AdLib FM cards it will be 0x388.
+ Note that this card does not have PCM support and no mixer; only FM
+ synthesis.
+
+ Make sure you have "sbiload" from the alsa-tools package available and,
+ after loading the module, find out the assigned ALSA sequencer port
+ number through "sbiload -l". Example output:
+
+ Port Client name Port name
+ 64:0 OPL2 FM synth OPL2 FM Port
+
+ Load the std.sb and drums.sb patches also supplied by sbiload:
+
+ sbiload -p 64:0 std.sb drums.sb
+
+ If you use this driver to drive an OPL3, you can use std.o3 and drums.o3
+ instead. To have the card produce sound, use aplaymidi from alsa-utils:
+
+ aplaymidi -p 64:0 foo.mid
+
Module snd-ad1816a
------------------


Attachments:
adlib-3.diff (6.91 kB)

2006-03-28 10:49:31

by Takashi Iwai

[permalink] [raw]
Subject: Re: [ALSA] AdLib FM card driver

At Mon, 27 Mar 2006 18:29:24 +0200,
Rene Herman wrote:
>
> Rene Herman wrote:
>
> > Attached is a version that simply jumps to a return -EINVAL, which
> > would also be the easiest way to fixup the others, at least for
> > -stable. If you disagree though, in the next message I'll sent a
> > version that does register the error, but for now just turns them
> > into -EINVAL before returning.
>
> As promised. As said, I prefer the previous one. With this one, it would
> only be a matter of deleting the "error = -EINVAL;" lines again to have
> it propagate the error up after a resolution of that -ENODEV | -ENXIO
> thing, but since the value isn't used anyway...

Thanks, it's now in ALSA CVS tree (with a minor modification, error =
-EINVAL is set just before return). It should be propagated to 2.6.17
soon later.


Takashi