162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * AdLib FM card driver. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/kernel.h> 762306a36Sopenharmony_ci#include <linux/module.h> 862306a36Sopenharmony_ci#include <linux/isa.h> 962306a36Sopenharmony_ci#include <sound/core.h> 1062306a36Sopenharmony_ci#include <sound/initval.h> 1162306a36Sopenharmony_ci#include <sound/opl3.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define CRD_NAME "AdLib FM" 1462306a36Sopenharmony_ci#define DEV_NAME "adlib" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ciMODULE_DESCRIPTION(CRD_NAME); 1762306a36Sopenharmony_ciMODULE_AUTHOR("Rene Herman"); 1862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; 2162306a36Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; 2262306a36Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; 2362306a36Sopenharmony_cistatic long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cimodule_param_array(index, int, NULL, 0444); 2662306a36Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard."); 2762306a36Sopenharmony_cimodule_param_array(id, charp, NULL, 0444); 2862306a36Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard."); 2962306a36Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444); 3062306a36Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard."); 3162306a36Sopenharmony_cimodule_param_hw_array(port, long, ioport, NULL, 0444); 3262306a36Sopenharmony_ciMODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver."); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic int snd_adlib_match(struct device *dev, unsigned int n) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci if (!enable[n]) 3762306a36Sopenharmony_ci return 0; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (port[n] == SNDRV_AUTO_PORT) { 4062306a36Sopenharmony_ci dev_err(dev, "please specify port\n"); 4162306a36Sopenharmony_ci return 0; 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci return 1; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic int snd_adlib_probe(struct device *dev, unsigned int n) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct snd_card *card; 4962306a36Sopenharmony_ci struct snd_opl3 *opl3; 5062306a36Sopenharmony_ci int error; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci error = snd_devm_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card); 5362306a36Sopenharmony_ci if (error < 0) { 5462306a36Sopenharmony_ci dev_err(dev, "could not create card\n"); 5562306a36Sopenharmony_ci return error; 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci card->private_data = devm_request_region(dev, port[n], 4, CRD_NAME); 5962306a36Sopenharmony_ci if (!card->private_data) { 6062306a36Sopenharmony_ci dev_err(dev, "could not grab ports\n"); 6162306a36Sopenharmony_ci return -EBUSY; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci strcpy(card->driver, DEV_NAME); 6562306a36Sopenharmony_ci strcpy(card->shortname, CRD_NAME); 6662306a36Sopenharmony_ci sprintf(card->longname, CRD_NAME " at %#lx", port[n]); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci error = snd_opl3_create(card, port[n], port[n] + 2, OPL3_HW_AUTO, 1, &opl3); 6962306a36Sopenharmony_ci if (error < 0) { 7062306a36Sopenharmony_ci dev_err(dev, "could not create OPL\n"); 7162306a36Sopenharmony_ci return error; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci error = snd_opl3_hwdep_new(opl3, 0, 0, NULL); 7562306a36Sopenharmony_ci if (error < 0) { 7662306a36Sopenharmony_ci dev_err(dev, "could not create FM\n"); 7762306a36Sopenharmony_ci return error; 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci error = snd_card_register(card); 8162306a36Sopenharmony_ci if (error < 0) { 8262306a36Sopenharmony_ci dev_err(dev, "could not register card\n"); 8362306a36Sopenharmony_ci return error; 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci dev_set_drvdata(dev, card); 8762306a36Sopenharmony_ci return 0; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic struct isa_driver snd_adlib_driver = { 9162306a36Sopenharmony_ci .match = snd_adlib_match, 9262306a36Sopenharmony_ci .probe = snd_adlib_probe, 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci .driver = { 9562306a36Sopenharmony_ci .name = DEV_NAME 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci}; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cimodule_isa_driver(snd_adlib_driver, SNDRV_CARDS); 100