]> git.ipfire.org Git - people/ms/linux.git/blame - sound/drivers/mpu401/mpu401.c
treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 156
[people/ms/linux.git] / sound / drivers / mpu401 / mpu401.c
CommitLineData
1a59d1b8 1// SPDX-License-Identifier: GPL-2.0-or-later
1da177e4
LT
2/*
3 * Driver for generic MPU-401 boards (UART mode only)
c1017a4c 4 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
1da177e4 5 * Copyright (c) 2004 by Castet Matthieu <castet.matthieu@free.fr>
1da177e4
LT
6 */
7
1da177e4
LT
8#include <linux/init.h>
9#include <linux/pnp.h>
b3fe9512
TI
10#include <linux/err.h>
11#include <linux/platform_device.h>
65a77217 12#include <linux/module.h>
1da177e4
LT
13#include <sound/core.h>
14#include <sound/mpu401.h>
15#include <sound/initval.h>
16
c1017a4c 17MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
1da177e4
LT
18MODULE_DESCRIPTION("MPU-401 UART");
19MODULE_LICENSE("GPL");
20
21static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* exclude the first card */
22static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
a67ff6a5 23static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
1da177e4 24#ifdef CONFIG_PNP
a67ff6a5 25static bool pnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
1da177e4
LT
26#endif
27static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* MPU-401 port number */
28static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* MPU-401 IRQ */
a67ff6a5 29static bool uart_enter[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
1da177e4
LT
30
31module_param_array(index, int, NULL, 0444);
32MODULE_PARM_DESC(index, "Index value for MPU-401 device.");
33module_param_array(id, charp, NULL, 0444);
34MODULE_PARM_DESC(id, "ID string for MPU-401 device.");
35module_param_array(enable, bool, NULL, 0444);
36MODULE_PARM_DESC(enable, "Enable MPU-401 device.");
37#ifdef CONFIG_PNP
38module_param_array(pnp, bool, NULL, 0444);
39MODULE_PARM_DESC(pnp, "PnP detection for MPU-401 device.");
40#endif
b11ce420 41module_param_hw_array(port, long, ioport, NULL, 0444);
1da177e4 42MODULE_PARM_DESC(port, "Port # for MPU-401 device.");
b11ce420 43module_param_hw_array(irq, int, irq, NULL, 0444);
1da177e4 44MODULE_PARM_DESC(irq, "IRQ # for MPU-401 device.");
8f7ba051
TI
45module_param_array(uart_enter, bool, NULL, 0444);
46MODULE_PARM_DESC(uart_enter, "Issue UART_ENTER command at open.");
1da177e4 47
f7a9275d 48static struct platform_device *platform_devices[SNDRV_CARDS];
f301ae6a
BH
49static int pnp_registered;
50static unsigned int snd_mpu401_devices;
1da177e4 51
5872f3f6
TI
52static int snd_mpu401_create(struct device *devptr, int dev,
53 struct snd_card **rcard)
1da177e4 54{
e1fad17b 55 struct snd_card *card;
1da177e4
LT
56 int err;
57
c1099fcb
CL
58 if (!uart_enter[dev])
59 snd_printk(KERN_ERR "the uart_enter option is obsolete; remove it\n");
60
1da177e4 61 *rcard = NULL;
5872f3f6
TI
62 err = snd_card_new(devptr, index[dev], id[dev], THIS_MODULE,
63 0, &card);
bd7dd77c
TI
64 if (err < 0)
65 return err;
1da177e4
LT
66 strcpy(card->driver, "MPU-401 UART");
67 strcpy(card->shortname, card->driver);
68 sprintf(card->longname, "%s at %#lx, ", card->shortname, port[dev]);
69 if (irq[dev] >= 0) {
70 sprintf(card->longname + strlen(card->longname), "irq %d", irq[dev]);
71 } else {
72 strcat(card->longname, "polled");
73 }
74
c1099fcb 75 err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, port[dev], 0,
dba8b469 76 irq[dev], NULL);
8f7ba051 77 if (err < 0) {
1da177e4 78 printk(KERN_ERR "MPU401 not detected at 0x%lx\n", port[dev]);
16dab54b 79 goto _err;
1da177e4 80 }
16dab54b 81
1da177e4
LT
82 *rcard = card;
83 return 0;
16dab54b
TI
84
85 _err:
86 snd_card_free(card);
87 return err;
1da177e4
LT
88}
89
fbbb01a1 90static int snd_mpu401_probe(struct platform_device *devptr)
1da177e4 91{
b3fe9512
TI
92 int dev = devptr->id;
93 int err;
94 struct snd_card *card;
95
1da177e4
LT
96 if (port[dev] == SNDRV_AUTO_PORT) {
97 snd_printk(KERN_ERR "specify port\n");
98 return -EINVAL;
99 }
100 if (irq[dev] == SNDRV_AUTO_IRQ) {
101 snd_printk(KERN_ERR "specify or disable IRQ\n");
102 return -EINVAL;
103 }
5872f3f6 104 err = snd_mpu401_create(&devptr->dev, dev, &card);
b3fe9512
TI
105 if (err < 0)
106 return err;
b3fe9512
TI
107 if ((err = snd_card_register(card)) < 0) {
108 snd_card_free(card);
109 return err;
110 }
111 platform_set_drvdata(devptr, card);
112 return 0;
1da177e4
LT
113}
114
fbbb01a1 115static int snd_mpu401_remove(struct platform_device *devptr)
b3fe9512
TI
116{
117 snd_card_free(platform_get_drvdata(devptr));
b3fe9512
TI
118 return 0;
119}
120
121#define SND_MPU401_DRIVER "snd_mpu401"
122
123static struct platform_driver snd_mpu401_driver = {
124 .probe = snd_mpu401_probe,
fbbb01a1 125 .remove = snd_mpu401_remove,
b3fe9512 126 .driver = {
8bf01d8a 127 .name = SND_MPU401_DRIVER,
b3fe9512
TI
128 },
129};
130
131
1da177e4
LT
132#ifdef CONFIG_PNP
133
134#define IO_EXTENT 2
135
1491c68a 136static const struct pnp_device_id snd_mpu401_pnpids[] = {
1da177e4
LT
137 { .id = "PNPb006" },
138 { .id = "" }
139};
140
141MODULE_DEVICE_TABLE(pnp, snd_mpu401_pnpids);
142
fbbb01a1
BP
143static int snd_mpu401_pnp(int dev, struct pnp_dev *device,
144 const struct pnp_device_id *id)
1da177e4
LT
145{
146 if (!pnp_port_valid(device, 0) ||
147 pnp_port_flags(device, 0) & IORESOURCE_DISABLED) {
148 snd_printk(KERN_ERR "no PnP port\n");
149 return -ENODEV;
150 }
151 if (pnp_port_len(device, 0) < IO_EXTENT) {
aa0a2ddc
GKH
152 snd_printk(KERN_ERR "PnP port length is %llu, expected %d\n",
153 (unsigned long long)pnp_port_len(device, 0),
154 IO_EXTENT);
1da177e4
LT
155 return -ENODEV;
156 }
157 port[dev] = pnp_port_start(device, 0);
158
159 if (!pnp_irq_valid(device, 0) ||
160 pnp_irq_flags(device, 0) & IORESOURCE_DISABLED) {
161 snd_printk(KERN_WARNING "no PnP irq, using polling\n");
162 irq[dev] = -1;
163 } else {
164 irq[dev] = pnp_irq(device, 0);
165 }
166 return 0;
167}
168
fbbb01a1
BP
169static int snd_mpu401_pnp_probe(struct pnp_dev *pnp_dev,
170 const struct pnp_device_id *id)
1da177e4
LT
171{
172 static int dev;
e1fad17b 173 struct snd_card *card;
1da177e4
LT
174 int err;
175
176 for ( ; dev < SNDRV_CARDS; ++dev) {
177 if (!enable[dev] || !pnp[dev])
178 continue;
179 err = snd_mpu401_pnp(dev, pnp_dev, id);
180 if (err < 0)
181 return err;
5872f3f6 182 err = snd_mpu401_create(&pnp_dev->dev, dev, &card);
1da177e4
LT
183 if (err < 0)
184 return err;
b3fe9512
TI
185 if ((err = snd_card_register(card)) < 0) {
186 snd_card_free(card);
187 return err;
188 }
1da177e4 189 pnp_set_drvdata(pnp_dev, card);
f301ae6a 190 snd_mpu401_devices++;
1da177e4
LT
191 ++dev;
192 return 0;
193 }
194 return -ENODEV;
195}
196
fbbb01a1 197static void snd_mpu401_pnp_remove(struct pnp_dev *dev)
1da177e4 198{
e1fad17b 199 struct snd_card *card = (struct snd_card *) pnp_get_drvdata(dev);
1da177e4
LT
200
201 snd_card_disconnect(card);
2b29b13c 202 snd_card_free_when_closed(card);
1da177e4
LT
203}
204
205static struct pnp_driver snd_mpu401_pnp_driver = {
206 .name = "mpu401",
207 .id_table = snd_mpu401_pnpids,
208 .probe = snd_mpu401_pnp_probe,
fbbb01a1 209 .remove = snd_mpu401_pnp_remove,
1da177e4
LT
210};
211#else
212static struct pnp_driver snd_mpu401_pnp_driver;
213#endif
214
c12aad6e 215static void snd_mpu401_unregister_all(void)
f7a9275d
CL
216{
217 int i;
218
219 if (pnp_registered)
220 pnp_unregister_driver(&snd_mpu401_pnp_driver);
221 for (i = 0; i < ARRAY_SIZE(platform_devices); ++i)
222 platform_device_unregister(platform_devices[i]);
223 platform_driver_unregister(&snd_mpu401_driver);
224}
225
1da177e4
LT
226static int __init alsa_card_mpu401_init(void)
227{
f301ae6a 228 int i, err;
1da177e4 229
b3fe9512
TI
230 if ((err = platform_driver_register(&snd_mpu401_driver)) < 0)
231 return err;
232
8278ca8f 233 for (i = 0; i < SNDRV_CARDS; i++) {
b3fe9512 234 struct platform_device *device;
8278ca8f
TI
235 if (! enable[i])
236 continue;
1da177e4 237#ifdef CONFIG_PNP
b3fe9512 238 if (pnp[i])
1da177e4
LT
239 continue;
240#endif
b3fe9512
TI
241 device = platform_device_register_simple(SND_MPU401_DRIVER,
242 i, NULL, 0);
a182ee98
RH
243 if (IS_ERR(device))
244 continue;
7152447d
RH
245 if (!platform_get_drvdata(device)) {
246 platform_device_unregister(device);
247 continue;
248 }
f7a9275d 249 platform_devices[i] = device;
f301ae6a 250 snd_mpu401_devices++;
1da177e4 251 }
f301ae6a
BH
252 err = pnp_register_driver(&snd_mpu401_pnp_driver);
253 if (!err)
1da177e4 254 pnp_registered = 1;
1da177e4 255
f301ae6a 256 if (!snd_mpu401_devices) {
1da177e4
LT
257#ifdef MODULE
258 printk(KERN_ERR "MPU-401 device not found or device busy\n");
259#endif
a182ee98
RH
260 snd_mpu401_unregister_all();
261 return -ENODEV;
1da177e4
LT
262 }
263 return 0;
264}
265
266static void __exit alsa_card_mpu401_exit(void)
267{
f7a9275d 268 snd_mpu401_unregister_all();
1da177e4
LT
269}
270
271module_init(alsa_card_mpu401_init)
272module_exit(alsa_card_mpu401_exit)