diff options
Diffstat (limited to 'sound/pci/es1938.c')
| -rw-r--r-- | sound/pci/es1938.c | 268 |
1 files changed, 82 insertions, 186 deletions
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 9d248eb2e26c..280125eff362 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Driver for ESS Solo-1 (ES1938, ES1946, ES1969) soundcard * Copyright (c) by Jaromir Koutek <miri@punknet.cz>, @@ -10,22 +11,6 @@ * * TODO: * Rewrite better spinlocks - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ /* @@ -67,10 +52,6 @@ MODULE_AUTHOR("Jaromir Koutek <miri@punknet.cz>"); MODULE_DESCRIPTION("ESS Solo-1"); MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("{{ESS,ES1938}," - "{ESS,ES1946}," - "{ESS,ES1969}," - "{TerraTec,128i PCI}}"); #if IS_REACHABLE(CONFIG_GAMEPORT) #define SUPPORT_JOYSTICK 1 @@ -235,9 +216,7 @@ struct es1938 { #ifdef SUPPORT_JOYSTICK struct gameport *gameport; #endif -#ifdef CONFIG_PM_SLEEP unsigned char saved_regs[SAVED_REG_SIZE]; -#endif }; static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id); @@ -258,11 +237,9 @@ MODULE_DEVICE_TABLE(pci, snd_es1938_ids); * -----------------------------------------------------------------*/ static void snd_es1938_mixer_write(struct es1938 *chip, unsigned char reg, unsigned char val) { - unsigned long flags; - spin_lock_irqsave(&chip->mixer_lock, flags); + guard(spinlock_irqsave)(&chip->mixer_lock); outb(reg, SLSB_REG(chip, MIXERADDR)); outb(val, SLSB_REG(chip, MIXERDATA)); - spin_unlock_irqrestore(&chip->mixer_lock, flags); dev_dbg(chip->card->dev, "Mixer reg %02x set to %02x\n", reg, val); } @@ -272,11 +249,10 @@ static void snd_es1938_mixer_write(struct es1938 *chip, unsigned char reg, unsig static int snd_es1938_mixer_read(struct es1938 *chip, unsigned char reg) { int data; - unsigned long flags; - spin_lock_irqsave(&chip->mixer_lock, flags); + + guard(spinlock_irqsave)(&chip->mixer_lock); outb(reg, SLSB_REG(chip, MIXERADDR)); data = inb(SLSB_REG(chip, MIXERDATA)); - spin_unlock_irqrestore(&chip->mixer_lock, flags); dev_dbg(chip->card->dev, "Mixer reg %02x now is %02x\n", reg, data); return data; } @@ -287,9 +263,9 @@ static int snd_es1938_mixer_read(struct es1938 *chip, unsigned char reg) static int snd_es1938_mixer_bits(struct es1938 *chip, unsigned char reg, unsigned char mask, unsigned char val) { - unsigned long flags; unsigned char old, new, oval; - spin_lock_irqsave(&chip->mixer_lock, flags); + + guard(spinlock_irqsave)(&chip->mixer_lock); outb(reg, SLSB_REG(chip, MIXERADDR)); old = inb(SLSB_REG(chip, MIXERDATA)); oval = old & mask; @@ -300,7 +276,6 @@ static int snd_es1938_mixer_bits(struct es1938 *chip, unsigned char reg, "Mixer reg %02x was %02x, set to %02x\n", reg, old, new); } - spin_unlock_irqrestore(&chip->mixer_lock, flags); return oval; } @@ -312,7 +287,8 @@ static void snd_es1938_write_cmd(struct es1938 *chip, unsigned char cmd) int i; unsigned char v; for (i = 0; i < WRITE_LOOP_TIMEOUT; i++) { - if (!(v = inb(SLSB_REG(chip, READSTATUS)) & 0x80)) { + v = inb(SLSB_REG(chip, READSTATUS)); + if (!(v & 0x80)) { outb(cmd, SLSB_REG(chip, WRITEDATA)); return; } @@ -328,9 +304,11 @@ static int snd_es1938_get_byte(struct es1938 *chip) { int i; unsigned char v; - for (i = GET_LOOP_TIMEOUT; i; i--) - if ((v = inb(SLSB_REG(chip, STATUS))) & 0x80) + for (i = GET_LOOP_TIMEOUT; i; i--) { + v = inb(SLSB_REG(chip, STATUS)); + if (v & 0x80) return inb(SLSB_REG(chip, READDATA)); + } dev_err(chip->card->dev, "get_byte timeout: status 0x02%x\n", v); return -ENODEV; } @@ -340,11 +318,9 @@ static int snd_es1938_get_byte(struct es1938 *chip) * -----------------------------------------------------------------*/ static void snd_es1938_write(struct es1938 *chip, unsigned char reg, unsigned char val) { - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + guard(spinlock_irqsave)(&chip->reg_lock); snd_es1938_write_cmd(chip, reg); snd_es1938_write_cmd(chip, val); - spin_unlock_irqrestore(&chip->reg_lock, flags); dev_dbg(chip->card->dev, "Reg %02x set to %02x\n", reg, val); } @@ -354,12 +330,11 @@ static void snd_es1938_write(struct es1938 *chip, unsigned char reg, unsigned ch static unsigned char snd_es1938_read(struct es1938 *chip, unsigned char reg) { unsigned char val; - unsigned long flags; - spin_lock_irqsave(&chip->reg_lock, flags); + + guard(spinlock_irqsave)(&chip->reg_lock); snd_es1938_write_cmd(chip, ESS_CMD_READREG); snd_es1938_write_cmd(chip, reg); val = snd_es1938_get_byte(chip); - spin_unlock_irqrestore(&chip->reg_lock, flags); dev_dbg(chip->card->dev, "Reg %02x now is %02x\n", reg, val); return val; } @@ -370,9 +345,9 @@ static unsigned char snd_es1938_read(struct es1938 *chip, unsigned char reg) static int snd_es1938_bits(struct es1938 *chip, unsigned char reg, unsigned char mask, unsigned char val) { - unsigned long flags; unsigned char old, new, oval; - spin_lock_irqsave(&chip->reg_lock, flags); + + guard(spinlock_irqsave)(&chip->reg_lock); snd_es1938_write_cmd(chip, ESS_CMD_READREG); snd_es1938_write_cmd(chip, reg); old = snd_es1938_get_byte(chip); @@ -384,7 +359,6 @@ static int snd_es1938_bits(struct es1938 *chip, unsigned char reg, unsigned char dev_dbg(chip->card->dev, "Reg %02x was %02x, set to %02x\n", reg, old, new); } - spin_unlock_irqrestore(&chip->reg_lock, flags); return oval; } @@ -840,7 +814,7 @@ static snd_pcm_uframes_t snd_es1938_playback_pointer(struct snd_pcm_substream *s static int snd_es1938_capture_copy(struct snd_pcm_substream *substream, int channel, unsigned long pos, - void __user *dst, unsigned long count) + struct iov_iter *dst, unsigned long count) { struct snd_pcm_runtime *runtime = substream->runtime; struct es1938 *chip = snd_pcm_substream_chip(substream); @@ -848,55 +822,17 @@ static int snd_es1938_capture_copy(struct snd_pcm_substream *substream, if (snd_BUG_ON(pos + count > chip->dma1_size)) return -EINVAL; if (pos + count < chip->dma1_size) { - if (copy_to_user(dst, runtime->dma_area + pos + 1, count)) + if (copy_to_iter(runtime->dma_area + pos + 1, count, dst) != count) return -EFAULT; } else { - if (copy_to_user(dst, runtime->dma_area + pos + 1, count - 1)) + if (copy_to_iter(runtime->dma_area + pos + 1, count - 1, dst) != count - 1) return -EFAULT; - if (put_user(runtime->dma_area[0], - ((unsigned char __user *)dst) + count - 1)) + if (copy_to_iter(runtime->dma_area, 1, dst) != 1) return -EFAULT; } return 0; } -static int snd_es1938_capture_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long pos, - void *dst, unsigned long count) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct es1938 *chip = snd_pcm_substream_chip(substream); - - if (snd_BUG_ON(pos + count > chip->dma1_size)) - return -EINVAL; - if (pos + count < chip->dma1_size) { - memcpy(dst, runtime->dma_area + pos + 1, count); - } else { - memcpy(dst, runtime->dma_area + pos + 1, count - 1); - runtime->dma_area[0] = *((unsigned char *)dst + count - 1); - } - return 0; -} - -/* - * buffer management - */ -static int snd_es1938_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) - -{ - int err; - - if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) - return err; - return 0; -} - -static int snd_es1938_pcm_hw_free(struct snd_pcm_substream *substream) -{ - return snd_pcm_lib_free_pages(substream); -} - /* ---------------------------------------------------------------------- * Audio1 Capture (ADC) * ----------------------------------------------------------------------*/ @@ -1011,9 +947,6 @@ static int snd_es1938_playback_close(struct snd_pcm_substream *substream) static const struct snd_pcm_ops snd_es1938_playback_ops = { .open = snd_es1938_playback_open, .close = snd_es1938_playback_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_es1938_pcm_hw_params, - .hw_free = snd_es1938_pcm_hw_free, .prepare = snd_es1938_playback_prepare, .trigger = snd_es1938_playback_trigger, .pointer = snd_es1938_playback_pointer, @@ -1022,14 +955,10 @@ static const struct snd_pcm_ops snd_es1938_playback_ops = { static const struct snd_pcm_ops snd_es1938_capture_ops = { .open = snd_es1938_capture_open, .close = snd_es1938_capture_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_es1938_pcm_hw_params, - .hw_free = snd_es1938_pcm_hw_free, .prepare = snd_es1938_capture_prepare, .trigger = snd_es1938_capture_trigger, .pointer = snd_es1938_capture_pointer, - .copy_user = snd_es1938_capture_copy, - .copy_kernel = snd_es1938_capture_copy_kernel, + .copy = snd_es1938_capture_copy, }; static int snd_es1938_new_pcm(struct es1938 *chip, int device) @@ -1037,17 +966,18 @@ static int snd_es1938_new_pcm(struct es1938 *chip, int device) struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(chip->card, "es-1938-1946", device, 2, 1, &pcm)) < 0) + err = snd_pcm_new(chip->card, "es-1938-1946", device, 2, 1, &pcm); + if (err < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_es1938_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_es1938_capture_ops); pcm->private_data = chip; pcm->info_flags = 0; - strcpy(pcm->name, "ESS Solo-1"); + strscpy(pcm->name, "ESS Solo-1"); - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), 64*1024, 64*1024); + snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, + &chip->pci->dev, 64*1024, 64*1024); chip->pcm = pcm; return 0; @@ -1347,7 +1277,7 @@ static const DECLARE_TLV_DB_RANGE(db_scale_line, static const DECLARE_TLV_DB_SCALE(db_scale_capture, 0, 150, 0); -static struct snd_kcontrol_new snd_es1938_controls[] = { +static const struct snd_kcontrol_new snd_es1938_controls[] = { ES1938_DOUBLE_TLV("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0, db_scale_master), ES1938_DOUBLE("Master Playback Switch", 0, 0x60, 0x62, 6, 6, 1, 1), @@ -1455,12 +1385,11 @@ static void snd_es1938_chip_init(struct es1938 *chip) outb(0, SLDM_REG(chip, DMACLEAR)); } -#ifdef CONFIG_PM_SLEEP /* * PM support */ -static unsigned char saved_regs[SAVED_REG_SIZE+1] = { +static const unsigned char saved_regs[SAVED_REG_SIZE+1] = { 0x14, 0x1a, 0x1c, 0x3a, 0x3c, 0x3e, 0x36, 0x38, 0x50, 0x52, 0x60, 0x61, 0x62, 0x63, 0x64, 0x68, 0x69, 0x6a, 0x6b, 0x6d, 0x6e, 0x6f, 0x7c, 0x7d, @@ -1472,10 +1401,10 @@ static int es1938_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct es1938 *chip = card->private_data; - unsigned char *s, *d; + const unsigned char *s; + unsigned char *d; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); /* save mixer-related registers */ for (s = saved_regs, d = chip->saved_regs; *s; s++, d++) @@ -1485,6 +1414,7 @@ static int es1938_suspend(struct device *dev) if (chip->irq >= 0) { free_irq(chip->irq, chip); chip->irq = -1; + card->sync_irq = -1; } return 0; } @@ -1494,7 +1424,8 @@ static int es1938_resume(struct device *dev) struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct es1938 *chip = card->private_data; - unsigned char *s, *d; + const unsigned char *s; + unsigned char *d; if (request_irq(pci->irq, snd_es1938_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { @@ -1504,6 +1435,7 @@ static int es1938_resume(struct device *dev) return -EIO; } chip->irq = pci->irq; + card->sync_irq = chip->irq; snd_es1938_chip_init(chip); /* restore mixer-related registers */ @@ -1518,11 +1450,7 @@ static int es1938_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(es1938_pm, es1938_suspend, es1938_resume); -#define ES1938_PM_OPS &es1938_pm -#else -#define ES1938_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(es1938_pm, es1938_suspend, es1938_resume); #ifdef SUPPORT_JOYSTICK static int snd_es1938_create_gameport(struct es1938 *chip) @@ -1558,8 +1486,10 @@ static inline int snd_es1938_create_gameport(struct es1938 *chip) { return -ENOS static inline void snd_es1938_free_gameport(struct es1938 *chip) { } #endif /* SUPPORT_JOYSTICK */ -static int snd_es1938_free(struct es1938 *chip) +static void snd_es1938_free(struct snd_card *card) { + struct es1938 *chip = card->private_data; + /* disable irqs */ outb(0x00, SLIO_REG(chip, IRQCONTROL)); if (chip->rmidi) @@ -1569,69 +1499,47 @@ static int snd_es1938_free(struct es1938 *chip) if (chip->irq >= 0) free_irq(chip->irq, chip); - pci_release_regions(chip->pci); - pci_disable_device(chip->pci); - kfree(chip); - return 0; -} - -static int snd_es1938_dev_free(struct snd_device *device) -{ - struct es1938 *chip = device->device_data; - return snd_es1938_free(chip); } static int snd_es1938_create(struct snd_card *card, - struct pci_dev *pci, - struct es1938 **rchip) + struct pci_dev *pci) { - struct es1938 *chip; + struct es1938 *chip = card->private_data; int err; - static struct snd_device_ops ops = { - .dev_free = snd_es1938_dev_free, - }; - - *rchip = NULL; /* enable PCI device */ - if ((err = pci_enable_device(pci)) < 0) + err = pcim_enable_device(pci); + if (err < 0) return err; /* check, if we can restrict PCI DMA transfers to 24 bits */ - if (dma_set_mask(&pci->dev, DMA_BIT_MASK(24)) < 0 || - dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(24)) < 0) { + if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(24))) { dev_err(card->dev, "architecture does not support 24bit PCI busmaster DMA\n"); - pci_disable_device(pci); return -ENXIO; } - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) { - pci_disable_device(pci); - return -ENOMEM; - } spin_lock_init(&chip->reg_lock); spin_lock_init(&chip->mixer_lock); chip->card = card; chip->pci = pci; chip->irq = -1; - if ((err = pci_request_regions(pci, "ESS Solo-1")) < 0) { - kfree(chip); - pci_disable_device(pci); + err = pcim_request_all_regions(pci, "ESS Solo-1"); + if (err < 0) return err; - } chip->io_port = pci_resource_start(pci, 0); chip->sb_port = pci_resource_start(pci, 1); chip->vc_port = pci_resource_start(pci, 2); chip->mpu_port = pci_resource_start(pci, 3); chip->game_port = pci_resource_start(pci, 4); + /* still use non-managed irq handler as it's re-acquired at PM resume */ if (request_irq(pci->irq, snd_es1938_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); - snd_es1938_free(chip); return -EBUSY; } chip->irq = pci->irq; + card->sync_irq = chip->irq; + card->private_free = snd_es1938_free; dev_dbg(card->dev, "create: io: 0x%lx, sb: 0x%lx, vc: 0x%lx, mpu: 0x%lx, game: 0x%lx\n", chip->io_port, chip->sb_port, chip->vc_port, chip->mpu_port, chip->game_port); @@ -1639,13 +1547,6 @@ static int snd_es1938_create(struct snd_card *card, chip->ddma_port = chip->vc_port + 0x00; /* fix from Thomas Sailer */ snd_es1938_chip_init(chip); - - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { - snd_es1938_free(chip); - return err; - } - - *rchip = chip; return 0; } @@ -1655,7 +1556,8 @@ static int snd_es1938_create(struct snd_card *card, static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id) { struct es1938 *chip = dev_id; - unsigned char status, audiostatus; + unsigned char status; + __always_unused unsigned char audiostatus; int handled = 0; status = inb(SLIO_REG(chip, IRQCONTROL)); @@ -1748,7 +1650,7 @@ static int snd_es1938_mixer(struct es1938 *chip) card = chip->card; - strcpy(card->mixername, "ESS Solo-1"); + strscpy(card->mixername, "ESS Solo-1"); for (idx = 0; idx < ARRAY_SIZE(snd_es1938_controls); idx++) { struct snd_kcontrol *kctl; @@ -1771,15 +1673,16 @@ static int snd_es1938_mixer(struct es1938 *chip) kctl->private_free = snd_es1938_hwv_free; break; } - if ((err = snd_ctl_add(card, kctl)) < 0) + err = snd_ctl_add(card, kctl); + if (err < 0) return err; } return 0; } -static int snd_es1938_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int __snd_es1938_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -1794,38 +1697,34 @@ static int snd_es1938_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, - 0, &card); + err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + sizeof(*chip), &card); if (err < 0) return err; - for (idx = 0; idx < 5; idx++) { + chip = card->private_data; + + for (idx = 0; idx < 5; idx++) if (pci_resource_start(pci, idx) == 0 || - !(pci_resource_flags(pci, idx) & IORESOURCE_IO)) { - snd_card_free(card); - return -ENODEV; - } - } - if ((err = snd_es1938_create(card, pci, &chip)) < 0) { - snd_card_free(card); + !(pci_resource_flags(pci, idx) & IORESOURCE_IO)) + return -ENODEV; + + err = snd_es1938_create(card, pci); + if (err < 0) return err; - } - card->private_data = chip; - strcpy(card->driver, "ES1938"); - strcpy(card->shortname, "ESS ES1938 (Solo-1)"); + strscpy(card->driver, "ES1938"); + strscpy(card->shortname, "ESS ES1938 (Solo-1)"); sprintf(card->longname, "%s rev %i, irq %i", card->shortname, chip->revision, chip->irq); - if ((err = snd_es1938_new_pcm(chip, 0)) < 0) { - snd_card_free(card); + err = snd_es1938_new_pcm(chip, 0); + if (err < 0) return err; - } - if ((err = snd_es1938_mixer(chip)) < 0) { - snd_card_free(card); + err = snd_es1938_mixer(chip); + if (err < 0) return err; - } if (snd_opl3_create(card, SLSB_REG(chip, FMLOWADDR), SLSB_REG(chip, FMHIGHADDR), @@ -1833,14 +1732,12 @@ static int snd_es1938_probe(struct pci_dev *pci, dev_err(card->dev, "OPL3 not detected at 0x%lx\n", SLSB_REG(chip, FMLOWADDR)); } else { - if ((err = snd_opl3_timer_new(opl3, 0, 1)) < 0) { - snd_card_free(card); + err = snd_opl3_timer_new(opl3, 0, 1); + if (err < 0) return err; - } - if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { - snd_card_free(card); + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) return err; - } } if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, chip->mpu_port, @@ -1855,28 +1752,27 @@ static int snd_es1938_probe(struct pci_dev *pci, snd_es1938_create_gameport(chip); - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); + err = snd_card_register(card); + if (err < 0) return err; - } pci_set_drvdata(pci, card); dev++; return 0; } -static void snd_es1938_remove(struct pci_dev *pci) +static int snd_es1938_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { - snd_card_free(pci_get_drvdata(pci)); + return snd_card_free_on_error(&pci->dev, __snd_es1938_probe(pci, pci_id)); } static struct pci_driver es1938_driver = { .name = KBUILD_MODNAME, .id_table = snd_es1938_ids, .probe = snd_es1938_probe, - .remove = snd_es1938_remove, .driver = { - .pm = ES1938_PM_OPS, + .pm = &es1938_pm, }, }; |
