brintos

brintos / linux-shallow public Read only

0
0
Text · 28.6 KiB · c0c2301 Raw
996 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>4 *  Routines for control of ESS ES1688/688/488 chip5 */6 7#include <linux/init.h>8#include <linux/interrupt.h>9#include <linux/delay.h>10#include <linux/slab.h>11#include <linux/ioport.h>12#include <linux/module.h>13#include <linux/io.h>14#include <sound/core.h>15#include <sound/es1688.h>16#include <sound/initval.h>17 18#include <asm/dma.h>19 20MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");21MODULE_DESCRIPTION("ESS ESx688 lowlevel module");22MODULE_LICENSE("GPL");23 24static int snd_es1688_dsp_command(struct snd_es1688 *chip, unsigned char val)25{26	int i;27 28	for (i = 10000; i; i--)29		if ((inb(ES1688P(chip, STATUS)) & 0x80) == 0) {30			outb(val, ES1688P(chip, COMMAND));31			return 1;32		}33	dev_dbg(chip->card->dev, "%s: timeout (0x%x)\n", __func__, val);34	return 0;35}36 37static int snd_es1688_dsp_get_byte(struct snd_es1688 *chip)38{39	int i;40 41	for (i = 1000; i; i--)42		if (inb(ES1688P(chip, DATA_AVAIL)) & 0x80)43			return inb(ES1688P(chip, READ));44	dev_dbg(chip->card->dev, "es1688 get byte failed: 0x%lx = 0x%x!!!\n",45		ES1688P(chip, DATA_AVAIL), inb(ES1688P(chip, DATA_AVAIL)));46	return -ENODEV;47}48 49static int snd_es1688_write(struct snd_es1688 *chip,50			    unsigned char reg, unsigned char data)51{52	if (!snd_es1688_dsp_command(chip, reg))53		return 0;54	return snd_es1688_dsp_command(chip, data);55}56 57static int snd_es1688_read(struct snd_es1688 *chip, unsigned char reg)58{59	/* Read a byte from an extended mode register of ES1688 */60	if (!snd_es1688_dsp_command(chip, 0xc0))61		return -1;62	if (!snd_es1688_dsp_command(chip, reg))63		return -1;64	return snd_es1688_dsp_get_byte(chip);65}66 67void snd_es1688_mixer_write(struct snd_es1688 *chip,68			    unsigned char reg, unsigned char data)69{70	outb(reg, ES1688P(chip, MIXER_ADDR));71	udelay(10);72	outb(data, ES1688P(chip, MIXER_DATA));73	udelay(10);74}75 76static unsigned char snd_es1688_mixer_read(struct snd_es1688 *chip, unsigned char reg)77{78	unsigned char result;79 80	outb(reg, ES1688P(chip, MIXER_ADDR));81	udelay(10);82	result = inb(ES1688P(chip, MIXER_DATA));83	udelay(10);84	return result;85}86 87int snd_es1688_reset(struct snd_es1688 *chip)88{89	int i;90 91	outb(3, ES1688P(chip, RESET));		/* valid only for ESS chips, SB -> 1 */92	udelay(10);93	outb(0, ES1688P(chip, RESET));94	udelay(30);95	for (i = 0; i < 1000 && !(inb(ES1688P(chip, DATA_AVAIL)) & 0x80); i++);96	if (inb(ES1688P(chip, READ)) != 0xaa) {97		dev_dbg(chip->card->dev, "ess_reset at 0x%lx: failed!!!\n",98			chip->port);99		return -ENODEV;100	}101	snd_es1688_dsp_command(chip, 0xc6);	/* enable extended mode */102	return 0;103}104EXPORT_SYMBOL(snd_es1688_reset);105 106static int snd_es1688_probe(struct snd_es1688 *chip)107{108	unsigned long flags;109	unsigned short major, minor;110	int i;111 112	/*113	 *  initialization sequence114	 */115 116	spin_lock_irqsave(&chip->reg_lock, flags);	/* Some ESS1688 cards need this */117	inb(ES1688P(chip, ENABLE1));	/* ENABLE1 */118	inb(ES1688P(chip, ENABLE1));	/* ENABLE1 */119	inb(ES1688P(chip, ENABLE1));	/* ENABLE1 */120	inb(ES1688P(chip, ENABLE2));	/* ENABLE2 */121	inb(ES1688P(chip, ENABLE1));	/* ENABLE1 */122	inb(ES1688P(chip, ENABLE2));	/* ENABLE2 */123	inb(ES1688P(chip, ENABLE1));	/* ENABLE1 */124	inb(ES1688P(chip, ENABLE1));	/* ENABLE1 */125	inb(ES1688P(chip, ENABLE2));	/* ENABLE2 */126	inb(ES1688P(chip, ENABLE1));	/* ENABLE1 */127	inb(ES1688P(chip, ENABLE0));	/* ENABLE0 */128 129	if (snd_es1688_reset(chip) < 0) {130		dev_dbg(chip->card->dev, "ESS: [0x%lx] reset failed... 0x%x\n",131			chip->port, inb(ES1688P(chip, READ)));132		spin_unlock_irqrestore(&chip->reg_lock, flags);133		return -ENODEV;134	}135	snd_es1688_dsp_command(chip, 0xe7);	/* return identification */136 137	for (i = 1000, major = minor = 0; i; i--) {138		if (inb(ES1688P(chip, DATA_AVAIL)) & 0x80) {139			if (major == 0) {140				major = inb(ES1688P(chip, READ));141			} else {142				minor = inb(ES1688P(chip, READ));143			}144		}145	}146 147	spin_unlock_irqrestore(&chip->reg_lock, flags);148 149	dev_dbg(chip->card->dev,150		"ESS: [0x%lx] found.. major = 0x%x, minor = 0x%x\n",151		chip->port, major, minor);152 153	chip->version = (major << 8) | minor;154	if (!chip->version)155		return -ENODEV;	/* probably SB */156 157	switch (chip->version & 0xfff0) {158	case 0x4880:159		dev_err(chip->card->dev,160			"[0x%lx] ESS: AudioDrive ES488 detected, but driver is in another place\n",161			chip->port);162		return -ENODEV;163	case 0x6880:164		break;165	default:166		dev_err(chip->card->dev,167			"[0x%lx] ESS: unknown AudioDrive chip with version 0x%x (Jazz16 soundcard?)\n",168			chip->port, chip->version);169		return -ENODEV;170	}171 172	spin_lock_irqsave(&chip->reg_lock, flags);173	snd_es1688_write(chip, 0xb1, 0x10);	/* disable IRQ */174	snd_es1688_write(chip, 0xb2, 0x00);	/* disable DMA */175	spin_unlock_irqrestore(&chip->reg_lock, flags);176 177	/* enable joystick, but disable OPL3 */178	spin_lock_irqsave(&chip->mixer_lock, flags);179	snd_es1688_mixer_write(chip, 0x40, 0x01);180	spin_unlock_irqrestore(&chip->mixer_lock, flags);181 182	return 0;183}184 185static int snd_es1688_init(struct snd_es1688 * chip, int enable)186{187	static const int irqs[16] = {-1, -1, 0, -1, -1, 1, -1, 2, -1, 0, 3, -1, -1, -1, -1, -1};188	unsigned long flags;189	int cfg, irq_bits, dma, dma_bits, tmp, tmp1;190 191	/* ok.. setup MPU-401 port and joystick and OPL3 */192	cfg = 0x01;		/* enable joystick, but disable OPL3 */193	if (enable && chip->mpu_port >= 0x300 && chip->mpu_irq > 0 && chip->hardware != ES1688_HW_688) {194		tmp = (chip->mpu_port & 0x0f0) >> 4;195		if (tmp <= 3) {196			switch (chip->mpu_irq) {197			case 9:198				tmp1 = 4;199				break;200			case 5:201				tmp1 = 5;202				break;203			case 7:204				tmp1 = 6;205				break;206			case 10:207				tmp1 = 7;208				break;209			default:210				tmp1 = 0;211			}212			if (tmp1) {213				cfg |= (tmp << 3) | (tmp1 << 5);214			}215		}216	}217	spin_lock_irqsave(&chip->reg_lock, flags);218	snd_es1688_mixer_write(chip, 0x40, cfg);219	spin_unlock_irqrestore(&chip->reg_lock, flags);220	/* --- */221	spin_lock_irqsave(&chip->reg_lock, flags);222	snd_es1688_read(chip, 0xb1);223	snd_es1688_read(chip, 0xb2);224	spin_unlock_irqrestore(&chip->reg_lock, flags);225	if (enable) {226		cfg = 0xf0;	/* enable only DMA counter interrupt */227		irq_bits = irqs[chip->irq & 0x0f];228		if (irq_bits < 0) {229			dev_err(chip->card->dev,230				"[0x%lx] ESS: bad IRQ %d for ES1688 chip!!\n",231				chip->port, chip->irq);232#if 0233			irq_bits = 0;234			cfg = 0x10;235#endif236			return -EINVAL;237		}238		spin_lock_irqsave(&chip->reg_lock, flags);239		snd_es1688_write(chip, 0xb1, cfg | (irq_bits << 2));240		spin_unlock_irqrestore(&chip->reg_lock, flags);241		cfg = 0xf0;	/* extended mode DMA enable */242		dma = chip->dma8;243		if (dma > 3 || dma == 2) {244			dev_err(chip->card->dev,245				"[0x%lx] ESS: bad DMA channel %d for ES1688 chip!!\n",246				chip->port, dma);247#if 0248			dma_bits = 0;249			cfg = 0x00;	/* disable all DMA */250#endif251			return -EINVAL;252		} else {253			dma_bits = dma;254			if (dma != 3)255				dma_bits++;256		}257		spin_lock_irqsave(&chip->reg_lock, flags);258		snd_es1688_write(chip, 0xb2, cfg | (dma_bits << 2));259		spin_unlock_irqrestore(&chip->reg_lock, flags);260	} else {261		spin_lock_irqsave(&chip->reg_lock, flags);262		snd_es1688_write(chip, 0xb1, 0x10);	/* disable IRQ */263		snd_es1688_write(chip, 0xb2, 0x00);	/* disable DMA */264		spin_unlock_irqrestore(&chip->reg_lock, flags);265	}266	spin_lock_irqsave(&chip->reg_lock, flags);267	snd_es1688_read(chip, 0xb1);268	snd_es1688_read(chip, 0xb2);269	snd_es1688_reset(chip);270	spin_unlock_irqrestore(&chip->reg_lock, flags);271	return 0;272}273 274/*275 276 */277 278static const struct snd_ratnum clocks[2] = {279	{280		.num = 795444,281		.den_min = 1,282		.den_max = 128,283		.den_step = 1,284	},285	{286		.num = 397722,287		.den_min = 1,288		.den_max = 128,289		.den_step = 1,290	}291};292 293static const struct snd_pcm_hw_constraint_ratnums hw_constraints_clocks  = {294	.nrats = 2,295	.rats = clocks,296};297 298static void snd_es1688_set_rate(struct snd_es1688 *chip, struct snd_pcm_substream *substream)299{300	struct snd_pcm_runtime *runtime = substream->runtime;301	unsigned int bits, divider;302 303	if (runtime->rate_num == clocks[0].num)304		bits = 256 - runtime->rate_den;305	else306		bits = 128 - runtime->rate_den;307	/* set filter register */308	divider = 256 - 7160000*20/(8*82*runtime->rate);309	/* write result to hardware */310	snd_es1688_write(chip, 0xa1, bits);311	snd_es1688_write(chip, 0xa2, divider);312}313 314static int snd_es1688_trigger(struct snd_es1688 *chip, int cmd, unsigned char value)315{316	int val;317 318	if (cmd == SNDRV_PCM_TRIGGER_STOP) {319		value = 0x00;320	} else if (cmd != SNDRV_PCM_TRIGGER_START) {321		return -EINVAL;322	}323	spin_lock(&chip->reg_lock);324	chip->trigger_value = value;325	val = snd_es1688_read(chip, 0xb8);326	if ((val < 0) || (val & 0x0f) == value) {327		spin_unlock(&chip->reg_lock);328		return -EINVAL;	/* something is wrong */329	}330#if 0331	dev_dbg(chip->card->dev, "trigger: val = 0x%x, value = 0x%x\n", val, value);332	dev_dbg(chip->card->dev, "trigger: pointer = 0x%x\n",333		snd_dma_pointer(chip->dma8, chip->dma_size));334#endif335	snd_es1688_write(chip, 0xb8, (val & 0xf0) | value);336	spin_unlock(&chip->reg_lock);337	return 0;338}339 340static int snd_es1688_playback_prepare(struct snd_pcm_substream *substream)341{342	unsigned long flags;343	struct snd_es1688 *chip = snd_pcm_substream_chip(substream);344	struct snd_pcm_runtime *runtime = substream->runtime;345	unsigned int size = snd_pcm_lib_buffer_bytes(substream);346	unsigned int count = snd_pcm_lib_period_bytes(substream);347 348	chip->dma_size = size;349	spin_lock_irqsave(&chip->reg_lock, flags);350	snd_es1688_reset(chip);351	snd_es1688_set_rate(chip, substream);352	snd_es1688_write(chip, 0xb8, 4);	/* auto init DMA mode */353	snd_es1688_write(chip, 0xa8, (snd_es1688_read(chip, 0xa8) & ~0x03) | (3 - runtime->channels));354	snd_es1688_write(chip, 0xb9, 2);	/* demand mode (4 bytes/request) */355	if (runtime->channels == 1) {356		if (snd_pcm_format_width(runtime->format) == 8) {357			/* 8. bit mono */358			snd_es1688_write(chip, 0xb6, 0x80);359			snd_es1688_write(chip, 0xb7, 0x51);360			snd_es1688_write(chip, 0xb7, 0xd0);361		} else {362			/* 16. bit mono */363			snd_es1688_write(chip, 0xb6, 0x00);364			snd_es1688_write(chip, 0xb7, 0x71);365			snd_es1688_write(chip, 0xb7, 0xf4);366		}367	} else {368		if (snd_pcm_format_width(runtime->format) == 8) {369			/* 8. bit stereo */370			snd_es1688_write(chip, 0xb6, 0x80);371			snd_es1688_write(chip, 0xb7, 0x51);372			snd_es1688_write(chip, 0xb7, 0x98);373		} else {374			/* 16. bit stereo */375			snd_es1688_write(chip, 0xb6, 0x00);376			snd_es1688_write(chip, 0xb7, 0x71);377			snd_es1688_write(chip, 0xb7, 0xbc);378		}379	}380	snd_es1688_write(chip, 0xb1, (snd_es1688_read(chip, 0xb1) & 0x0f) | 0x50);381	snd_es1688_write(chip, 0xb2, (snd_es1688_read(chip, 0xb2) & 0x0f) | 0x50);382	snd_es1688_dsp_command(chip, ES1688_DSP_CMD_SPKON);383	spin_unlock_irqrestore(&chip->reg_lock, flags);384	/* --- */385	count = -count;386	snd_dma_program(chip->dma8, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);387	spin_lock_irqsave(&chip->reg_lock, flags);388	snd_es1688_write(chip, 0xa4, (unsigned char) count);389	snd_es1688_write(chip, 0xa5, (unsigned char) (count >> 8));390	spin_unlock_irqrestore(&chip->reg_lock, flags);391	return 0;392}393 394static int snd_es1688_playback_trigger(struct snd_pcm_substream *substream,395				       int cmd)396{397	struct snd_es1688 *chip = snd_pcm_substream_chip(substream);398	return snd_es1688_trigger(chip, cmd, 0x05);399}400 401static int snd_es1688_capture_prepare(struct snd_pcm_substream *substream)402{403	unsigned long flags;404	struct snd_es1688 *chip = snd_pcm_substream_chip(substream);405	struct snd_pcm_runtime *runtime = substream->runtime;406	unsigned int size = snd_pcm_lib_buffer_bytes(substream);407	unsigned int count = snd_pcm_lib_period_bytes(substream);408 409	chip->dma_size = size;410	spin_lock_irqsave(&chip->reg_lock, flags);411	snd_es1688_reset(chip);412	snd_es1688_set_rate(chip, substream);413	snd_es1688_dsp_command(chip, ES1688_DSP_CMD_SPKOFF);414	snd_es1688_write(chip, 0xb8, 0x0e);	/* auto init DMA mode */415	snd_es1688_write(chip, 0xa8, (snd_es1688_read(chip, 0xa8) & ~0x03) | (3 - runtime->channels));416	snd_es1688_write(chip, 0xb9, 2);	/* demand mode (4 bytes/request) */417	if (runtime->channels == 1) {418		if (snd_pcm_format_width(runtime->format) == 8) {419			/* 8. bit mono */420			snd_es1688_write(chip, 0xb7, 0x51);421			snd_es1688_write(chip, 0xb7, 0xd0);422		} else {423			/* 16. bit mono */424			snd_es1688_write(chip, 0xb7, 0x71);425			snd_es1688_write(chip, 0xb7, 0xf4);426		}427	} else {428		if (snd_pcm_format_width(runtime->format) == 8) {429			/* 8. bit stereo */430			snd_es1688_write(chip, 0xb7, 0x51);431			snd_es1688_write(chip, 0xb7, 0x98);432		} else {433			/* 16. bit stereo */434			snd_es1688_write(chip, 0xb7, 0x71);435			snd_es1688_write(chip, 0xb7, 0xbc);436		}437	}438	snd_es1688_write(chip, 0xb1, (snd_es1688_read(chip, 0xb1) & 0x0f) | 0x50);439	snd_es1688_write(chip, 0xb2, (snd_es1688_read(chip, 0xb2) & 0x0f) | 0x50);440	spin_unlock_irqrestore(&chip->reg_lock, flags);441	/* --- */442	count = -count;443	snd_dma_program(chip->dma8, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);444	spin_lock_irqsave(&chip->reg_lock, flags);445	snd_es1688_write(chip, 0xa4, (unsigned char) count);446	snd_es1688_write(chip, 0xa5, (unsigned char) (count >> 8));447	spin_unlock_irqrestore(&chip->reg_lock, flags);448	return 0;449}450 451static int snd_es1688_capture_trigger(struct snd_pcm_substream *substream,452				      int cmd)453{454	struct snd_es1688 *chip = snd_pcm_substream_chip(substream);455	return snd_es1688_trigger(chip, cmd, 0x0f);456}457 458static irqreturn_t snd_es1688_interrupt(int irq, void *dev_id)459{460	struct snd_es1688 *chip = dev_id;461 462	if (chip->trigger_value == 0x05)	/* ok.. playback is active */463		snd_pcm_period_elapsed(chip->playback_substream);464	if (chip->trigger_value == 0x0f)	/* ok.. capture is active */465		snd_pcm_period_elapsed(chip->capture_substream);466 467	inb(ES1688P(chip, DATA_AVAIL));	/* ack interrupt */468	return IRQ_HANDLED;469}470 471static snd_pcm_uframes_t snd_es1688_playback_pointer(struct snd_pcm_substream *substream)472{473	struct snd_es1688 *chip = snd_pcm_substream_chip(substream);474	size_t ptr;475	476	if (chip->trigger_value != 0x05)477		return 0;478	ptr = snd_dma_pointer(chip->dma8, chip->dma_size);479	return bytes_to_frames(substream->runtime, ptr);480}481 482static snd_pcm_uframes_t snd_es1688_capture_pointer(struct snd_pcm_substream *substream)483{484	struct snd_es1688 *chip = snd_pcm_substream_chip(substream);485	size_t ptr;486	487	if (chip->trigger_value != 0x0f)488		return 0;489	ptr = snd_dma_pointer(chip->dma8, chip->dma_size);490	return bytes_to_frames(substream->runtime, ptr);491}492 493/*494 495 */496 497static const struct snd_pcm_hardware snd_es1688_playback =498{499	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |500				 SNDRV_PCM_INFO_MMAP_VALID),501	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,502	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,503	.rate_min =		4000,504	.rate_max =		48000,505	.channels_min =		1,506	.channels_max =		2,507	.buffer_bytes_max =	65536,508	.period_bytes_min =	64,509	.period_bytes_max =	65536,510	.periods_min =		1,511	.periods_max =		1024,512	.fifo_size =		0,513};514 515static const struct snd_pcm_hardware snd_es1688_capture =516{517	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |518				 SNDRV_PCM_INFO_MMAP_VALID),519	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,520	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,521	.rate_min =		4000,522	.rate_max =		48000,523	.channels_min =		1,524	.channels_max =		2,525	.buffer_bytes_max =	65536,526	.period_bytes_min =	64,527	.period_bytes_max =	65536,528	.periods_min =		1,529	.periods_max =		1024,530	.fifo_size =		0,531};532 533/*534 535 */536 537static int snd_es1688_playback_open(struct snd_pcm_substream *substream)538{539	struct snd_es1688 *chip = snd_pcm_substream_chip(substream);540	struct snd_pcm_runtime *runtime = substream->runtime;541 542	if (chip->capture_substream != NULL)543		return -EAGAIN;544	chip->playback_substream = substream;545	runtime->hw = snd_es1688_playback;546	snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,547				      &hw_constraints_clocks);548	return 0;549}550 551static int snd_es1688_capture_open(struct snd_pcm_substream *substream)552{553	struct snd_es1688 *chip = snd_pcm_substream_chip(substream);554	struct snd_pcm_runtime *runtime = substream->runtime;555 556	if (chip->playback_substream != NULL)557		return -EAGAIN;558	chip->capture_substream = substream;559	runtime->hw = snd_es1688_capture;560	snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,561				      &hw_constraints_clocks);562	return 0;563}564 565static int snd_es1688_playback_close(struct snd_pcm_substream *substream)566{567	struct snd_es1688 *chip = snd_pcm_substream_chip(substream);568 569	chip->playback_substream = NULL;570	return 0;571}572 573static int snd_es1688_capture_close(struct snd_pcm_substream *substream)574{575	struct snd_es1688 *chip = snd_pcm_substream_chip(substream);576 577	chip->capture_substream = NULL;578	return 0;579}580 581static int snd_es1688_free(struct snd_es1688 *chip)582{583	if (chip->hardware != ES1688_HW_UNDEF)584		snd_es1688_init(chip, 0);585	release_and_free_resource(chip->res_port);586	if (chip->irq >= 0)587		free_irq(chip->irq, (void *) chip);588	if (chip->dma8 >= 0) {589		disable_dma(chip->dma8);590		free_dma(chip->dma8);591	}592	return 0;593}594 595static int snd_es1688_dev_free(struct snd_device *device)596{597	struct snd_es1688 *chip = device->device_data;598	return snd_es1688_free(chip);599}600 601static const char *snd_es1688_chip_id(struct snd_es1688 *chip)602{603	static char tmp[16];604	sprintf(tmp, "ES%s688 rev %i", chip->hardware == ES1688_HW_688 ? "" : "1", chip->version & 0x0f);605	return tmp;606}607 608int snd_es1688_create(struct snd_card *card,609		      struct snd_es1688 *chip,610		      unsigned long port,611		      unsigned long mpu_port,612		      int irq,613		      int mpu_irq,614		      int dma8,615		      unsigned short hardware)616{617	static const struct snd_device_ops ops = {618		.dev_free =	snd_es1688_dev_free,619	};620                                621	int err;622 623	if (chip == NULL)624		return -ENOMEM;625	chip->card = card;626	chip->irq = -1;627	chip->dma8 = -1;628	chip->hardware = ES1688_HW_UNDEF;629	630	chip->res_port = request_region(port + 4, 12, "ES1688");631	if (chip->res_port == NULL) {632		dev_err(card->dev, "es1688: can't grab port 0x%lx\n", port + 4);633		err = -EBUSY;634		goto exit;635	}636 637	err = request_irq(irq, snd_es1688_interrupt, 0, "ES1688", (void *) chip);638	if (err < 0) {639		dev_err(card->dev, "es1688: can't grab IRQ %d\n", irq);640		goto exit;641	}642 643	chip->irq = irq;644	card->sync_irq = chip->irq;645	err = request_dma(dma8, "ES1688");646 647	if (err < 0) {648		dev_err(card->dev, "es1688: can't grab DMA8 %d\n", dma8);649		goto exit;650	}651	chip->dma8 = dma8;652 653	spin_lock_init(&chip->reg_lock);654	spin_lock_init(&chip->mixer_lock);655	chip->port = port;656	mpu_port &= ~0x000f;657	if (mpu_port < 0x300 || mpu_port > 0x330)658		mpu_port = 0;659	chip->mpu_port = mpu_port;660	chip->mpu_irq = mpu_irq;661	chip->hardware = hardware;662 663	err = snd_es1688_probe(chip);664	if (err < 0)665		goto exit;666 667	err = snd_es1688_init(chip, 1);668	if (err < 0)669		goto exit;670 671	/* Register device */672	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);673exit:674	if (err)675		snd_es1688_free(chip);676	return err;677}678 679static const struct snd_pcm_ops snd_es1688_playback_ops = {680	.open =			snd_es1688_playback_open,681	.close =		snd_es1688_playback_close,682	.prepare =		snd_es1688_playback_prepare,683	.trigger =		snd_es1688_playback_trigger,684	.pointer =		snd_es1688_playback_pointer,685};686 687static const struct snd_pcm_ops snd_es1688_capture_ops = {688	.open =			snd_es1688_capture_open,689	.close =		snd_es1688_capture_close,690	.prepare =		snd_es1688_capture_prepare,691	.trigger =		snd_es1688_capture_trigger,692	.pointer =		snd_es1688_capture_pointer,693};694 695int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, int device)696{697	struct snd_pcm *pcm;698	int err;699 700	err = snd_pcm_new(card, "ESx688", device, 1, 1, &pcm);701	if (err < 0)702		return err;703 704	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_es1688_playback_ops);705	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_es1688_capture_ops);706 707	pcm->private_data = chip;708	pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;709	strcpy(pcm->name, snd_es1688_chip_id(chip));710	chip->pcm = pcm;711 712	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, card->dev,713				       64*1024, 64*1024);714	return 0;715}716 717/*718 *  MIXER part719 */720 721static int snd_es1688_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)722{723	static const char * const texts[8] = {724		"Mic", "Mic Master", "CD", "AOUT",725		"Mic1", "Mix", "Line", "Master"726	};727 728	return snd_ctl_enum_info(uinfo, 1, 8, texts);729}730 731static int snd_es1688_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)732{733	struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol);734	ucontrol->value.enumerated.item[0] = snd_es1688_mixer_read(chip, ES1688_REC_DEV) & 7;735	return 0;736}737 738static int snd_es1688_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)739{740	struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol);741	unsigned long flags;742	unsigned char oval, nval;743	int change;744	745	if (ucontrol->value.enumerated.item[0] > 8)746		return -EINVAL;747	spin_lock_irqsave(&chip->reg_lock, flags);748	oval = snd_es1688_mixer_read(chip, ES1688_REC_DEV);749	nval = (ucontrol->value.enumerated.item[0] & 7) | (oval & ~15);750	change = nval != oval;751	if (change)752		snd_es1688_mixer_write(chip, ES1688_REC_DEV, nval);753	spin_unlock_irqrestore(&chip->reg_lock, flags);754	return change;755}756 757#define ES1688_SINGLE(xname, xindex, reg, shift, mask, invert) \758{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \759  .info = snd_es1688_info_single, \760  .get = snd_es1688_get_single, .put = snd_es1688_put_single, \761  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }762 763static int snd_es1688_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)764{765	int mask = (kcontrol->private_value >> 16) & 0xff;766 767	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;768	uinfo->count = 1;769	uinfo->value.integer.min = 0;770	uinfo->value.integer.max = mask;771	return 0;772}773 774static int snd_es1688_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)775{776	struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol);777	unsigned long flags;778	int reg = kcontrol->private_value & 0xff;779	int shift = (kcontrol->private_value >> 8) & 0xff;780	int mask = (kcontrol->private_value >> 16) & 0xff;781	int invert = (kcontrol->private_value >> 24) & 0xff;782	783	spin_lock_irqsave(&chip->reg_lock, flags);784	ucontrol->value.integer.value[0] = (snd_es1688_mixer_read(chip, reg) >> shift) & mask;785	spin_unlock_irqrestore(&chip->reg_lock, flags);786	if (invert)787		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];788	return 0;789}790 791static int snd_es1688_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)792{793	struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol);794	unsigned long flags;795	int reg = kcontrol->private_value & 0xff;796	int shift = (kcontrol->private_value >> 8) & 0xff;797	int mask = (kcontrol->private_value >> 16) & 0xff;798	int invert = (kcontrol->private_value >> 24) & 0xff;799	int change;800	unsigned char oval, nval;801	802	nval = (ucontrol->value.integer.value[0] & mask);803	if (invert)804		nval = mask - nval;805	nval <<= shift;806	spin_lock_irqsave(&chip->reg_lock, flags);807	oval = snd_es1688_mixer_read(chip, reg);808	nval = (oval & ~(mask << shift)) | nval;809	change = nval != oval;810	if (change)811		snd_es1688_mixer_write(chip, reg, nval);812	spin_unlock_irqrestore(&chip->reg_lock, flags);813	return change;814}815 816#define ES1688_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \817{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \818  .info = snd_es1688_info_double, \819  .get = snd_es1688_get_double, .put = snd_es1688_put_double, \820  .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }821 822static int snd_es1688_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)823{824	int mask = (kcontrol->private_value >> 24) & 0xff;825 826	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;827	uinfo->count = 2;828	uinfo->value.integer.min = 0;829	uinfo->value.integer.max = mask;830	return 0;831}832 833static int snd_es1688_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)834{835	struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol);836	unsigned long flags;837	int left_reg = kcontrol->private_value & 0xff;838	int right_reg = (kcontrol->private_value >> 8) & 0xff;839	int shift_left = (kcontrol->private_value >> 16) & 0x07;840	int shift_right = (kcontrol->private_value >> 19) & 0x07;841	int mask = (kcontrol->private_value >> 24) & 0xff;842	int invert = (kcontrol->private_value >> 22) & 1;843	unsigned char left, right;844	845	spin_lock_irqsave(&chip->reg_lock, flags);846	if (left_reg < 0xa0)847		left = snd_es1688_mixer_read(chip, left_reg);848	else849		left = snd_es1688_read(chip, left_reg);850	if (left_reg != right_reg) {851		if (right_reg < 0xa0) 852			right = snd_es1688_mixer_read(chip, right_reg);853		else854			right = snd_es1688_read(chip, right_reg);855	} else856		right = left;857	spin_unlock_irqrestore(&chip->reg_lock, flags);858	ucontrol->value.integer.value[0] = (left >> shift_left) & mask;859	ucontrol->value.integer.value[1] = (right >> shift_right) & mask;860	if (invert) {861		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];862		ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];863	}864	return 0;865}866 867static int snd_es1688_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)868{869	struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol);870	unsigned long flags;871	int left_reg = kcontrol->private_value & 0xff;872	int right_reg = (kcontrol->private_value >> 8) & 0xff;873	int shift_left = (kcontrol->private_value >> 16) & 0x07;874	int shift_right = (kcontrol->private_value >> 19) & 0x07;875	int mask = (kcontrol->private_value >> 24) & 0xff;876	int invert = (kcontrol->private_value >> 22) & 1;877	int change;878	unsigned char val1, val2, oval1, oval2;879	880	val1 = ucontrol->value.integer.value[0] & mask;881	val2 = ucontrol->value.integer.value[1] & mask;882	if (invert) {883		val1 = mask - val1;884		val2 = mask - val2;885	}886	val1 <<= shift_left;887	val2 <<= shift_right;888	spin_lock_irqsave(&chip->reg_lock, flags);889	if (left_reg != right_reg) {890		if (left_reg < 0xa0)891			oval1 = snd_es1688_mixer_read(chip, left_reg);892		else893			oval1 = snd_es1688_read(chip, left_reg);894		if (right_reg < 0xa0)895			oval2 = snd_es1688_mixer_read(chip, right_reg);896		else897			oval2 = snd_es1688_read(chip, right_reg);898		val1 = (oval1 & ~(mask << shift_left)) | val1;899		val2 = (oval2 & ~(mask << shift_right)) | val2;900		change = val1 != oval1 || val2 != oval2;901		if (change) {902			if (left_reg < 0xa0)903				snd_es1688_mixer_write(chip, left_reg, val1);904			else905				snd_es1688_write(chip, left_reg, val1);906			if (right_reg < 0xa0)907				snd_es1688_mixer_write(chip, right_reg, val1);908			else909				snd_es1688_write(chip, right_reg, val1);910		}911	} else {912		if (left_reg < 0xa0)913			oval1 = snd_es1688_mixer_read(chip, left_reg);914		else915			oval1 = snd_es1688_read(chip, left_reg);916		val1 = (oval1 & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2;917		change = val1 != oval1;918		if (change) {919			if (left_reg < 0xa0)920				snd_es1688_mixer_write(chip, left_reg, val1);921			else922				snd_es1688_write(chip, left_reg, val1);923		}924			925	}926	spin_unlock_irqrestore(&chip->reg_lock, flags);927	return change;928}929 930static const struct snd_kcontrol_new snd_es1688_controls[] = {931ES1688_DOUBLE("Master Playback Volume", 0, ES1688_MASTER_DEV, ES1688_MASTER_DEV, 4, 0, 15, 0),932ES1688_DOUBLE("PCM Playback Volume", 0, ES1688_PCM_DEV, ES1688_PCM_DEV, 4, 0, 15, 0),933ES1688_DOUBLE("Line Playback Volume", 0, ES1688_LINE_DEV, ES1688_LINE_DEV, 4, 0, 15, 0),934ES1688_DOUBLE("CD Playback Volume", 0, ES1688_CD_DEV, ES1688_CD_DEV, 4, 0, 15, 0),935ES1688_DOUBLE("FM Playback Volume", 0, ES1688_FM_DEV, ES1688_FM_DEV, 4, 0, 15, 0),936ES1688_DOUBLE("Mic Playback Volume", 0, ES1688_MIC_DEV, ES1688_MIC_DEV, 4, 0, 15, 0),937ES1688_DOUBLE("Aux Playback Volume", 0, ES1688_AUX_DEV, ES1688_AUX_DEV, 4, 0, 15, 0),938ES1688_SINGLE("Beep Playback Volume", 0, ES1688_SPEAKER_DEV, 0, 7, 0),939ES1688_DOUBLE("Capture Volume", 0, ES1688_RECLEV_DEV, ES1688_RECLEV_DEV, 4, 0, 15, 0),940ES1688_SINGLE("Capture Switch", 0, ES1688_REC_DEV, 4, 1, 1),941{942	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,943	.name = "Capture Source",944	.info = snd_es1688_info_mux,945	.get = snd_es1688_get_mux,946	.put = snd_es1688_put_mux,947},948};949 950#define ES1688_INIT_TABLE_SIZE (sizeof(snd_es1688_init_table)/2)951 952static const unsigned char snd_es1688_init_table[][2] = {953	{ ES1688_MASTER_DEV, 0 },954	{ ES1688_PCM_DEV, 0 },955	{ ES1688_LINE_DEV, 0 },956	{ ES1688_CD_DEV, 0 },957	{ ES1688_FM_DEV, 0 },958	{ ES1688_MIC_DEV, 0 },959	{ ES1688_AUX_DEV, 0 },960	{ ES1688_SPEAKER_DEV, 0 },961	{ ES1688_RECLEV_DEV, 0 },962	{ ES1688_REC_DEV, 0x17 }963};964                                        965int snd_es1688_mixer(struct snd_card *card, struct snd_es1688 *chip)966{967	unsigned int idx;968	int err;969	unsigned char reg, val;970 971	if (snd_BUG_ON(!chip || !card))972		return -EINVAL;973 974	strcpy(card->mixername, snd_es1688_chip_id(chip));975 976	for (idx = 0; idx < ARRAY_SIZE(snd_es1688_controls); idx++) {977		err = snd_ctl_add(card, snd_ctl_new1(&snd_es1688_controls[idx], chip));978		if (err < 0)979			return err;980	}981	for (idx = 0; idx < ES1688_INIT_TABLE_SIZE; idx++) {982		reg = snd_es1688_init_table[idx][0];983		val = snd_es1688_init_table[idx][1];984		if (reg < 0xa0)985			snd_es1688_mixer_write(chip, reg, val);986		else987			snd_es1688_write(chip, reg, val);988	}989	return 0;990}991 992EXPORT_SYMBOL(snd_es1688_mixer_write);993EXPORT_SYMBOL(snd_es1688_create);994EXPORT_SYMBOL(snd_es1688_pcm);995EXPORT_SYMBOL(snd_es1688_mixer);996