Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/pcmcia/pdaudiocf/pdaudiocf.c
26427 views
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 <[email protected]>
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
22
MODULE_AUTHOR("Jaroslav Kysela <[email protected]>");
23
MODULE_DESCRIPTION("Sound Core " CARD_NAME);
24
MODULE_LICENSE("GPL");
25
26
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
27
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
28
static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable switches */
29
30
module_param_array(index, int, NULL, 0444);
31
MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
32
module_param_array(id, charp, NULL, 0444);
33
MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
34
module_param_array(enable, bool, NULL, 0444);
35
MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
36
37
/*
38
*/
39
40
static struct snd_card *card_list[SNDRV_CARDS];
41
42
/*
43
* prototypes
44
*/
45
static int pdacf_config(struct pcmcia_device *link);
46
static void snd_pdacf_detach(struct pcmcia_device *p_dev);
47
48
static 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
*/
57
static 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
70
static 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
*/
79
static 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
return pdacf_config(link);
135
}
136
137
138
/**
139
* snd_pdacf_assign_resources - initialize the hardware and card instance.
140
* @pdacf: context
141
* @port: i/o port for the card
142
* @irq: irq number for the card
143
*
144
* this function assigns the specified port and irq, boot the card,
145
* create pcm and control instances, and initialize the rest hardware.
146
*
147
* returns 0 if successful, or a negative error code.
148
*/
149
static int snd_pdacf_assign_resources(struct snd_pdacf *pdacf, int port, int irq)
150
{
151
int err;
152
struct snd_card *card = pdacf->card;
153
154
dev_dbg(card->dev, "pdacf assign resources: port = 0x%x, irq = %d\n", port, irq);
155
pdacf->port = port;
156
pdacf->irq = irq;
157
pdacf->chip_status |= PDAUDIOCF_STAT_IS_CONFIGURED;
158
159
err = snd_pdacf_ak4117_create(pdacf);
160
if (err < 0)
161
return err;
162
163
strscpy(card->driver, "PDAudio-CF");
164
sprintf(card->shortname, "Core Sound %s", card->driver);
165
sprintf(card->longname, "%s at 0x%x, irq %i",
166
card->shortname, port, irq);
167
168
err = snd_pdacf_pcm_new(pdacf);
169
if (err < 0)
170
return err;
171
172
err = snd_card_register(card);
173
if (err < 0)
174
return err;
175
176
return 0;
177
}
178
179
180
/*
181
* snd_pdacf_detach - detach callback for cs
182
*/
183
static void snd_pdacf_detach(struct pcmcia_device *link)
184
{
185
struct snd_pdacf *chip = link->priv;
186
187
if (chip->chip_status & PDAUDIOCF_STAT_IS_CONFIGURED)
188
snd_pdacf_powerdown(chip);
189
chip->chip_status |= PDAUDIOCF_STAT_IS_STALE; /* to be sure */
190
snd_card_disconnect(chip->card);
191
snd_card_free_when_closed(chip->card);
192
}
193
194
/*
195
* configuration callback
196
*/
197
198
static int pdacf_config(struct pcmcia_device *link)
199
{
200
struct snd_pdacf *pdacf = link->priv;
201
int ret;
202
203
link->config_index = 0x5;
204
link->config_flags |= CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ;
205
206
ret = pcmcia_request_io(link);
207
if (ret)
208
goto failed_preirq;
209
210
ret = request_threaded_irq(link->irq, pdacf_interrupt,
211
pdacf_threaded_irq,
212
IRQF_SHARED, link->devname, link->priv);
213
if (ret)
214
goto failed_preirq;
215
216
ret = pcmcia_enable_device(link);
217
if (ret)
218
goto failed;
219
220
if (snd_pdacf_assign_resources(pdacf, link->resource[0]->start,
221
link->irq) < 0)
222
goto failed;
223
224
pdacf->card->sync_irq = link->irq;
225
return 0;
226
227
failed:
228
free_irq(link->irq, link->priv);
229
failed_preirq:
230
pcmcia_disable_device(link);
231
return -ENODEV;
232
}
233
234
#ifdef CONFIG_PM
235
236
static int pdacf_suspend(struct pcmcia_device *link)
237
{
238
struct snd_pdacf *chip = link->priv;
239
240
if (chip)
241
snd_pdacf_suspend(chip);
242
243
return 0;
244
}
245
246
static int pdacf_resume(struct pcmcia_device *link)
247
{
248
struct snd_pdacf *chip = link->priv;
249
250
if (pcmcia_dev_present(link)) {
251
if (chip)
252
snd_pdacf_resume(chip);
253
}
254
255
return 0;
256
}
257
258
#endif
259
260
/*
261
* Module entry points
262
*/
263
static const struct pcmcia_device_id snd_pdacf_ids[] = {
264
/* this is too general PCMCIA_DEVICE_MANF_CARD(0x015d, 0x4c45), */
265
PCMCIA_DEVICE_PROD_ID12("Core Sound","PDAudio-CF",0x396d19d2,0x71717b49),
266
PCMCIA_DEVICE_NULL
267
};
268
MODULE_DEVICE_TABLE(pcmcia, snd_pdacf_ids);
269
270
static struct pcmcia_driver pdacf_cs_driver = {
271
.owner = THIS_MODULE,
272
.name = "snd-pdaudiocf",
273
.probe = snd_pdacf_probe,
274
.remove = snd_pdacf_detach,
275
.id_table = snd_pdacf_ids,
276
#ifdef CONFIG_PM
277
.suspend = pdacf_suspend,
278
.resume = pdacf_resume,
279
#endif
280
};
281
module_pcmcia_driver(pdacf_cs_driver);
282
283