GNU Linux-libre 5.10.217-gnu1
[releases.git] / sound / pci / ymfpci / ymfpci.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  The driver for the Yamaha's DS1/DS1E cards
4  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
5  */
6
7 #include <linux/init.h>
8 #include <linux/pci.h>
9 #include <linux/time.h>
10 #include <linux/module.h>
11 #include <sound/core.h>
12 #include "ymfpci.h"
13 #include <sound/mpu401.h>
14 #include <sound/opl3.h>
15 #include <sound/initval.h>
16
17 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
18 MODULE_DESCRIPTION("Yamaha DS-1 PCI");
19 MODULE_LICENSE("GPL");
20 MODULE_SUPPORTED_DEVICE("{{Yamaha,YMF724},"
21                 "{Yamaha,YMF724F},"
22                 "{Yamaha,YMF740},"
23                 "{Yamaha,YMF740C},"
24                 "{Yamaha,YMF744},"
25                 "{Yamaha,YMF754}}");
26
27 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;      /* Index 0-MAX */
28 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;       /* ID for this card */
29 static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;     /* Enable this card */
30 static long fm_port[SNDRV_CARDS];
31 static long mpu_port[SNDRV_CARDS];
32 #ifdef SUPPORT_JOYSTICK
33 static long joystick_port[SNDRV_CARDS];
34 #endif
35 static bool rear_switch[SNDRV_CARDS];
36
37 module_param_array(index, int, NULL, 0444);
38 MODULE_PARM_DESC(index, "Index value for the Yamaha DS-1 PCI soundcard.");
39 module_param_array(id, charp, NULL, 0444);
40 MODULE_PARM_DESC(id, "ID string for the Yamaha DS-1 PCI soundcard.");
41 module_param_array(enable, bool, NULL, 0444);
42 MODULE_PARM_DESC(enable, "Enable Yamaha DS-1 soundcard.");
43 module_param_hw_array(mpu_port, long, ioport, NULL, 0444);
44 MODULE_PARM_DESC(mpu_port, "MPU-401 Port.");
45 module_param_hw_array(fm_port, long, ioport, NULL, 0444);
46 MODULE_PARM_DESC(fm_port, "FM OPL-3 Port.");
47 #ifdef SUPPORT_JOYSTICK
48 module_param_hw_array(joystick_port, long, ioport, NULL, 0444);
49 MODULE_PARM_DESC(joystick_port, "Joystick port address");
50 #endif
51 module_param_array(rear_switch, bool, NULL, 0444);
52 MODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch");
53
54 static const struct pci_device_id snd_ymfpci_ids[] = {
55         { PCI_VDEVICE(YAMAHA, 0x0004), 0, },   /* YMF724 */
56         { PCI_VDEVICE(YAMAHA, 0x000d), 0, },   /* YMF724F */
57         { PCI_VDEVICE(YAMAHA, 0x000a), 0, },   /* YMF740 */
58         { PCI_VDEVICE(YAMAHA, 0x000c), 0, },   /* YMF740C */
59         { PCI_VDEVICE(YAMAHA, 0x0010), 0, },   /* YMF744 */
60         { PCI_VDEVICE(YAMAHA, 0x0012), 0, },   /* YMF754 */
61         { 0, }
62 };
63
64 MODULE_DEVICE_TABLE(pci, snd_ymfpci_ids);
65
66 #ifdef SUPPORT_JOYSTICK
67 static int snd_ymfpci_create_gameport(struct snd_ymfpci *chip, int dev,
68                                       int legacy_ctrl, int legacy_ctrl2)
69 {
70         struct gameport *gp;
71         struct resource *r = NULL;
72         int io_port = joystick_port[dev];
73
74         if (!io_port)
75                 return -ENODEV;
76
77         if (chip->pci->device >= 0x0010) { /* YMF 744/754 */
78
79                 if (io_port == 1) {
80                         /* auto-detect */
81                         io_port = pci_resource_start(chip->pci, 2);
82                         if (!io_port)
83                                 return -ENODEV;
84                 }
85         } else {
86                 if (io_port == 1) {
87                         /* auto-detect */
88                         for (io_port = 0x201; io_port <= 0x205; io_port++) {
89                                 if (io_port == 0x203)
90                                         continue;
91                                 r = request_region(io_port, 1, "YMFPCI gameport");
92                                 if (r)
93                                         break;
94                         }
95                         if (!r) {
96                                 dev_err(chip->card->dev,
97                                         "no gameport ports available\n");
98                                 return -EBUSY;
99                         }
100                 }
101                 switch (io_port) {
102                 case 0x201: legacy_ctrl2 |= 0 << 6; break;
103                 case 0x202: legacy_ctrl2 |= 1 << 6; break;
104                 case 0x204: legacy_ctrl2 |= 2 << 6; break;
105                 case 0x205: legacy_ctrl2 |= 3 << 6; break;
106                 default:
107                         dev_err(chip->card->dev,
108                                 "invalid joystick port %#x", io_port);
109                         return -EINVAL;
110                 }
111         }
112
113         if (!r) {
114                 r = request_region(io_port, 1, "YMFPCI gameport");
115                 if (!r) {
116                         dev_err(chip->card->dev,
117                                 "joystick port %#x is in use.\n", io_port);
118                         return -EBUSY;
119                 }
120         }
121
122         chip->gameport = gp = gameport_allocate_port();
123         if (!gp) {
124                 dev_err(chip->card->dev,
125                         "cannot allocate memory for gameport\n");
126                 release_and_free_resource(r);
127                 return -ENOMEM;
128         }
129
130
131         gameport_set_name(gp, "Yamaha YMF Gameport");
132         gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));
133         gameport_set_dev_parent(gp, &chip->pci->dev);
134         gp->io = io_port;
135         gameport_set_port_data(gp, r);
136
137         if (chip->pci->device >= 0x0010) /* YMF 744/754 */
138                 pci_write_config_word(chip->pci, PCIR_DSXG_JOYBASE, io_port);
139
140         pci_write_config_word(chip->pci, PCIR_DSXG_LEGACY, legacy_ctrl | YMFPCI_LEGACY_JPEN);
141         pci_write_config_word(chip->pci, PCIR_DSXG_ELEGACY, legacy_ctrl2);
142
143         gameport_register_port(chip->gameport);
144
145         return 0;
146 }
147
148 void snd_ymfpci_free_gameport(struct snd_ymfpci *chip)
149 {
150         if (chip->gameport) {
151                 struct resource *r = gameport_get_port_data(chip->gameport);
152
153                 gameport_unregister_port(chip->gameport);
154                 chip->gameport = NULL;
155
156                 release_and_free_resource(r);
157         }
158 }
159 #else
160 static inline int snd_ymfpci_create_gameport(struct snd_ymfpci *chip, int dev, int l, int l2) { return -ENOSYS; }
161 void snd_ymfpci_free_gameport(struct snd_ymfpci *chip) { }
162 #endif /* SUPPORT_JOYSTICK */
163
164 static int snd_card_ymfpci_probe(struct pci_dev *pci,
165                                  const struct pci_device_id *pci_id)
166 {
167         static int dev;
168         struct snd_card *card;
169         struct resource *fm_res = NULL;
170         struct resource *mpu_res = NULL;
171         struct snd_ymfpci *chip;
172         struct snd_opl3 *opl3;
173         const char *str, *model;
174         int err;
175         u16 legacy_ctrl, legacy_ctrl2, old_legacy_ctrl;
176
177         if (dev >= SNDRV_CARDS)
178                 return -ENODEV;
179         if (!enable[dev]) {
180                 dev++;
181                 return -ENOENT;
182         }
183
184         err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
185                            0, &card);
186         if (err < 0)
187                 return err;
188
189         switch (pci_id->device) {
190         case 0x0004: str = "YMF724";  model = "DS-1"; break;
191         case 0x000d: str = "YMF724F"; model = "DS-1"; break;
192         case 0x000a: str = "YMF740";  model = "DS-1L"; break;
193         case 0x000c: str = "YMF740C"; model = "DS-1L"; break;
194         case 0x0010: str = "YMF744";  model = "DS-1S"; break;
195         case 0x0012: str = "YMF754";  model = "DS-1E"; break;
196         default: model = str = "???"; break;
197         }
198
199         legacy_ctrl = 0;
200         legacy_ctrl2 = 0x0800;  /* SBEN = 0, SMOD = 01, LAD = 0 */
201
202         if (pci_id->device >= 0x0010) { /* YMF 744/754 */
203                 if (fm_port[dev] == 1) {
204                         /* auto-detect */
205                         fm_port[dev] = pci_resource_start(pci, 1);
206                 }
207                 if (fm_port[dev] > 0)
208                         fm_res = request_region(fm_port[dev], 4, "YMFPCI OPL3");
209                 if (fm_res) {
210                         legacy_ctrl |= YMFPCI_LEGACY_FMEN;
211                         pci_write_config_word(pci, PCIR_DSXG_FMBASE, fm_port[dev]);
212                 }
213                 if (mpu_port[dev] == 1) {
214                         /* auto-detect */
215                         mpu_port[dev] = pci_resource_start(pci, 1) + 0x20;
216                 }
217                 if (mpu_port[dev] > 0)
218                         mpu_res = request_region(mpu_port[dev], 2, "YMFPCI MPU401");
219                 if (mpu_res) {
220                         legacy_ctrl |= YMFPCI_LEGACY_MEN;
221                         pci_write_config_word(pci, PCIR_DSXG_MPU401BASE, mpu_port[dev]);
222                 }
223         } else {
224                 switch (fm_port[dev]) {
225                 case 0x388: legacy_ctrl2 |= 0; break;
226                 case 0x398: legacy_ctrl2 |= 1; break;
227                 case 0x3a0: legacy_ctrl2 |= 2; break;
228                 case 0x3a8: legacy_ctrl2 |= 3; break;
229                 default: fm_port[dev] = 0; break;
230                 }
231                 if (fm_port[dev] > 0)
232                         fm_res = request_region(fm_port[dev], 4, "YMFPCI OPL3");
233                 if (fm_res) {
234                         legacy_ctrl |= YMFPCI_LEGACY_FMEN;
235                 } else {
236                         legacy_ctrl2 &= ~YMFPCI_LEGACY2_FMIO;
237                         fm_port[dev] = 0;
238                 }
239                 switch (mpu_port[dev]) {
240                 case 0x330: legacy_ctrl2 |= 0 << 4; break;
241                 case 0x300: legacy_ctrl2 |= 1 << 4; break;
242                 case 0x332: legacy_ctrl2 |= 2 << 4; break;
243                 case 0x334: legacy_ctrl2 |= 3 << 4; break;
244                 default: mpu_port[dev] = 0; break;
245                 }
246                 if (mpu_port[dev] > 0)
247                         mpu_res = request_region(mpu_port[dev], 2, "YMFPCI MPU401");
248                 if (mpu_res) {
249                         legacy_ctrl |= YMFPCI_LEGACY_MEN;
250                 } else {
251                         legacy_ctrl2 &= ~YMFPCI_LEGACY2_MPUIO;
252                         mpu_port[dev] = 0;
253                 }
254         }
255         if (mpu_res) {
256                 legacy_ctrl |= YMFPCI_LEGACY_MIEN;
257                 legacy_ctrl2 |= YMFPCI_LEGACY2_IMOD;
258         }
259         pci_read_config_word(pci, PCIR_DSXG_LEGACY, &old_legacy_ctrl);
260         pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl);
261         pci_write_config_word(pci, PCIR_DSXG_ELEGACY, legacy_ctrl2);
262         err = snd_ymfpci_create(card, pci, old_legacy_ctrl, &chip);
263         if (err  < 0) {
264                 release_and_free_resource(mpu_res);
265                 release_and_free_resource(fm_res);
266                 goto free_card;
267         }
268         chip->fm_res = fm_res;
269         chip->mpu_res = mpu_res;
270         card->private_data = chip;
271
272         strcpy(card->driver, str);
273         sprintf(card->shortname, "Yamaha %s (%s)", model, str);
274         sprintf(card->longname, "%s at 0x%lx, irq %i",
275                 card->shortname,
276                 chip->reg_area_phys,
277                 chip->irq);
278         err = snd_ymfpci_pcm(chip, 0);
279         if (err < 0)
280                 goto free_card;
281
282         err = snd_ymfpci_pcm_spdif(chip, 1);
283         if (err < 0)
284                 goto free_card;
285
286         err = snd_ymfpci_mixer(chip, rear_switch[dev]);
287         if (err < 0)
288                 goto free_card;
289
290         if (chip->ac97->ext_id & AC97_EI_SDAC) {
291                 err = snd_ymfpci_pcm_4ch(chip, 2);
292                 if (err < 0)
293                         goto free_card;
294
295                 err = snd_ymfpci_pcm2(chip, 3);
296                 if (err < 0)
297                         goto free_card;
298         }
299         err = snd_ymfpci_timer(chip, 0);
300         if (err < 0)
301                 goto free_card;
302
303         if (chip->mpu_res) {
304                 err = snd_mpu401_uart_new(card, 0, MPU401_HW_YMFPCI,
305                                           mpu_port[dev],
306                                           MPU401_INFO_INTEGRATED |
307                                           MPU401_INFO_IRQ_HOOK,
308                                           -1, &chip->rawmidi);
309                 if (err < 0) {
310                         dev_warn(card->dev,
311                                  "cannot initialize MPU401 at 0x%lx, skipping...\n",
312                                  mpu_port[dev]);
313                         legacy_ctrl &= ~YMFPCI_LEGACY_MIEN; /* disable MPU401 irq */
314                         pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl);
315                 }
316         }
317         if (chip->fm_res) {
318                 err = snd_opl3_create(card,
319                                       fm_port[dev],
320                                       fm_port[dev] + 2,
321                                       OPL3_HW_OPL3, 1, &opl3);
322                 if (err < 0) {
323                         dev_warn(card->dev,
324                                  "cannot initialize FM OPL3 at 0x%lx, skipping...\n",
325                                  fm_port[dev]);
326                         legacy_ctrl &= ~YMFPCI_LEGACY_FMEN;
327                         pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl);
328                 } else {
329                         err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
330                         if (err < 0) {
331                                 dev_err(card->dev, "cannot create opl3 hwdep\n");
332                                 goto free_card;
333                         }
334                 }
335         }
336
337         snd_ymfpci_create_gameport(chip, dev, legacy_ctrl, legacy_ctrl2);
338
339         err = snd_card_register(card);
340         if (err < 0)
341                 goto free_card;
342
343         pci_set_drvdata(pci, card);
344         dev++;
345         return 0;
346
347 free_card:
348         snd_card_free(card);
349         return err;
350 }
351
352 static void snd_card_ymfpci_remove(struct pci_dev *pci)
353 {
354         snd_card_free(pci_get_drvdata(pci));
355 }
356
357 static struct pci_driver ymfpci_driver = {
358         .name = KBUILD_MODNAME,
359         .id_table = snd_ymfpci_ids,
360         .probe = snd_card_ymfpci_probe,
361         .remove = snd_card_ymfpci_remove,
362 #ifdef CONFIG_PM_SLEEP
363         .driver = {
364                 .pm = &snd_ymfpci_pm,
365         },
366 #endif
367 };
368
369 module_pci_driver(ymfpci_driver);