File Index
Files and directories
Sign in
FILE

pdaudiocf.c

File preview with syntax highlighting.

linux-6.19.14/sound/pcmcia/pdaudiocf/pdaudiocf.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Driver for Sound Core PDAudioCF soundcard
  4 *
  5 * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>
  6 */
  7
  8#include <sound/core.h>
  9#include <linux/slab.h>
 10#include <linux/module.h>
 11#include <pcmcia/ciscode.h>
 12#include <pcmcia/cisreg.h>
 13#include "pdaudiocf.h"
 14#include <sound/initval.h>
 15#include <linux/init.h>
 16
 17/*
 18 */
 19
 20#define CARD_NAME	"PDAudio-CF"
 21
 22MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 23MODULE_DESCRIPTION("Sound Core " CARD_NAME);
 24MODULE_LICENSE("GPL");
 25
 26static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
 27static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 28static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable switches */
 29
 30module_param_array(index, int, NULL, 0444);
 31MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
 32module_param_array(id, charp, NULL, 0444);
 33MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
 34module_param_array(enable, bool, NULL, 0444);
 35MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
 36
 37/*
 38 */
 39
 40static struct snd_card *card_list[SNDRV_CARDS];
 41
 42/*
 43 * prototypes
 44 */
 45static int pdacf_config(struct pcmcia_device *link);
 46static void snd_pdacf_detach(struct pcmcia_device *p_dev);
 47
 48static void pdacf_release(struct pcmcia_device *link)
 49{
 50	free_irq(link->irq, link->priv);
 51	pcmcia_disable_device(link);
 52}
 53
 54/*
 55 * destructor
 56 */
 57static int snd_pdacf_free(struct snd_pdacf *pdacf)
 58{
 59	struct pcmcia_device *link = pdacf->p_dev;
 60
 61	pdacf_release(link);
 62
 63	card_list[pdacf->index] = NULL;
 64	pdacf->card = NULL;
 65
 66	kfree(pdacf);
 67	return 0;
 68}
 69
 70static int snd_pdacf_dev_free(struct snd_device *device)
 71{
 72	struct snd_pdacf *chip = device->device_data;
 73	return snd_pdacf_free(chip);
 74}
 75
 76/*
 77 * snd_pdacf_attach - attach callback for cs
 78 */
 79static int snd_pdacf_probe(struct pcmcia_device *link)
 80{
 81	int i, err;
 82	struct snd_pdacf *pdacf;
 83	struct snd_card *card;
 84	static const struct snd_device_ops ops = {
 85		.dev_free =	snd_pdacf_dev_free,
 86	};
 87
 88	/* find an empty slot from the card list */
 89	for (i = 0; i < SNDRV_CARDS; i++) {
 90		if (! card_list[i])
 91			break;
 92	}
 93	if (i >= SNDRV_CARDS) {
 94		dev_err(&link->dev, "pdacf: too many cards found\n");
 95		return -EINVAL;
 96	}
 97	if (! enable[i])
 98		return -ENODEV; /* disabled explicitly */
 99
100	/* ok, create a card instance */
101	err = snd_card_new(&link->dev, index[i], id[i], THIS_MODULE,
102			   0, &card);
103	if (err < 0) {
104		dev_err(&link->dev, "pdacf: cannot create a card instance\n");
105		return err;
106	}
107
108	pdacf = snd_pdacf_create(card);
109	if (!pdacf) {
110		snd_card_free(card);
111		return -ENOMEM;
112	}
113
114	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, pdacf, &ops);
115	if (err < 0) {
116		kfree(pdacf);
117		snd_card_free(card);
118		return err;
119	}
120
121	pdacf->index = i;
122	card_list[i] = card;
123
124	pdacf->p_dev = link;
125	link->priv = pdacf;
126
127	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
128	link->resource[0]->end = 16;
129
130	link->config_flags = CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ;
131	link->config_index = 1;
132	link->config_regs = PRESENT_OPTION;
133
134	err = pdacf_config(link);
135	if (err < 0) {
136		card_list[i] = NULL;
137		snd_card_free(card);
138		return err;
139	}
140	return 0;
141}
142
143
144/**
145 * snd_pdacf_assign_resources - initialize the hardware and card instance.
146 * @pdacf: context
147 * @port: i/o port for the card
148 * @irq: irq number for the card
149 *
150 * this function assigns the specified port and irq, boot the card,
151 * create pcm and control instances, and initialize the rest hardware.
152 *
153 * returns 0 if successful, or a negative error code.
154 */
155static int snd_pdacf_assign_resources(struct snd_pdacf *pdacf, int port, int irq)
156{
157	int err;
158	struct snd_card *card = pdacf->card;
159
160	dev_dbg(card->dev, "pdacf assign resources: port = 0x%x, irq = %d\n", port, irq);
161	pdacf->port = port;
162	pdacf->irq = irq;
163	pdacf->chip_status |= PDAUDIOCF_STAT_IS_CONFIGURED;
164
165	err = snd_pdacf_ak4117_create(pdacf);
166	if (err < 0)
167		return err;	
168
169	strscpy(card->driver, "PDAudio-CF");
170	sprintf(card->shortname, "Core Sound %s", card->driver);
171	sprintf(card->longname, "%s at 0x%x, irq %i",
172		card->shortname, port, irq);
173
174	err = snd_pdacf_pcm_new(pdacf);
175	if (err < 0)
176		return err;
177
178	err = snd_card_register(card);
179	if (err < 0)
180		return err;
181
182	return 0;
183}
184
185
186/*
187 * snd_pdacf_detach - detach callback for cs
188 */
189static void snd_pdacf_detach(struct pcmcia_device *link)
190{
191	struct snd_pdacf *chip = link->priv;
192
193	if (chip->chip_status & PDAUDIOCF_STAT_IS_CONFIGURED)
194		snd_pdacf_powerdown(chip);
195	chip->chip_status |= PDAUDIOCF_STAT_IS_STALE; /* to be sure */
196	snd_card_disconnect(chip->card);
197	snd_card_free_when_closed(chip->card);
198}
199
200/*
201 * configuration callback
202 */
203
204static int pdacf_config(struct pcmcia_device *link)
205{
206	struct snd_pdacf *pdacf = link->priv;
207	int ret;
208
209	link->config_index = 0x5;
210	link->config_flags |= CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ;
211
212	ret = pcmcia_request_io(link);
213	if (ret)
214		goto failed_preirq;
215
216	ret = request_threaded_irq(link->irq, pdacf_interrupt,
217				   pdacf_threaded_irq,
218				   IRQF_SHARED, link->devname, link->priv);
219	if (ret)
220		goto failed_preirq;
221
222	ret = pcmcia_enable_device(link);
223	if (ret)
224		goto failed;
225
226	if (snd_pdacf_assign_resources(pdacf, link->resource[0]->start,
227					link->irq) < 0)
228		goto failed;
229
230	pdacf->card->sync_irq = link->irq;
231	return 0;
232
233 failed:
234	free_irq(link->irq, link->priv);
235failed_preirq:
236	pcmcia_disable_device(link);
237	return -ENODEV;
238}
239
240#ifdef CONFIG_PM
241
242static int pdacf_suspend(struct pcmcia_device *link)
243{
244	struct snd_pdacf *chip = link->priv;
245
246	if (chip)
247		snd_pdacf_suspend(chip);
248
249	return 0;
250}
251
252static int pdacf_resume(struct pcmcia_device *link)
253{
254	struct snd_pdacf *chip = link->priv;
255
256	if (pcmcia_dev_present(link)) {
257		if (chip)
258			snd_pdacf_resume(chip);
259	}
260
261	return 0;
262}
263
264#endif
265
266/*
267 * Module entry points
268 */
269static const struct pcmcia_device_id snd_pdacf_ids[] = {
270	/* this is too general PCMCIA_DEVICE_MANF_CARD(0x015d, 0x4c45), */
271	PCMCIA_DEVICE_PROD_ID12("Core Sound","PDAudio-CF",0x396d19d2,0x71717b49),
272	PCMCIA_DEVICE_NULL
273};
274MODULE_DEVICE_TABLE(pcmcia, snd_pdacf_ids);
275
276static struct pcmcia_driver pdacf_cs_driver = {
277	.owner		= THIS_MODULE,
278	.name		= "snd-pdaudiocf",
279	.probe		= snd_pdacf_probe,
280	.remove		= snd_pdacf_detach,
281	.id_table	= snd_pdacf_ids,
282#ifdef CONFIG_PM
283	.suspend	= pdacf_suspend,
284	.resume		= pdacf_resume,
285#endif
286};
287module_pcmcia_driver(pdacf_cs_driver);
~/ Read-only file preview.