diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/drivers/mpu401/mpu401.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'sound/drivers/mpu401/mpu401.c')
-rw-r--r-- | sound/drivers/mpu401/mpu401.c | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c new file mode 100644 index 000000000000..cb36ecb78697 --- /dev/null +++ b/sound/drivers/mpu401/mpu401.c | |||
@@ -0,0 +1,229 @@ | |||
1 | /* | ||
2 | * Driver for generic MPU-401 boards (UART mode only) | ||
3 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> | ||
4 | * Copyright (c) 2004 by Castet Matthieu <castet.matthieu@free.fr> | ||
5 | * | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <sound/driver.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/pnp.h> | ||
26 | #include <linux/moduleparam.h> | ||
27 | #include <sound/core.h> | ||
28 | #include <sound/mpu401.h> | ||
29 | #include <sound/initval.h> | ||
30 | |||
31 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); | ||
32 | MODULE_DESCRIPTION("MPU-401 UART"); | ||
33 | MODULE_LICENSE("GPL"); | ||
34 | |||
35 | static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* exclude the first card */ | ||
36 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | ||
37 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ | ||
38 | #ifdef CONFIG_PNP | ||
39 | static int pnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; | ||
40 | #endif | ||
41 | static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* MPU-401 port number */ | ||
42 | static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* MPU-401 IRQ */ | ||
43 | |||
44 | module_param_array(index, int, NULL, 0444); | ||
45 | MODULE_PARM_DESC(index, "Index value for MPU-401 device."); | ||
46 | module_param_array(id, charp, NULL, 0444); | ||
47 | MODULE_PARM_DESC(id, "ID string for MPU-401 device."); | ||
48 | module_param_array(enable, bool, NULL, 0444); | ||
49 | MODULE_PARM_DESC(enable, "Enable MPU-401 device."); | ||
50 | #ifdef CONFIG_PNP | ||
51 | module_param_array(pnp, bool, NULL, 0444); | ||
52 | MODULE_PARM_DESC(pnp, "PnP detection for MPU-401 device."); | ||
53 | #endif | ||
54 | module_param_array(port, long, NULL, 0444); | ||
55 | MODULE_PARM_DESC(port, "Port # for MPU-401 device."); | ||
56 | module_param_array(irq, int, NULL, 0444); | ||
57 | MODULE_PARM_DESC(irq, "IRQ # for MPU-401 device."); | ||
58 | |||
59 | static snd_card_t *snd_mpu401_legacy_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; | ||
60 | static int pnp_registered = 0; | ||
61 | |||
62 | static int snd_mpu401_create(int dev, snd_card_t **rcard) | ||
63 | { | ||
64 | snd_card_t *card; | ||
65 | int err; | ||
66 | |||
67 | *rcard = NULL; | ||
68 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); | ||
69 | if (card == NULL) | ||
70 | return -ENOMEM; | ||
71 | strcpy(card->driver, "MPU-401 UART"); | ||
72 | strcpy(card->shortname, card->driver); | ||
73 | sprintf(card->longname, "%s at %#lx, ", card->shortname, port[dev]); | ||
74 | if (irq[dev] >= 0) { | ||
75 | sprintf(card->longname + strlen(card->longname), "irq %d", irq[dev]); | ||
76 | } else { | ||
77 | strcat(card->longname, "polled"); | ||
78 | } | ||
79 | |||
80 | if (snd_mpu401_uart_new(card, 0, | ||
81 | MPU401_HW_MPU401, | ||
82 | port[dev], 0, | ||
83 | irq[dev], irq[dev] >= 0 ? SA_INTERRUPT : 0, NULL) < 0) { | ||
84 | printk(KERN_ERR "MPU401 not detected at 0x%lx\n", port[dev]); | ||
85 | snd_card_free(card); | ||
86 | return -ENODEV; | ||
87 | } | ||
88 | if ((err = snd_card_register(card)) < 0) { | ||
89 | snd_card_free(card); | ||
90 | return err; | ||
91 | } | ||
92 | *rcard = card; | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int __devinit snd_mpu401_probe(int dev) | ||
97 | { | ||
98 | if (port[dev] == SNDRV_AUTO_PORT) { | ||
99 | snd_printk(KERN_ERR "specify port\n"); | ||
100 | return -EINVAL; | ||
101 | } | ||
102 | if (irq[dev] == SNDRV_AUTO_IRQ) { | ||
103 | snd_printk(KERN_ERR "specify or disable IRQ\n"); | ||
104 | return -EINVAL; | ||
105 | } | ||
106 | return snd_mpu401_create(dev, &snd_mpu401_legacy_cards[dev]); | ||
107 | } | ||
108 | |||
109 | #ifdef CONFIG_PNP | ||
110 | |||
111 | #define IO_EXTENT 2 | ||
112 | |||
113 | static struct pnp_device_id snd_mpu401_pnpids[] = { | ||
114 | { .id = "PNPb006" }, | ||
115 | { .id = "" } | ||
116 | }; | ||
117 | |||
118 | MODULE_DEVICE_TABLE(pnp, snd_mpu401_pnpids); | ||
119 | |||
120 | static int __init snd_mpu401_pnp(int dev, struct pnp_dev *device, | ||
121 | const struct pnp_device_id *id) | ||
122 | { | ||
123 | if (!pnp_port_valid(device, 0) || | ||
124 | pnp_port_flags(device, 0) & IORESOURCE_DISABLED) { | ||
125 | snd_printk(KERN_ERR "no PnP port\n"); | ||
126 | return -ENODEV; | ||
127 | } | ||
128 | if (pnp_port_len(device, 0) < IO_EXTENT) { | ||
129 | snd_printk(KERN_ERR "PnP port length is %ld, expected %d\n", | ||
130 | pnp_port_len(device, 0), IO_EXTENT); | ||
131 | return -ENODEV; | ||
132 | } | ||
133 | port[dev] = pnp_port_start(device, 0); | ||
134 | |||
135 | if (!pnp_irq_valid(device, 0) || | ||
136 | pnp_irq_flags(device, 0) & IORESOURCE_DISABLED) { | ||
137 | snd_printk(KERN_WARNING "no PnP irq, using polling\n"); | ||
138 | irq[dev] = -1; | ||
139 | } else { | ||
140 | irq[dev] = pnp_irq(device, 0); | ||
141 | } | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static int __devinit snd_mpu401_pnp_probe(struct pnp_dev *pnp_dev, | ||
146 | const struct pnp_device_id *id) | ||
147 | { | ||
148 | static int dev; | ||
149 | snd_card_t *card; | ||
150 | int err; | ||
151 | |||
152 | for ( ; dev < SNDRV_CARDS; ++dev) { | ||
153 | if (!enable[dev] || !pnp[dev]) | ||
154 | continue; | ||
155 | err = snd_mpu401_pnp(dev, pnp_dev, id); | ||
156 | if (err < 0) | ||
157 | return err; | ||
158 | err = snd_mpu401_create(dev, &card); | ||
159 | if (err < 0) | ||
160 | return err; | ||
161 | snd_card_set_dev(card, &pnp_dev->dev); | ||
162 | pnp_set_drvdata(pnp_dev, card); | ||
163 | ++dev; | ||
164 | return 0; | ||
165 | } | ||
166 | return -ENODEV; | ||
167 | } | ||
168 | |||
169 | static void __devexit snd_mpu401_pnp_remove(struct pnp_dev *dev) | ||
170 | { | ||
171 | snd_card_t *card = (snd_card_t *) pnp_get_drvdata(dev); | ||
172 | |||
173 | snd_card_disconnect(card); | ||
174 | snd_card_free_in_thread(card); | ||
175 | } | ||
176 | |||
177 | static struct pnp_driver snd_mpu401_pnp_driver = { | ||
178 | .name = "mpu401", | ||
179 | .id_table = snd_mpu401_pnpids, | ||
180 | .probe = snd_mpu401_pnp_probe, | ||
181 | .remove = __devexit_p(snd_mpu401_pnp_remove), | ||
182 | }; | ||
183 | #else | ||
184 | static struct pnp_driver snd_mpu401_pnp_driver; | ||
185 | #endif | ||
186 | |||
187 | static int __init alsa_card_mpu401_init(void) | ||
188 | { | ||
189 | int dev, devices = 0; | ||
190 | int err; | ||
191 | |||
192 | for (dev = 0; dev < SNDRV_CARDS; dev++) { | ||
193 | if (!enable[dev]) | ||
194 | continue; | ||
195 | #ifdef CONFIG_PNP | ||
196 | if (pnp[dev]) | ||
197 | continue; | ||
198 | #endif | ||
199 | if (snd_mpu401_probe(dev) >= 0) | ||
200 | devices++; | ||
201 | } | ||
202 | if ((err = pnp_register_driver(&snd_mpu401_pnp_driver)) >= 0) { | ||
203 | pnp_registered = 1; | ||
204 | devices += err; | ||
205 | } | ||
206 | |||
207 | if (!devices) { | ||
208 | #ifdef MODULE | ||
209 | printk(KERN_ERR "MPU-401 device not found or device busy\n"); | ||
210 | #endif | ||
211 | if (pnp_registered) | ||
212 | pnp_unregister_driver(&snd_mpu401_pnp_driver); | ||
213 | return -ENODEV; | ||
214 | } | ||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static void __exit alsa_card_mpu401_exit(void) | ||
219 | { | ||
220 | int idx; | ||
221 | |||
222 | if (pnp_registered) | ||
223 | pnp_unregister_driver(&snd_mpu401_pnp_driver); | ||
224 | for (idx = 0; idx < SNDRV_CARDS; idx++) | ||
225 | snd_card_free(snd_mpu401_legacy_cards[idx]); | ||
226 | } | ||
227 | |||
228 | module_init(alsa_card_mpu401_init) | ||
229 | module_exit(alsa_card_mpu401_exit) | ||