18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * The driver for the Yamaha's DS1/DS1E cards 48c2ecf20Sopenharmony_ci * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/init.h> 88c2ecf20Sopenharmony_ci#include <linux/pci.h> 98c2ecf20Sopenharmony_ci#include <linux/time.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <sound/core.h> 128c2ecf20Sopenharmony_ci#include "ymfpci.h" 138c2ecf20Sopenharmony_ci#include <sound/mpu401.h> 148c2ecf20Sopenharmony_ci#include <sound/opl3.h> 158c2ecf20Sopenharmony_ci#include <sound/initval.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 188c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Yamaha DS-1 PCI"); 198c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 208c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("{{Yamaha,YMF724}," 218c2ecf20Sopenharmony_ci "{Yamaha,YMF724F}," 228c2ecf20Sopenharmony_ci "{Yamaha,YMF740}," 238c2ecf20Sopenharmony_ci "{Yamaha,YMF740C}," 248c2ecf20Sopenharmony_ci "{Yamaha,YMF744}," 258c2ecf20Sopenharmony_ci "{Yamaha,YMF754}}"); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 288c2ecf20Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 298c2ecf20Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ 308c2ecf20Sopenharmony_cistatic long fm_port[SNDRV_CARDS]; 318c2ecf20Sopenharmony_cistatic long mpu_port[SNDRV_CARDS]; 328c2ecf20Sopenharmony_ci#ifdef SUPPORT_JOYSTICK 338c2ecf20Sopenharmony_cistatic long joystick_port[SNDRV_CARDS]; 348c2ecf20Sopenharmony_ci#endif 358c2ecf20Sopenharmony_cistatic bool rear_switch[SNDRV_CARDS]; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cimodule_param_array(index, int, NULL, 0444); 388c2ecf20Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for the Yamaha DS-1 PCI soundcard."); 398c2ecf20Sopenharmony_cimodule_param_array(id, charp, NULL, 0444); 408c2ecf20Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for the Yamaha DS-1 PCI soundcard."); 418c2ecf20Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444); 428c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable Yamaha DS-1 soundcard."); 438c2ecf20Sopenharmony_cimodule_param_hw_array(mpu_port, long, ioport, NULL, 0444); 448c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mpu_port, "MPU-401 Port."); 458c2ecf20Sopenharmony_cimodule_param_hw_array(fm_port, long, ioport, NULL, 0444); 468c2ecf20Sopenharmony_ciMODULE_PARM_DESC(fm_port, "FM OPL-3 Port."); 478c2ecf20Sopenharmony_ci#ifdef SUPPORT_JOYSTICK 488c2ecf20Sopenharmony_cimodule_param_hw_array(joystick_port, long, ioport, NULL, 0444); 498c2ecf20Sopenharmony_ciMODULE_PARM_DESC(joystick_port, "Joystick port address"); 508c2ecf20Sopenharmony_ci#endif 518c2ecf20Sopenharmony_cimodule_param_array(rear_switch, bool, NULL, 0444); 528c2ecf20Sopenharmony_ciMODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch"); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic const struct pci_device_id snd_ymfpci_ids[] = { 558c2ecf20Sopenharmony_ci { PCI_VDEVICE(YAMAHA, 0x0004), 0, }, /* YMF724 */ 568c2ecf20Sopenharmony_ci { PCI_VDEVICE(YAMAHA, 0x000d), 0, }, /* YMF724F */ 578c2ecf20Sopenharmony_ci { PCI_VDEVICE(YAMAHA, 0x000a), 0, }, /* YMF740 */ 588c2ecf20Sopenharmony_ci { PCI_VDEVICE(YAMAHA, 0x000c), 0, }, /* YMF740C */ 598c2ecf20Sopenharmony_ci { PCI_VDEVICE(YAMAHA, 0x0010), 0, }, /* YMF744 */ 608c2ecf20Sopenharmony_ci { PCI_VDEVICE(YAMAHA, 0x0012), 0, }, /* YMF754 */ 618c2ecf20Sopenharmony_ci { 0, } 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, snd_ymfpci_ids); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#ifdef SUPPORT_JOYSTICK 678c2ecf20Sopenharmony_cistatic int snd_ymfpci_create_gameport(struct snd_ymfpci *chip, int dev, 688c2ecf20Sopenharmony_ci int legacy_ctrl, int legacy_ctrl2) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct gameport *gp; 718c2ecf20Sopenharmony_ci struct resource *r = NULL; 728c2ecf20Sopenharmony_ci int io_port = joystick_port[dev]; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (!io_port) 758c2ecf20Sopenharmony_ci return -ENODEV; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (chip->pci->device >= 0x0010) { /* YMF 744/754 */ 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (io_port == 1) { 808c2ecf20Sopenharmony_ci /* auto-detect */ 818c2ecf20Sopenharmony_ci io_port = pci_resource_start(chip->pci, 2); 828c2ecf20Sopenharmony_ci if (!io_port) 838c2ecf20Sopenharmony_ci return -ENODEV; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci } else { 868c2ecf20Sopenharmony_ci if (io_port == 1) { 878c2ecf20Sopenharmony_ci /* auto-detect */ 888c2ecf20Sopenharmony_ci for (io_port = 0x201; io_port <= 0x205; io_port++) { 898c2ecf20Sopenharmony_ci if (io_port == 0x203) 908c2ecf20Sopenharmony_ci continue; 918c2ecf20Sopenharmony_ci r = request_region(io_port, 1, "YMFPCI gameport"); 928c2ecf20Sopenharmony_ci if (r) 938c2ecf20Sopenharmony_ci break; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci if (!r) { 968c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 978c2ecf20Sopenharmony_ci "no gameport ports available\n"); 988c2ecf20Sopenharmony_ci return -EBUSY; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci switch (io_port) { 1028c2ecf20Sopenharmony_ci case 0x201: legacy_ctrl2 |= 0 << 6; break; 1038c2ecf20Sopenharmony_ci case 0x202: legacy_ctrl2 |= 1 << 6; break; 1048c2ecf20Sopenharmony_ci case 0x204: legacy_ctrl2 |= 2 << 6; break; 1058c2ecf20Sopenharmony_ci case 0x205: legacy_ctrl2 |= 3 << 6; break; 1068c2ecf20Sopenharmony_ci default: 1078c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 1088c2ecf20Sopenharmony_ci "invalid joystick port %#x", io_port); 1098c2ecf20Sopenharmony_ci return -EINVAL; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (!r) { 1148c2ecf20Sopenharmony_ci r = request_region(io_port, 1, "YMFPCI gameport"); 1158c2ecf20Sopenharmony_ci if (!r) { 1168c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 1178c2ecf20Sopenharmony_ci "joystick port %#x is in use.\n", io_port); 1188c2ecf20Sopenharmony_ci return -EBUSY; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci chip->gameport = gp = gameport_allocate_port(); 1238c2ecf20Sopenharmony_ci if (!gp) { 1248c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 1258c2ecf20Sopenharmony_ci "cannot allocate memory for gameport\n"); 1268c2ecf20Sopenharmony_ci release_and_free_resource(r); 1278c2ecf20Sopenharmony_ci return -ENOMEM; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci gameport_set_name(gp, "Yamaha YMF Gameport"); 1328c2ecf20Sopenharmony_ci gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci)); 1338c2ecf20Sopenharmony_ci gameport_set_dev_parent(gp, &chip->pci->dev); 1348c2ecf20Sopenharmony_ci gp->io = io_port; 1358c2ecf20Sopenharmony_ci gameport_set_port_data(gp, r); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (chip->pci->device >= 0x0010) /* YMF 744/754 */ 1388c2ecf20Sopenharmony_ci pci_write_config_word(chip->pci, PCIR_DSXG_JOYBASE, io_port); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci pci_write_config_word(chip->pci, PCIR_DSXG_LEGACY, legacy_ctrl | YMFPCI_LEGACY_JPEN); 1418c2ecf20Sopenharmony_ci pci_write_config_word(chip->pci, PCIR_DSXG_ELEGACY, legacy_ctrl2); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci gameport_register_port(chip->gameport); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci return 0; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_civoid snd_ymfpci_free_gameport(struct snd_ymfpci *chip) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci if (chip->gameport) { 1518c2ecf20Sopenharmony_ci struct resource *r = gameport_get_port_data(chip->gameport); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci gameport_unregister_port(chip->gameport); 1548c2ecf20Sopenharmony_ci chip->gameport = NULL; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci release_and_free_resource(r); 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci#else 1608c2ecf20Sopenharmony_cistatic inline int snd_ymfpci_create_gameport(struct snd_ymfpci *chip, int dev, int l, int l2) { return -ENOSYS; } 1618c2ecf20Sopenharmony_civoid snd_ymfpci_free_gameport(struct snd_ymfpci *chip) { } 1628c2ecf20Sopenharmony_ci#endif /* SUPPORT_JOYSTICK */ 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int snd_card_ymfpci_probe(struct pci_dev *pci, 1658c2ecf20Sopenharmony_ci const struct pci_device_id *pci_id) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci static int dev; 1688c2ecf20Sopenharmony_ci struct snd_card *card; 1698c2ecf20Sopenharmony_ci struct resource *fm_res = NULL; 1708c2ecf20Sopenharmony_ci struct resource *mpu_res = NULL; 1718c2ecf20Sopenharmony_ci struct snd_ymfpci *chip; 1728c2ecf20Sopenharmony_ci struct snd_opl3 *opl3; 1738c2ecf20Sopenharmony_ci const char *str, *model; 1748c2ecf20Sopenharmony_ci int err; 1758c2ecf20Sopenharmony_ci u16 legacy_ctrl, legacy_ctrl2, old_legacy_ctrl; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (dev >= SNDRV_CARDS) 1788c2ecf20Sopenharmony_ci return -ENODEV; 1798c2ecf20Sopenharmony_ci if (!enable[dev]) { 1808c2ecf20Sopenharmony_ci dev++; 1818c2ecf20Sopenharmony_ci return -ENOENT; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, 1858c2ecf20Sopenharmony_ci 0, &card); 1868c2ecf20Sopenharmony_ci if (err < 0) 1878c2ecf20Sopenharmony_ci return err; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci switch (pci_id->device) { 1908c2ecf20Sopenharmony_ci case 0x0004: str = "YMF724"; model = "DS-1"; break; 1918c2ecf20Sopenharmony_ci case 0x000d: str = "YMF724F"; model = "DS-1"; break; 1928c2ecf20Sopenharmony_ci case 0x000a: str = "YMF740"; model = "DS-1L"; break; 1938c2ecf20Sopenharmony_ci case 0x000c: str = "YMF740C"; model = "DS-1L"; break; 1948c2ecf20Sopenharmony_ci case 0x0010: str = "YMF744"; model = "DS-1S"; break; 1958c2ecf20Sopenharmony_ci case 0x0012: str = "YMF754"; model = "DS-1E"; break; 1968c2ecf20Sopenharmony_ci default: model = str = "???"; break; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci legacy_ctrl = 0; 2008c2ecf20Sopenharmony_ci legacy_ctrl2 = 0x0800; /* SBEN = 0, SMOD = 01, LAD = 0 */ 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if (pci_id->device >= 0x0010) { /* YMF 744/754 */ 2038c2ecf20Sopenharmony_ci if (fm_port[dev] == 1) { 2048c2ecf20Sopenharmony_ci /* auto-detect */ 2058c2ecf20Sopenharmony_ci fm_port[dev] = pci_resource_start(pci, 1); 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci if (fm_port[dev] > 0) 2088c2ecf20Sopenharmony_ci fm_res = request_region(fm_port[dev], 4, "YMFPCI OPL3"); 2098c2ecf20Sopenharmony_ci if (fm_res) { 2108c2ecf20Sopenharmony_ci legacy_ctrl |= YMFPCI_LEGACY_FMEN; 2118c2ecf20Sopenharmony_ci pci_write_config_word(pci, PCIR_DSXG_FMBASE, fm_port[dev]); 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci if (mpu_port[dev] == 1) { 2148c2ecf20Sopenharmony_ci /* auto-detect */ 2158c2ecf20Sopenharmony_ci mpu_port[dev] = pci_resource_start(pci, 1) + 0x20; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci if (mpu_port[dev] > 0) 2188c2ecf20Sopenharmony_ci mpu_res = request_region(mpu_port[dev], 2, "YMFPCI MPU401"); 2198c2ecf20Sopenharmony_ci if (mpu_res) { 2208c2ecf20Sopenharmony_ci legacy_ctrl |= YMFPCI_LEGACY_MEN; 2218c2ecf20Sopenharmony_ci pci_write_config_word(pci, PCIR_DSXG_MPU401BASE, mpu_port[dev]); 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci } else { 2248c2ecf20Sopenharmony_ci switch (fm_port[dev]) { 2258c2ecf20Sopenharmony_ci case 0x388: legacy_ctrl2 |= 0; break; 2268c2ecf20Sopenharmony_ci case 0x398: legacy_ctrl2 |= 1; break; 2278c2ecf20Sopenharmony_ci case 0x3a0: legacy_ctrl2 |= 2; break; 2288c2ecf20Sopenharmony_ci case 0x3a8: legacy_ctrl2 |= 3; break; 2298c2ecf20Sopenharmony_ci default: fm_port[dev] = 0; break; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci if (fm_port[dev] > 0) 2328c2ecf20Sopenharmony_ci fm_res = request_region(fm_port[dev], 4, "YMFPCI OPL3"); 2338c2ecf20Sopenharmony_ci if (fm_res) { 2348c2ecf20Sopenharmony_ci legacy_ctrl |= YMFPCI_LEGACY_FMEN; 2358c2ecf20Sopenharmony_ci } else { 2368c2ecf20Sopenharmony_ci legacy_ctrl2 &= ~YMFPCI_LEGACY2_FMIO; 2378c2ecf20Sopenharmony_ci fm_port[dev] = 0; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci switch (mpu_port[dev]) { 2408c2ecf20Sopenharmony_ci case 0x330: legacy_ctrl2 |= 0 << 4; break; 2418c2ecf20Sopenharmony_ci case 0x300: legacy_ctrl2 |= 1 << 4; break; 2428c2ecf20Sopenharmony_ci case 0x332: legacy_ctrl2 |= 2 << 4; break; 2438c2ecf20Sopenharmony_ci case 0x334: legacy_ctrl2 |= 3 << 4; break; 2448c2ecf20Sopenharmony_ci default: mpu_port[dev] = 0; break; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci if (mpu_port[dev] > 0) 2478c2ecf20Sopenharmony_ci mpu_res = request_region(mpu_port[dev], 2, "YMFPCI MPU401"); 2488c2ecf20Sopenharmony_ci if (mpu_res) { 2498c2ecf20Sopenharmony_ci legacy_ctrl |= YMFPCI_LEGACY_MEN; 2508c2ecf20Sopenharmony_ci } else { 2518c2ecf20Sopenharmony_ci legacy_ctrl2 &= ~YMFPCI_LEGACY2_MPUIO; 2528c2ecf20Sopenharmony_ci mpu_port[dev] = 0; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci if (mpu_res) { 2568c2ecf20Sopenharmony_ci legacy_ctrl |= YMFPCI_LEGACY_MIEN; 2578c2ecf20Sopenharmony_ci legacy_ctrl2 |= YMFPCI_LEGACY2_IMOD; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci pci_read_config_word(pci, PCIR_DSXG_LEGACY, &old_legacy_ctrl); 2608c2ecf20Sopenharmony_ci pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl); 2618c2ecf20Sopenharmony_ci pci_write_config_word(pci, PCIR_DSXG_ELEGACY, legacy_ctrl2); 2628c2ecf20Sopenharmony_ci err = snd_ymfpci_create(card, pci, old_legacy_ctrl, &chip); 2638c2ecf20Sopenharmony_ci if (err < 0) { 2648c2ecf20Sopenharmony_ci release_and_free_resource(mpu_res); 2658c2ecf20Sopenharmony_ci release_and_free_resource(fm_res); 2668c2ecf20Sopenharmony_ci goto free_card; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci chip->fm_res = fm_res; 2698c2ecf20Sopenharmony_ci chip->mpu_res = mpu_res; 2708c2ecf20Sopenharmony_ci card->private_data = chip; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci strcpy(card->driver, str); 2738c2ecf20Sopenharmony_ci sprintf(card->shortname, "Yamaha %s (%s)", model, str); 2748c2ecf20Sopenharmony_ci sprintf(card->longname, "%s at 0x%lx, irq %i", 2758c2ecf20Sopenharmony_ci card->shortname, 2768c2ecf20Sopenharmony_ci chip->reg_area_phys, 2778c2ecf20Sopenharmony_ci chip->irq); 2788c2ecf20Sopenharmony_ci err = snd_ymfpci_pcm(chip, 0); 2798c2ecf20Sopenharmony_ci if (err < 0) 2808c2ecf20Sopenharmony_ci goto free_card; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci err = snd_ymfpci_pcm_spdif(chip, 1); 2838c2ecf20Sopenharmony_ci if (err < 0) 2848c2ecf20Sopenharmony_ci goto free_card; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci err = snd_ymfpci_mixer(chip, rear_switch[dev]); 2878c2ecf20Sopenharmony_ci if (err < 0) 2888c2ecf20Sopenharmony_ci goto free_card; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (chip->ac97->ext_id & AC97_EI_SDAC) { 2918c2ecf20Sopenharmony_ci err = snd_ymfpci_pcm_4ch(chip, 2); 2928c2ecf20Sopenharmony_ci if (err < 0) 2938c2ecf20Sopenharmony_ci goto free_card; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci err = snd_ymfpci_pcm2(chip, 3); 2968c2ecf20Sopenharmony_ci if (err < 0) 2978c2ecf20Sopenharmony_ci goto free_card; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci err = snd_ymfpci_timer(chip, 0); 3008c2ecf20Sopenharmony_ci if (err < 0) 3018c2ecf20Sopenharmony_ci goto free_card; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (chip->mpu_res) { 3048c2ecf20Sopenharmony_ci err = snd_mpu401_uart_new(card, 0, MPU401_HW_YMFPCI, 3058c2ecf20Sopenharmony_ci mpu_port[dev], 3068c2ecf20Sopenharmony_ci MPU401_INFO_INTEGRATED | 3078c2ecf20Sopenharmony_ci MPU401_INFO_IRQ_HOOK, 3088c2ecf20Sopenharmony_ci -1, &chip->rawmidi); 3098c2ecf20Sopenharmony_ci if (err < 0) { 3108c2ecf20Sopenharmony_ci dev_warn(card->dev, 3118c2ecf20Sopenharmony_ci "cannot initialize MPU401 at 0x%lx, skipping...\n", 3128c2ecf20Sopenharmony_ci mpu_port[dev]); 3138c2ecf20Sopenharmony_ci legacy_ctrl &= ~YMFPCI_LEGACY_MIEN; /* disable MPU401 irq */ 3148c2ecf20Sopenharmony_ci pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl); 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci if (chip->fm_res) { 3188c2ecf20Sopenharmony_ci err = snd_opl3_create(card, 3198c2ecf20Sopenharmony_ci fm_port[dev], 3208c2ecf20Sopenharmony_ci fm_port[dev] + 2, 3218c2ecf20Sopenharmony_ci OPL3_HW_OPL3, 1, &opl3); 3228c2ecf20Sopenharmony_ci if (err < 0) { 3238c2ecf20Sopenharmony_ci dev_warn(card->dev, 3248c2ecf20Sopenharmony_ci "cannot initialize FM OPL3 at 0x%lx, skipping...\n", 3258c2ecf20Sopenharmony_ci fm_port[dev]); 3268c2ecf20Sopenharmony_ci legacy_ctrl &= ~YMFPCI_LEGACY_FMEN; 3278c2ecf20Sopenharmony_ci pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl); 3288c2ecf20Sopenharmony_ci } else { 3298c2ecf20Sopenharmony_ci err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); 3308c2ecf20Sopenharmony_ci if (err < 0) { 3318c2ecf20Sopenharmony_ci dev_err(card->dev, "cannot create opl3 hwdep\n"); 3328c2ecf20Sopenharmony_ci goto free_card; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci snd_ymfpci_create_gameport(chip, dev, legacy_ctrl, legacy_ctrl2); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci err = snd_card_register(card); 3408c2ecf20Sopenharmony_ci if (err < 0) 3418c2ecf20Sopenharmony_ci goto free_card; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci pci_set_drvdata(pci, card); 3448c2ecf20Sopenharmony_ci dev++; 3458c2ecf20Sopenharmony_ci return 0; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cifree_card: 3488c2ecf20Sopenharmony_ci snd_card_free(card); 3498c2ecf20Sopenharmony_ci return err; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic void snd_card_ymfpci_remove(struct pci_dev *pci) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci snd_card_free(pci_get_drvdata(pci)); 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic struct pci_driver ymfpci_driver = { 3588c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 3598c2ecf20Sopenharmony_ci .id_table = snd_ymfpci_ids, 3608c2ecf20Sopenharmony_ci .probe = snd_card_ymfpci_probe, 3618c2ecf20Sopenharmony_ci .remove = snd_card_ymfpci_remove, 3628c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 3638c2ecf20Sopenharmony_ci .driver = { 3648c2ecf20Sopenharmony_ci .pm = &snd_ymfpci_pm, 3658c2ecf20Sopenharmony_ci }, 3668c2ecf20Sopenharmony_ci#endif 3678c2ecf20Sopenharmony_ci}; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cimodule_pci_driver(ymfpci_driver); 370