Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | // SPDX-License-Identifier: GPL-2.0-or-later /* * Generic driver for AD1848/AD1847/CS4248 chips (0.1 Alpha) * Copyright (c) by Tugrul Galatali <galatalt@stuy.edu>, * Jaroslav Kysela <perex@perex.cz> * Based on card-4232.c by Jaroslav Kysela <perex@perex.cz> */ #include <linux/init.h> #include <linux/err.h> #include <linux/isa.h> #include <linux/time.h> #include <linux/wait.h> #include <linux/module.h> #include <sound/core.h> #include <sound/wss.h> #include <sound/initval.h> #define CRD_NAME "Generic AD1848/AD1847/CS4248" #define DEV_NAME "ad1848" MODULE_DESCRIPTION(CRD_NAME); MODULE_AUTHOR("Tugrul Galatali <galatalt@stuy.edu>, Jaroslav Kysela <perex@perex.cz>"); MODULE_LICENSE("GPL"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,11,12,15 */ static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */ static bool thinkpad[SNDRV_CARDS]; /* Thinkpad special case */ 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_hw_array(port, long, ioport, NULL, 0444); MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver."); module_param_hw_array(irq, int, irq, NULL, 0444); MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver."); module_param_hw_array(dma1, int, dma, NULL, 0444); MODULE_PARM_DESC(dma1, "DMA1 # for " CRD_NAME " driver."); module_param_array(thinkpad, bool, NULL, 0444); MODULE_PARM_DESC(thinkpad, "Enable only for the onboard CS4248 of IBM Thinkpad 360/750/755 series."); static int snd_ad1848_match(struct device *dev, unsigned int n) { if (!enable[n]) return 0; if (port[n] == SNDRV_AUTO_PORT) { dev_err(dev, "please specify port\n"); return 0; } if (irq[n] == SNDRV_AUTO_IRQ) { dev_err(dev, "please specify irq\n"); return 0; } if (dma1[n] == SNDRV_AUTO_DMA) { dev_err(dev, "please specify dma1\n"); return 0; } return 1; } static int snd_ad1848_probe(struct device *dev, unsigned int n) { struct snd_card *card; struct snd_wss *chip; int error; error = snd_devm_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card); if (error < 0) return error; error = snd_wss_create(card, port[n], -1, irq[n], dma1[n], -1, thinkpad[n] ? WSS_HW_THINKPAD : WSS_HW_DETECT, 0, &chip); if (error < 0) return error; card->private_data = chip; error = snd_wss_pcm(chip, 0); if (error < 0) return error; error = snd_wss_mixer(chip); if (error < 0) return error; strscpy(card->driver, "AD1848", sizeof(card->driver)); strscpy(card->shortname, chip->pcm->name, sizeof(card->shortname)); if (!thinkpad[n]) snprintf(card->longname, sizeof(card->longname), "%s at 0x%lx, irq %d, dma %d", chip->pcm->name, chip->port, irq[n], dma1[n]); else snprintf(card->longname, sizeof(card->longname), "%s at 0x%lx, irq %d, dma %d [Thinkpad]", chip->pcm->name, chip->port, irq[n], dma1[n]); error = snd_card_register(card); if (error < 0) return error; dev_set_drvdata(dev, card); return 0; } #ifdef CONFIG_PM static int snd_ad1848_suspend(struct device *dev, unsigned int n, pm_message_t state) { struct snd_card *card = dev_get_drvdata(dev); struct snd_wss *chip = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); chip->suspend(chip); return 0; } static int snd_ad1848_resume(struct device *dev, unsigned int n) { struct snd_card *card = dev_get_drvdata(dev); struct snd_wss *chip = card->private_data; chip->resume(chip); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } #endif static struct isa_driver snd_ad1848_driver = { .match = snd_ad1848_match, .probe = snd_ad1848_probe, #ifdef CONFIG_PM .suspend = snd_ad1848_suspend, .resume = snd_ad1848_resume, #endif .driver = { .name = DEV_NAME } }; module_isa_driver(snd_ad1848_driver, SNDRV_CARDS); |