cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ymfpci.c (9605B)


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