brintos

brintos / linux-shallow public Read only

0
0
Text · 5.8 KiB · a4d5bf3 Raw
263 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>4 *                   Uros Bizjak <uros@kss-loka.si>5 *6 *  Lowlevel routines for control of Sound Blaster cards7 */8 9#include <linux/delay.h>10#include <linux/init.h>11#include <linux/interrupt.h>12#include <linux/slab.h>13#include <linux/ioport.h>14#include <linux/module.h>15#include <linux/io.h>16#include <sound/core.h>17#include <sound/sb.h>18#include <sound/initval.h>19 20#include <asm/dma.h>21 22MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");23MODULE_DESCRIPTION("ALSA lowlevel driver for Sound Blaster cards");24MODULE_LICENSE("GPL");25 26#define BUSY_LOOPS 10000027 28#undef IO_DEBUG29 30int snd_sbdsp_command(struct snd_sb *chip, unsigned char val)31{32	int i;33#ifdef IO_DEBUG34	dev_dbg(chip->card->dev, "command 0x%x\n", val);35#endif36	for (i = BUSY_LOOPS; i; i--)37		if ((inb(SBP(chip, STATUS)) & 0x80) == 0) {38			outb(val, SBP(chip, COMMAND));39			return 1;40		}41	dev_dbg(chip->card->dev, "%s [0x%lx]: timeout (0x%x)\n", __func__, chip->port, val);42	return 0;43}44 45int snd_sbdsp_get_byte(struct snd_sb *chip)46{47	int val;48	int i;49	for (i = BUSY_LOOPS; i; i--) {50		if (inb(SBP(chip, DATA_AVAIL)) & 0x80) {51			val = inb(SBP(chip, READ));52#ifdef IO_DEBUG53			dev_dbg(chip->card->dev, "get_byte 0x%x\n", val);54#endif55			return val;56		}57	}58	dev_dbg(chip->card->dev, "%s [0x%lx]: timeout\n", __func__, chip->port);59	return -ENODEV;60}61 62int snd_sbdsp_reset(struct snd_sb *chip)63{64	int i;65 66	outb(1, SBP(chip, RESET));67	udelay(10);68	outb(0, SBP(chip, RESET));69	udelay(30);70	for (i = BUSY_LOOPS; i; i--)71		if (inb(SBP(chip, DATA_AVAIL)) & 0x80) {72			if (inb(SBP(chip, READ)) == 0xaa)73				return 0;74			else75				break;76		}77	if (chip->card)78		dev_dbg(chip->card->dev, "%s [0x%lx] failed...\n", __func__, chip->port);79	return -ENODEV;80}81 82static int snd_sbdsp_version(struct snd_sb * chip)83{84	unsigned int result;85 86	snd_sbdsp_command(chip, SB_DSP_GET_VERSION);87	result = (short) snd_sbdsp_get_byte(chip) << 8;88	result |= (short) snd_sbdsp_get_byte(chip);89	return result;90}91 92static int snd_sbdsp_probe(struct snd_sb * chip)93{94	int version;95	int major, minor;96	char *str;97	unsigned long flags;98 99	/*100	 *  initialization sequence101	 */102 103	spin_lock_irqsave(&chip->reg_lock, flags);104	if (snd_sbdsp_reset(chip) < 0) {105		spin_unlock_irqrestore(&chip->reg_lock, flags);106		return -ENODEV;107	}108	version = snd_sbdsp_version(chip);109	if (version < 0) {110		spin_unlock_irqrestore(&chip->reg_lock, flags);111		return -ENODEV;112	}113	spin_unlock_irqrestore(&chip->reg_lock, flags);114	major = version >> 8;115	minor = version & 0xff;116	dev_dbg(chip->card->dev, "SB [0x%lx]: DSP chip found, version = %i.%i\n",117		chip->port, major, minor);118 119	switch (chip->hardware) {120	case SB_HW_AUTO:121		switch (major) {122		case 1:123			chip->hardware = SB_HW_10;124			str = "1.0";125			break;126		case 2:127			if (minor) {128				chip->hardware = SB_HW_201;129				str = "2.01+";130			} else {131				chip->hardware = SB_HW_20;132				str = "2.0";133			}134			break;135		case 3:136			chip->hardware = SB_HW_PRO;137			str = "Pro";138			break;139		case 4:140			chip->hardware = SB_HW_16;141			str = "16";142			break;143		default:144			dev_info(chip->card->dev, "SB [0x%lx]: unknown DSP chip version %i.%i\n",145				 chip->port, major, minor);146			return -ENODEV;147		}148		break;149	case SB_HW_ALS100:150		str = "16 (ALS-100)";151		break;152	case SB_HW_ALS4000:153		str = "16 (ALS-4000)";154		break;155	case SB_HW_DT019X:156		str = "(DT019X/ALS007)";157		break;158	case SB_HW_CS5530:159		str = "16 (CS5530)";160		break;161	case SB_HW_JAZZ16:162		str = "Pro (Jazz16)";163		break;164	default:165		return -ENODEV;166	}167	sprintf(chip->name, "Sound Blaster %s", str);168	chip->version = (major << 8) | minor;169	return 0;170}171 172int snd_sbdsp_create(struct snd_card *card,173		     unsigned long port,174		     int irq,175		     irq_handler_t irq_handler,176		     int dma8,177		     int dma16,178		     unsigned short hardware,179		     struct snd_sb **r_chip)180{181	struct snd_sb *chip;182	int err;183 184	if (snd_BUG_ON(!r_chip))185		return -EINVAL;186	*r_chip = NULL;187	chip = devm_kzalloc(card->dev, sizeof(*chip), GFP_KERNEL);188	if (!chip)189		return -ENOMEM;190	spin_lock_init(&chip->reg_lock);191	spin_lock_init(&chip->open_lock);192	spin_lock_init(&chip->midi_input_lock);193	spin_lock_init(&chip->mixer_lock);194	chip->irq = -1;195	chip->dma8 = -1;196	chip->dma16 = -1;197	chip->port = port;198	199	if (devm_request_irq(card->dev, irq, irq_handler,200			     (hardware == SB_HW_ALS4000 ||201			      hardware == SB_HW_CS5530) ?202			     IRQF_SHARED : 0,203			     "SoundBlaster", (void *) chip)) {204		dev_err(card->dev, "sb: can't grab irq %d\n", irq);205		return -EBUSY;206	}207	chip->irq = irq;208	card->sync_irq = chip->irq;209 210	if (hardware == SB_HW_ALS4000)211		goto __skip_allocation;212	213	chip->res_port = devm_request_region(card->dev, port, 16,214					     "SoundBlaster");215	if (!chip->res_port) {216		dev_err(card->dev, "sb: can't grab port 0x%lx\n", port);217		return -EBUSY;218	}219 220#ifdef CONFIG_ISA221	if (dma8 >= 0 && snd_devm_request_dma(card->dev, dma8,222					      "SoundBlaster - 8bit")) {223		dev_err(card->dev, "sb: can't grab DMA8 %d\n", dma8);224		return -EBUSY;225	}226	chip->dma8 = dma8;227	if (dma16 >= 0) {228		if (hardware != SB_HW_ALS100 && (dma16 < 5 || dma16 > 7)) {229			/* no duplex */230			dma16 = -1;231		} else if (snd_devm_request_dma(card->dev, dma16,232						"SoundBlaster - 16bit")) {233			dev_err(card->dev, "sb: can't grab DMA16 %d\n", dma16);234			return -EBUSY;235		}236	}237	chip->dma16 = dma16;238#endif239 240      __skip_allocation:241	chip->card = card;242	chip->hardware = hardware;243	err = snd_sbdsp_probe(chip);244	if (err < 0)245		return err;246	*r_chip = chip;247	return 0;248}249 250EXPORT_SYMBOL(snd_sbdsp_command);251EXPORT_SYMBOL(snd_sbdsp_get_byte);252EXPORT_SYMBOL(snd_sbdsp_reset);253EXPORT_SYMBOL(snd_sbdsp_create);254/* sb_mixer.c */255EXPORT_SYMBOL(snd_sbmixer_write);256EXPORT_SYMBOL(snd_sbmixer_read);257EXPORT_SYMBOL(snd_sbmixer_new);258EXPORT_SYMBOL(snd_sbmixer_add_ctl);259#ifdef CONFIG_PM260EXPORT_SYMBOL(snd_sbmixer_suspend);261EXPORT_SYMBOL(snd_sbmixer_resume);262#endif263