^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * AdLib FM card driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/isa.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <sound/initval.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <sound/opl3.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #define CRD_NAME "AdLib FM"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #define DEV_NAME "adlib"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) MODULE_DESCRIPTION(CRD_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) MODULE_AUTHOR("Rene Herman");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) module_param_array(index, int, NULL, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) module_param_array(id, charp, NULL, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) module_param_array(enable, bool, NULL, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) module_param_hw_array(port, long, ioport, NULL, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static int snd_adlib_match(struct device *dev, unsigned int n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) if (!enable[n])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) if (port[n] == SNDRV_AUTO_PORT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) dev_err(dev, "please specify port\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static void snd_adlib_free(struct snd_card *card)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) release_and_free_resource(card->private_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static int snd_adlib_probe(struct device *dev, unsigned int n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct snd_card *card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct snd_opl3 *opl3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) if (error < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) dev_err(dev, "could not create card\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) card->private_data = request_region(port[n], 4, CRD_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (!card->private_data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) dev_err(dev, "could not grab ports\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) error = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) card->private_free = snd_adlib_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) strcpy(card->driver, DEV_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) strcpy(card->shortname, CRD_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) sprintf(card->longname, CRD_NAME " at %#lx", port[n]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) error = snd_opl3_create(card, port[n], port[n] + 2, OPL3_HW_AUTO, 1, &opl3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (error < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) dev_err(dev, "could not create OPL\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) error = snd_opl3_hwdep_new(opl3, 0, 0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (error < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) dev_err(dev, "could not create FM\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) error = snd_card_register(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (error < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) dev_err(dev, "could not register card\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) dev_set_drvdata(dev, card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) out: snd_card_free(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) static int snd_adlib_remove(struct device *dev, unsigned int n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) snd_card_free(dev_get_drvdata(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) static struct isa_driver snd_adlib_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) .match = snd_adlib_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) .probe = snd_adlib_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) .remove = snd_adlib_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) .name = DEV_NAME
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) module_isa_driver(snd_adlib_driver, SNDRV_CARDS);