From d56b9b9c464a10ab1ee51a4c6190a2b57b8ef7a6 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 4 Oct 2006 02:17:22 -0700 Subject: [PATCH] The scheduled removal of some OSS drivers This patch contains the scheduled removal of OSS drivers that: - have ALSA drivers for the same hardware without known regressions and - whose Kconfig options have been removed in 2.6.17. [michal.k.k.piotrowski@gmail.com: build fix] Signed-off-by: Adrian Bunk Signed-off-by: Michal Piotrowski Cc: David Woodhouse Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/oss/maestro.c | 3686 --------------------------------------------------- 1 file changed, 3686 deletions(-) delete mode 100644 sound/oss/maestro.c (limited to 'sound/oss/maestro.c') diff --git a/sound/oss/maestro.c b/sound/oss/maestro.c deleted file mode 100644 index 1d98d100d739..000000000000 --- a/sound/oss/maestro.c +++ /dev/null @@ -1,3686 +0,0 @@ -/***************************************************************************** - * - * ESS Maestro/Maestro-2/Maestro-2E driver for Linux 2.[23].x - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * (c) Copyright 1999 Alan Cox - * - * Based heavily on SonicVibes.c: - * Copyright (C) 1998-1999 Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * Heavily modified by Zach Brown based on lunch - * with ESS engineers. Many thanks to Howard Kim for providing - * contacts and hardware. Honorable mention goes to Eric - * Brombaugh for all sorts of things. Best regards to the - * proprietors of Hack Central for fine lodging. - * - * Supported devices: - * /dev/dsp0-3 standard /dev/dsp device, (mostly) OSS compatible - * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible - * - * Hardware Description - * - * A working Maestro setup contains the Maestro chip wired to a - * codec or 2. In the Maestro we have the APUs, the ASSP, and the - * Wavecache. The APUs can be though of as virtual audio routing - * channels. They can take data from a number of sources and perform - * basic encodings of the data. The wavecache is a storehouse for - * PCM data. Typically it deals with PCI and interracts with the - * APUs. The ASSP is a wacky DSP like device that ESS is loth - * to release docs on. Thankfully it isn't required on the Maestro - * until you start doing insane things like FM emulation and surround - * encoding. The codecs are almost always AC-97 compliant codecs, - * but it appears that early Maestros may have had PT101 (an ESS - * part?) wired to them. The only real difference in the Maestro - * families is external goop like docking capability, memory for - * the ASSP, and initialization differences. - * - * Driver Operation - * - * We only drive the APU/Wavecache as typical DACs and drive the - * mixers in the codecs. There are 64 APUs. We assign 6 to each - * /dev/dsp? device. 2 channels for output, and 4 channels for - * input. - * - * Each APU can do a number of things, but we only really use - * 3 basic functions. For playback we use them to convert PCM - * data fetched over PCI by the wavecahche into analog data that - * is handed to the codec. One APU for mono, and a pair for stereo. - * When in stereo, the combination of smarts in the APU and Wavecache - * decide which wavecache gets the left or right channel. - * - * For record we still use the old overly mono system. For each in - * coming channel the data comes in from the codec, through a 'input' - * APU, through another rate converter APU, and then into memory via - * the wavecache and PCI. If its stereo, we mash it back into LRLR in - * software. The pass between the 2 APUs is supposedly what requires us - * to have a 512 byte buffer sitting around in wavecache/memory. - * - * The wavecache makes our life even more fun. First off, it can - * only address the first 28 bits of PCI address space, making it - * useless on quite a few architectures. Secondly, its insane. - * It claims to fetch from 4 regions of PCI space, each 4 meg in length. - * But that doesn't really work. You can only use 1 region. So all our - * allocations have to be in 4meg of each other. Booo. Hiss. - * So we have a module parameter, dsps_order, that is the order of - * the number of dsps to provide. All their buffer space is allocated - * on open time. The sonicvibes OSS routines we inherited really want - * power of 2 buffers, so we have all those next to each other, then - * 512 byte regions for the recording wavecaches. This ends up - * wasting quite a bit of memory. The only fixes I can see would be - * getting a kernel allocator that could work in zones, or figuring out - * just how to coerce the WP into doing what we want. - * - * The indirection of the various registers means we have to spinlock - * nearly all register accesses. We have the main register indirection - * like the wave cache, maestro registers, etc. Then we have beasts - * like the APU interface that is indirect registers gotten at through - * the main maestro indirection. Ouch. We spinlock around the actual - * ports on a per card basis. This means spinlock activity at each IO - * operation, but the only IO operation clusters are in non critical - * paths and it makes the code far easier to follow. Interrupts are - * blocked while holding the locks because the int handler has to - * get at some of them :(. The mixer interface doesn't, however. - * We also have an OSS state lock that is thrown around in a few - * places. - * - * This driver has brute force APM suspend support. We catch suspend - * notifications and stop all work being done on the chip. Any people - * that try between this shutdown and the real suspend operation will - * be put to sleep. When we resume we restore our software state on - * the chip and wake up the people that were using it. The code thats - * being used now is quite dirty and assumes we're on a uni-processor - * machine. Much of it will need to be cleaned up for SMP ACPI or - * similar. - * - * We also pay attention to PCI power management now. The driver - * will power down units of the chip that it knows aren't needed. - * The WaveProcessor and company are only powered on when people - * have /dev/dsp*s open. On removal the driver will - * power down the maestro entirely. There could still be - * trouble with BIOSen that magically change power states - * themselves, but we'll see. - * - * History - * v0.15 - May 21 2001 - Marcus Meissner - * Ported to Linux 2.4 PCI API. Some clean ups, global devs list - * removed (now using pci device driver data). - * PM needs to be polished still. Bumped version. - * (still kind of v0.14) May 13 2001 - Ben Pfaff - * Add support for 978 docking and basic hardware volume control - * (still kind of v0.14) Nov 23 - Alan Cox - * Add clocking= for people with seriously warped hardware - * (still v0.14) Nov 10 2000 - Bartlomiej Zolnierkiewicz - * add __init to maestro_ac97_init() and maestro_install() - * (still based on v0.14) Mar 29 2000 - Zach Brown - * move to 2.3 power management interface, which - * required hacking some suspend/resume/check paths - * make static compilation work - * v0.14 - Jan 28 2000 - Zach Brown - * add PCI power management through ACPI regs. - * we now shut down on machine reboot/halt - * leave scary PCI config items alone (isa stuff, mostly) - * enable 1921s, it seems only mine was broke. - * fix swapped left/right pcm dac. har har. - * up bob freq, increase buffers, fix pointers at underflow - * silly compilation problems - * v0.13 - Nov 18 1999 - Zach Brown - * fix nec Versas? man would that be cool. - * v0.12 - Nov 12 1999 - Zach Brown - * brown bag volume max fix.. - * v0.11 - Nov 11 1999 - Zach Brown - * use proper stereo apu decoding, mmap/write should work. - * make volume sliders more useful, tweak rate calculation. - * fix lame 8bit format reporting bug. duh. apm apu saving buglet also - * fix maestro 1 clock freq "bug", remove pt101 support - * v0.10 - Oct 28 1999 - Zach Brown - * aha, so, sometimes the WP writes a status word to offset 0 - * from one of the PCMBARs. rearrange allocation accordingly.. - * cheers again to Eric for being a good hacker in investigating this. - * Jeroen Hoogervorst submits 7500 fix out of nowhere. yay. :) - * v0.09 - Oct 23 1999 - Zach Brown - * added APM support. - * re-order something such that some 2Es now work. Magic! - * new codec reset routine. made some codecs come to life. - * fix clear_advance, sync some control with ESS. - * now write to all base regs to be paranoid. - * v0.08 - Oct 20 1999 - Zach Brown - * Fix initial buflen bug. I am so smart. also smp compiling.. - * I owe Eric yet another beer: fixed recmask, igain, - * muting, and adc sync consistency. Go Team. - * v0.07 - Oct 4 1999 - Zach Brown - * tweak adc/dac, formating, and stuff to allow full duplex - * allocate dsps memory at open() so we can fit in the wavecache window - * fix wavecache braindamage. again. no more scribbling? - * fix ess 1921 codec bug on some laptops. - * fix dumb pci scanning bug - * started 2.3 cleanup, redid spinlocks, little cleanups - * v0.06 - Sep 20 1999 - Zach Brown - * fix wavecache thinkos. limit to 1 /dev/dsp. - * eric is wearing his thinking toque this week. - * spotted apu mode bugs and gain ramping problem - * don't touch weird mixer regs, make recmask optional - * fixed igain inversion, defaults for mixers, clean up rec_start - * make mono recording work. - * report subsystem stuff, please send reports. - * littles: parallel out, amp now - * v0.05 - Sep 17 1999 - Zach Brown - * merged and fixed up Eric's initial recording code - * munged format handling to catch misuse, needs rewrite. - * revert ring bus init, fixup shared int, add pci busmaster setting - * fix mixer oss interface, fix mic mute and recmask - * mask off unsupported mixers, reset with all 1s, modularize defaults - * make sure bob is running while we need it - * got rid of device limit, initial minimal apm hooks - * pull out dead code/includes, only allow multimedia/audio maestros - * v0.04 - Sep 01 1999 - Zach Brown - * copied memory leak fix from sonicvibes driver - * different ac97 reset, play with 2.0 ac97, simplify ring bus setup - * bob freq code, region sanity, jitter sync fix; all from Eric - * - * TODO - * fix bob frequency - * endianness - * do smart things with ac97 2.0 bits. - * dual codecs - * leave 54->61 open - * - * it also would be fun to have a mode that would not use pci dma at all - * but would copy into the wavecache on board memory and use that - * on architectures that don't like the maestro's pci dma ickiness. - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include -#include -#include -#include -#include - -#include "maestro.h" - -static struct pci_driver maestro_pci_driver; - -/* --------------------------------------------------------------------- */ - -#define M_DEBUG 1 - -#ifdef M_DEBUG -static int debug; -#define M_printk(args...) {if (debug) printk(args);} -#else -#define M_printk(x) -#endif - -/* we try to setup 2^(dsps_order) /dev/dsp devices */ -static int dsps_order; -/* whether or not we mess around with power management */ -static int use_pm=2; /* set to 1 for force */ -/* clocking for broken hardware - a few laptops seem to use a 50Khz clock - ie insmod with clocking=50000 or so */ - -static int clocking=48000; - -MODULE_AUTHOR("Zach Brown , Alan Cox "); -MODULE_DESCRIPTION("ESS Maestro Driver"); -MODULE_LICENSE("GPL"); - -#ifdef M_DEBUG -module_param(debug, bool, 0644); -#endif -module_param(dsps_order, int, 0); -module_param(use_pm, int, 0); -module_param(clocking, int, 0); - -/* --------------------------------------------------------------------- */ -#define DRIVER_VERSION "0.15" - -#ifndef PCI_VENDOR_ESS -#define PCI_VENDOR_ESS 0x125D -#define PCI_DEVICE_ID_ESS_ESS1968 0x1968 /* Maestro 2 */ -#define PCI_DEVICE_ID_ESS_ESS1978 0x1978 /* Maestro 2E */ - -#define PCI_VENDOR_ESS_OLD 0x1285 /* Platform Tech, - the people the maestro - was bought from */ -#define PCI_DEVICE_ID_ESS_ESS0100 0x0100 /* maestro 1 */ -#endif /* PCI_VENDOR_ESS */ - -#define ESS_CHAN_HARD 0x100 - -/* NEC Versas ? */ -#define NEC_VERSA_SUBID1 0x80581033 -#define NEC_VERSA_SUBID2 0x803c1033 - - -/* changed so that I could actually find all the - references and fix them up. it's a little more readable now. */ -#define ESS_FMT_STEREO 0x01 -#define ESS_FMT_16BIT 0x02 -#define ESS_FMT_MASK 0x03 -#define ESS_DAC_SHIFT 0 -#define ESS_ADC_SHIFT 4 - -#define ESS_STATE_MAGIC 0x125D1968 -#define ESS_CARD_MAGIC 0x19283746 - -#define DAC_RUNNING 1 -#define ADC_RUNNING 2 - -#define MAX_DSP_ORDER 2 -#define MAX_DSPS (1<src buffer page */ - void *mixbuf; - -}; - -struct ess_card { - unsigned int magic; - - /* We keep maestro cards in a linked list */ - struct ess_card *next; - - int dev_mixer; - - int card_type; - - /* as most of this is static, - perhaps it should be a pointer to a global struct */ - struct mixer_goo { - int modcnt; - int supported_mixers; - int stereo_mixers; - int record_sources; - /* the caller must guarantee arg sanity before calling these */ -/* int (*read_mixer)(struct ess_card *card, int index);*/ - void (*write_mixer)(struct ess_card *card,int mixer, unsigned int left,unsigned int right); - int (*recmask_io)(struct ess_card *card,int rw,int mask); - unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; - } mix; - - int power_regs; - - int in_suspend; - wait_queue_head_t suspend_queue; - - struct ess_state channels[MAX_DSPS]; - u16 maestro_map[NR_IDRS]; /* Register map */ - /* we have to store this junk so that we can come back from a - suspend */ - u16 apu_map[NR_APUS][NR_APU_REGS]; /* contents of apu regs */ - - /* this locks around the physical registers on the card */ - spinlock_t lock; - - /* memory for this card.. wavecache limited :(*/ - void *dmapages; - int dmaorder; - - /* hardware resources */ - struct pci_dev *pcidev; - u32 iobase; - u32 irq; - - int bob_freq; - char dsps_open; - - int dock_mute_vol; -}; - -static void set_mixer(struct ess_card *card,unsigned int mixer, unsigned int val ); - -static unsigned -ld2(unsigned int x) -{ - unsigned r = 0; - - if (x >= 0x10000) { - x >>= 16; - r += 16; - } - if (x >= 0x100) { - x >>= 8; - r += 8; - } - if (x >= 0x10) { - x >>= 4; - r += 4; - } - if (x >= 4) { - x >>= 2; - r += 2; - } - if (x >= 2) - r++; - return r; -} - - -/* --------------------------------------------------------------------- */ - -static void check_suspend(struct ess_card *card); - -/* --------------------------------------------------------------------- */ - - -/* - * ESS Maestro AC97 codec programming interface. - */ - -static void maestro_ac97_set(struct ess_card *card, u8 cmd, u16 val) -{ - int io = card->iobase; - int i; - /* - * Wait for the codec bus to be free - */ - - check_suspend(card); - - for(i=0;i<10000;i++) - { - if(!(inb(io+ESS_AC97_INDEX)&1)) - break; - } - /* - * Write the bus - */ - outw(val, io+ESS_AC97_DATA); - mdelay(1); - outb(cmd, io+ESS_AC97_INDEX); - mdelay(1); -} - -static u16 maestro_ac97_get(struct ess_card *card, u8 cmd) -{ - int io = card->iobase; - int sanity=10000; - u16 data; - int i; - - check_suspend(card); - /* - * Wait for the codec bus to be free - */ - - for(i=0;i<10000;i++) - { - if(!(inb(io+ESS_AC97_INDEX)&1)) - break; - } - - outb(cmd|0x80, io+ESS_AC97_INDEX); - mdelay(1); - - while(inb(io+ESS_AC97_INDEX)&1) - { - sanity--; - if(!sanity) - { - printk(KERN_ERR "maestro: ac97 codec timeout reading 0x%x.\n",cmd); - return 0; - } - } - data=inw(io+ESS_AC97_DATA); - mdelay(1); - return data; -} - -/* OSS interface to the ac97s.. */ - -#define AC97_STEREO_MASK (SOUND_MASK_VOLUME|\ - SOUND_MASK_PCM|SOUND_MASK_LINE|SOUND_MASK_CD|\ - SOUND_MASK_VIDEO|SOUND_MASK_LINE1|SOUND_MASK_IGAIN) - -#define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \ - SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_MIC|\ - SOUND_MASK_SPEAKER) - -#define AC97_RECORD_MASK (SOUND_MASK_MIC|\ - SOUND_MASK_CD| SOUND_MASK_VIDEO| SOUND_MASK_LINE1| SOUND_MASK_LINE|\ - SOUND_MASK_PHONEIN) - -#define supported_mixer(CARD,FOO) ( CARD->mix.supported_mixers & (1<offset); - - if(AC97_STEREO_MASK & (1<> 8) & 0x7f; - right = val & 0x7f; - - if (mixer == SOUND_MIXER_IGAIN) { - right = (right * 100) / mh->scale; - left = (left * 100) / mh->scale; - } else { - right = 100 - ((right * 100) / mh->scale); - left = 100 - ((left * 100) / mh->scale); - } - - ret = left | (right << 8); - } else if (mixer == SOUND_MIXER_SPEAKER) { - ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale); - } else if (mixer == SOUND_MIXER_MIC) { - ret = 100 - (((val & 0x1f) * 100) / mh->scale); - /* the low bit is optional in the tone sliders and masking - it lets is avoid the 0xf 'bypass'.. */ - } else if (mixer == SOUND_MIXER_BASS) { - ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale); - } else if (mixer == SOUND_MIXER_TREBLE) { - ret = 100 - (((val & 0xe) * 100) / mh->scale); - } - - M_printk("read mixer %d (0x%x) %x -> %x\n",mixer,mh->offset,val,ret); - - return ret; -} -#endif - -/* write the OSS encoded volume to the given OSS encoded mixer, - again caller's job to make sure all is well in arg land, - call with spinlock held */ - -/* linear scale -> log */ -static unsigned char lin2log[101] = -{ -0, 0 , 15 , 23 , 30 , 34 , 38 , 42 , 45 , 47 , -50 , 52 , 53 , 55 , 57 , 58 , 60 , 61 , 62 , -63 , 65 , 66 , 67 , 68 , 69 , 69 , 70 , 71 , -72 , 73 , 73 , 74 , 75 , 75 , 76 , 77 , 77 , -78 , 78 , 79 , 80 , 80 , 81 , 81 , 82 , 82 , -83 , 83 , 84 , 84 , 84 , 85 , 85 , 86 , 86 , -87 , 87 , 87 , 88 , 88 , 88 , 89 , 89 , 89 , -90 , 90 , 90 , 91 , 91 , 91 , 92 , 92 , 92 , -93 , 93 , 93 , 94 , 94 , 94 , 94 , 95 , 95 , -95 , 95 , 96 , 96 , 96 , 96 , 97 , 97 , 97 , -97 , 98 , 98 , 98 , 98 , 99 , 99 , 99 , 99 , 99 -}; - -static void ac97_write_mixer(struct ess_card *card,int mixer, unsigned int left, unsigned int right) -{ - u16 val=0; - struct ac97_mixer_hw *mh = &ac97_hw[mixer]; - - M_printk("wrote mixer %d (0x%x) %d,%d",mixer,mh->offset,left,right); - - if(AC97_STEREO_MASK & (1<scale) / 100; - left = (left * mh->scale) / 100; - if ((left == 0) && (right == 0)) - val |= 0x8000; - } else if (mixer == SOUND_MIXER_PCM || mixer == SOUND_MIXER_CD) { - /* log conversion seems bad for them */ - if ((left == 0) && (right == 0)) - val = 0x8000; - right = ((100 - right) * mh->scale) / 100; - left = ((100 - left) * mh->scale) / 100; - } else { - /* log conversion for the stereo controls */ - if((left == 0) && (right == 0)) - val = 0x8000; - right = ((100 - lin2log[right]) * mh->scale) / 100; - left = ((100 - lin2log[left]) * mh->scale) / 100; - } - - val |= (left << 8) | right; - - } else if (mixer == SOUND_MIXER_SPEAKER) { - val = (((100 - left) * mh->scale) / 100) << 1; - } else if (mixer == SOUND_MIXER_MIC) { - val = maestro_ac97_get(card, mh->offset) & ~0x801f; - val |= (((100 - left) * mh->scale) / 100); - /* the low bit is optional in the tone sliders and masking - it lets is avoid the 0xf 'bypass'.. */ - } else if (mixer == SOUND_MIXER_BASS) { - val = maestro_ac97_get(card , mh->offset) & ~0x0f00; - val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00; - } else if (mixer == SOUND_MIXER_TREBLE) { - val = maestro_ac97_get(card , mh->offset) & ~0x000f; - val |= (((100 - left) * mh->scale) / 100) & 0x000e; - } - - maestro_ac97_set(card , mh->offset, val); - - M_printk(" -> %x\n",val); -} - -/* the following tables allow us to go from - OSS <-> ac97 quickly. */ - -enum ac97_recsettings { - AC97_REC_MIC=0, - AC97_REC_CD, - AC97_REC_VIDEO, - AC97_REC_AUX, - AC97_REC_LINE, - AC97_REC_STEREO, /* combination of all enabled outputs.. */ - AC97_REC_MONO, /*.. or the mono equivalent */ - AC97_REC_PHONE -}; - -static unsigned int ac97_oss_mask[] = { - [AC97_REC_MIC] = SOUND_MASK_MIC, - [AC97_REC_CD] = SOUND_MASK_CD, - [AC97_REC_VIDEO] = SOUND_MASK_VIDEO, - [AC97_REC_AUX] = SOUND_MASK_LINE1, - [AC97_REC_LINE] = SOUND_MASK_LINE, - [AC97_REC_PHONE] = SOUND_MASK_PHONEIN -}; - -/* indexed by bit position */ -static unsigned int ac97_oss_rm[] = { - [SOUND_MIXER_MIC] = AC97_REC_MIC, - [SOUND_MIXER_CD] = AC97_REC_CD, - [SOUND_MIXER_VIDEO] = AC97_REC_VIDEO, - [SOUND_MIXER_LINE1] = AC97_REC_AUX, - [SOUND_MIXER_LINE] = AC97_REC_LINE, - [SOUND_MIXER_PHONEIN] = AC97_REC_PHONE -}; - -/* read or write the recmask - the ac97 can really have left and right recording - inputs independently set, but OSS doesn't seem to - want us to express that to the user. - the caller guarantees that we have a supported bit set, - and they must be holding the card's spinlock */ -static int -ac97_recmask_io(struct ess_card *card, int read, int mask) -{ - unsigned int val = ac97_oss_mask[ maestro_ac97_get(card, 0x1a) & 0x7 ]; - - if (read) return val; - - /* oss can have many inputs, maestro can't. try - to pick the 'new' one */ - - if (mask != val) mask &= ~val; - - val = ffs(mask) - 1; - val = ac97_oss_rm[val]; - val |= val << 8; /* set both channels */ - - M_printk("maestro: setting ac97 recmask to 0x%x\n",val); - - maestro_ac97_set(card,0x1a,val); - - return 0; -}; - -/* - * The Maestro can be wired to a standard AC97 compliant codec - * (see www.intel.com for the pdf's on this), or to a PT101 codec - * which appears to be the ES1918 (data sheet on the esstech.com.tw site) - * - * The PT101 setup is untested. - */ - -static u16 __init maestro_ac97_init(struct ess_card *card) -{ - u16 vend1, vend2, caps; - - card->mix.supported_mixers = AC97_SUPPORTED_MASK; - card->mix.stereo_mixers = AC97_STEREO_MASK; - card->mix.record_sources = AC97_RECORD_MASK; -/* card->mix.read_mixer = ac97_read_mixer;*/ - card->mix.write_mixer = ac97_write_mixer; - card->mix.recmask_io = ac97_recmask_io; - - vend1 = maestro_ac97_get(card, 0x7c); - vend2 = maestro_ac97_get(card, 0x7e); - - caps = maestro_ac97_get(card, 0x00); - - printk(KERN_INFO "maestro: AC97 Codec detected: v: 0x%2x%2x caps: 0x%x pwr: 0x%x\n", - vend1,vend2,caps,maestro_ac97_get(card,0x26) & 0xf); - - if (! (caps & 0x4) ) { - /* no bass/treble nobs */ - card->mix.supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE); - } - - /* XXX endianness, dork head. */ - /* vendor specifc bits.. */ - switch ((long)(vend1 << 16) | vend2) { - case 0x545200ff: /* TriTech */ - /* no idea what this does */ - maestro_ac97_set(card,0x2a,0x0001); - maestro_ac97_set(card,0x2c,0x0000); - maestro_ac97_set(card,0x2c,0xffff); - break; -#if 0 /* i thought the problems I was seeing were with - the 1921, but apparently they were with the pci board - it was on, so this code is commented out. - lets see if this holds true. */ - case 0x83847609: /* ESS 1921 */ - /* writing to 0xe (mic) or 0x1a (recmask) seems - to hang this codec */ - card->mix.supported_mixers &= ~(SOUND_MASK_MIC); - card->mix.record_sources = 0; - card->mix.recmask_io = NULL; -#if 0 /* don't ask. I have yet to see what these actually do. */ - maestro_ac97_set(card,0x76,0xABBA); /* o/~ Take a chance on me o/~ */ - udelay(20); - maestro_ac97_set(card,0x78,0x3002); - udelay(20); - maestro_ac97_set(card,0x78,0x3802); - udelay(20); -#endif - break; -#endif - default: break; - } - - maestro_ac97_set(card, 0x1E, 0x0404); - /* null misc stuff */ - maestro_ac97_set(card, 0x20, 0x0000); - - return 0; -} - -#if 0 /* there has been 1 person on the planet with a pt101 that we - know of. If they care, they can put this back in :) */ -static u16 maestro_pt101_init(struct ess_card *card,int iobase) -{ - printk(KERN_INFO "maestro: PT101 Codec detected, initializing but _not_ installing mixer device.\n"); - /* who knows.. */ - maestro_ac97_set(iobase, 0x2A, 0x0001); - maestro_ac97_set(iobase, 0x2C, 0x0000); - maestro_ac97_set(iobase, 0x2C, 0xFFFF); - maestro_ac97_set(iobase, 0x10, 0x9F1F); - maestro_ac97_set(iobase, 0x12, 0x0808); - maestro_ac97_set(iobase, 0x14, 0x9F1F); - maestro_ac97_set(iobase, 0x16, 0x9F1F); - maestro_ac97_set(iobase, 0x18, 0x0404); - maestro_ac97_set(iobase, 0x1A, 0x0000); - maestro_ac97_set(iobase, 0x1C, 0x0000); - maestro_ac97_set(iobase, 0x02, 0x0404); - maestro_ac97_set(iobase, 0x04, 0x0808); - maestro_ac97_set(iobase, 0x0C, 0x801F); - maestro_ac97_set(iobase, 0x0E, 0x801F); - return 0; -} -#endif - -/* this is very magic, and very slow.. */ -static void -maestro_ac97_reset(int ioaddr, struct pci_dev *pcidev) -{ - u16 save_68; - u16 w; - u32 vend; - - outw( inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38); - outw( inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a); - outw( inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c); - - /* reset the first codec */ - outw(0x0000, ioaddr+0x36); - save_68 = inw(ioaddr+0x68); - pci_read_config_word(pcidev, 0x58, &w); /* something magical with gpio and bus arb. */ - pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &vend); - if( w & 0x1) - save_68 |= 0x10; - outw(0xfffe, ioaddr + 0x64); /* tickly gpio 0.. */ - outw(0x0001, ioaddr + 0x68); - outw(0x0000, ioaddr + 0x60); - udelay(20); - outw(0x0001, ioaddr + 0x60); - mdelay(20); - - outw(save_68 | 0x1, ioaddr + 0x68); /* now restore .. */ - outw( (inw(ioaddr + 0x38) & 0xfffc)|0x1, ioaddr + 0x38); - outw( (inw(ioaddr + 0x3a) & 0xfffc)|0x1, ioaddr + 0x3a); - outw( (inw(ioaddr + 0x3c) & 0xfffc)|0x1, ioaddr + 0x3c); - - /* now the second codec */ - outw(0x0000, ioaddr+0x36); - outw(0xfff7, ioaddr + 0x64); - save_68 = inw(ioaddr+0x68); - outw(0x0009, ioaddr + 0x68); - outw(0x0001, ioaddr + 0x60); - udelay(20); - outw(0x0009, ioaddr + 0x60); - mdelay(500); /* .. ouch.. */ - outw( inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38); - outw( inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a); - outw( inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c); - -#if 0 /* the loop here needs to be much better if we want it.. */ - M_printk("trying software reset\n"); - /* try and do a software reset */ - outb(0x80|0x7c, ioaddr + 0x30); - for (w=0; ; w++) { - if ((inw(ioaddr+ 0x30) & 1) == 0) { - if(inb(ioaddr + 0x32) !=0) break; - - outb(0x80|0x7d, ioaddr + 0x30); - if (((inw(ioaddr+ 0x30) & 1) == 0) && (inb(ioaddr + 0x32) !=0)) break; - outb(0x80|0x7f, ioaddr + 0x30); - if (((inw(ioaddr+ 0x30) & 1) == 0) && (inb(ioaddr + 0x32) !=0)) break; - } - - if( w > 10000) { - outb( inb(ioaddr + 0x37) | 0x08, ioaddr + 0x37); /* do a software reset */ - mdelay(500); /* oh my.. */ - outb( inb(ioaddr + 0x37) & ~0x08, ioaddr + 0x37); - udelay(1); - outw( 0x80, ioaddr+0x30); - for(w = 0 ; w < 10000; w++) { - if((inw(ioaddr + 0x30) & 1) ==0) break; - } - } - } -#endif - if ( vend == NEC_VERSA_SUBID1 || vend == NEC_VERSA_SUBID2) { - /* turn on external amp? */ - outw(0xf9ff, ioaddr + 0x64); - outw(inw(ioaddr+0x68) | 0x600, ioaddr + 0x68); - outw(0x0209, ioaddr + 0x60); - } - - /* Turn on the 978 docking chip. - First frob the "master output enable" bit, - then set most of the playback volume control registers to max. */ - outb(inb(ioaddr+0xc0)|(1<<5), ioaddr+0xc0); - outb(0xff, ioaddr+0xc3); - outb(0xff, ioaddr+0xc4); - outb(0xff, ioaddr+0xc6); - outb(0xff, ioaddr+0xc8); - outb(0x3f, ioaddr+0xcf); - outb(0x3f, ioaddr+0xd0); -} -/* - * Indirect register access. Not all registers are readable so we - * need to keep register state ourselves - */ - -#define WRITEABLE_MAP 0xEFFFFF -#define READABLE_MAP 0x64003F - -/* - * The Maestro engineers were a little indirection happy. These indirected - * registers themselves include indirect registers at another layer - */ - -static void __maestro_write(struct ess_card *card, u16 reg, u16 data) -{ - long ioaddr = card->iobase; - - outw(reg, ioaddr+0x02); - outw(data, ioaddr+0x00); - if( reg >= NR_IDRS) printk("maestro: IDR %d out of bounds!\n",reg); - else card->maestro_map[reg]=data; - -} - -static void maestro_write(struct ess_state *s, u16 reg, u16 data) -{ - unsigned long flags; - - check_suspend(s->card); - spin_lock_irqsave(&s->card->lock,flags); - - __maestro_write(s->card,reg,data); - - spin_unlock_irqrestore(&s->card->lock,flags); -} - -static u16 __maestro_read(struct ess_card *card, u16 reg) -{ - long ioaddr = card->iobase; - - outw(reg, ioaddr+0x02); - return card->maestro_map[reg]=inw(ioaddr+0x00); -} - -static u16 maestro_read(struct ess_state *s, u16 reg) -{ - if(READABLE_MAP & (1<card); - spin_lock_irqsave(&s->card->lock,flags); - - __maestro_read(s->card,reg); - - spin_unlock_irqrestore(&s->card->lock,flags); - } - return s->card->maestro_map[reg]; -} - -/* - * These routines handle accessing the second level indirections to the - * wave ram. - */ - -/* - * The register names are the ones ESS uses (see 104T31.ZIP) - */ - -#define IDR0_DATA_PORT 0x00 -#define IDR1_CRAM_POINTER 0x01 -#define IDR2_CRAM_DATA 0x02 -#define IDR3_WAVE_DATA 0x03 -#define IDR4_WAVE_PTR_LOW 0x04 -#define IDR5_WAVE_PTR_HI 0x05 -#define IDR6_TIMER_CTRL 0x06 -#define IDR7_WAVE_ROMRAM 0x07 - -static void apu_index_set(struct ess_card *card, u16 index) -{ - int i; - __maestro_write(card, IDR1_CRAM_POINTER, index); - for(i=0;i<1000;i++) - if(__maestro_read(card, IDR1_CRAM_POINTER)==index) - return; - printk(KERN_WARNING "maestro: APU register select failed.\n"); -} - -static void apu_data_set(struct ess_card *card, u16 data) -{ - int i; - for(i=0;i<1000;i++) - { - if(__maestro_read(card, IDR0_DATA_PORT)==data) - return; - __maestro_write(card, IDR0_DATA_PORT, data); - } -} - -/* - * This is the public interface for APU manipulation. It handles the - * interlock to avoid two APU writes in parallel etc. Don't diddle - * directly with the stuff above. - */ - -static void apu_set_register(struct ess_state *s, u16 channel, u8 reg, u16 data) -{ - unsigned long flags; - - check_suspend(s->card); - - if(channel&ESS_CHAN_HARD) - channel&=~ESS_CHAN_HARD; - else - { - if(channel>5) - printk("BAD CHANNEL %d.\n",channel); - else - channel = s->apu[channel]; - /* store based on real hardware apu/reg */ - s->card->apu_map[channel][reg]=data; - } - reg|=(channel<<4); - - /* hooray for double indirection!! */ - spin_lock_irqsave(&s->card->lock,flags); - - apu_index_set(s->card, reg); - apu_data_set(s->card, data); - - spin_unlock_irqrestore(&s->card->lock,flags); -} - -static u16 apu_get_register(struct ess_state *s, u16 channel, u8 reg) -{ - unsigned long flags; - u16 v; - - check_suspend(s->card); - - if(channel&ESS_CHAN_HARD) - channel&=~ESS_CHAN_HARD; - else - channel = s->apu[channel]; - - reg|=(channel<<4); - - spin_lock_irqsave(&s->card->lock,flags); - - apu_index_set(s->card, reg); - v=__maestro_read(s->card, IDR0_DATA_PORT); - - spin_unlock_irqrestore(&s->card->lock,flags); - return v; -} - - -/* - * The wavecache buffers between the APUs and - * pci bus mastering - */ - -static void wave_set_register(struct ess_state *s, u16 reg, u16 value) -{ - long ioaddr = s->card->iobase; - unsigned long flags; - check_suspend(s->card); - - spin_lock_irqsave(&s->card->lock,flags); - - outw(reg, ioaddr+0x10); - outw(value, ioaddr+0x12); - - spin_unlock_irqrestore(&s->card->lock,flags); -} - -static u16 wave_get_register(struct ess_state *s, u16 reg) -{ - long ioaddr = s->card->iobase; - unsigned long flags; - u16 value; - check_suspend(s->card); - - spin_lock_irqsave(&s->card->lock,flags); - outw(reg, ioaddr+0x10); - value=inw(ioaddr+0x12); - spin_unlock_irqrestore(&s->card->lock,flags); - - return value; -} - -static void sound_reset(int ioaddr) -{ - outw(0x2000, 0x18+ioaddr); - udelay(1); - outw(0x0000, 0x18+ioaddr); - udelay(1); -} - -/* sets the play formats of these apus, should be passed the already shifted format */ -static void set_apu_fmt(struct ess_state *s, int apu, int mode) -{ - int apu_fmt = 0x10; - - if(!(mode&ESS_FMT_16BIT)) apu_fmt+=0x20; - if((mode&ESS_FMT_STEREO)) apu_fmt+=0x10; - s->apu_mode[apu] = apu_fmt; - s->apu_mode[apu+1] = apu_fmt; -} - -/* this only fixes the output apu mode to be later set by start_dac and - company. output apu modes are set in ess_rec_setup */ -static void set_fmt(struct ess_state *s, unsigned char mask, unsigned char data) -{ - s->fmt = (s->fmt & mask) | data; - set_apu_fmt(s, 0, (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK); -} - -/* this is off by a little bit.. */ -static u32 compute_rate(struct ess_state *s, u32 freq) -{ - u32 clock = clock_freq[s->card->card_type]; - - freq = (freq * clocking)/48000; - - if (freq == 48000) - return 0x10000; - - return ((freq / clock) <<16 )+ - (((freq % clock) << 16) / clock); -} - -static void set_dac_rate(struct ess_state *s, unsigned int rate) -{ - u32 freq; - int fmt = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK; - - if (rate > 48000) - rate = 48000; - if (rate < 4000) - rate = 4000; - - s->ratedac = rate; - - if(! (fmt & ESS_FMT_16BIT) && !(fmt & ESS_FMT_STEREO)) - rate >>= 1; - -/* M_printk("computing dac rate %d with mode %d\n",rate,s->fmt);*/ - - freq = compute_rate(s, rate); - - /* Load the frequency, turn on 6dB */ - apu_set_register(s, 0, 2,(apu_get_register(s, 0, 2)&0x00FF)| - ( ((freq&0xFF)<<8)|0x10 )); - apu_set_register(s, 0, 3, freq>>8); - apu_set_register(s, 1, 2,(apu_get_register(s, 1, 2)&0x00FF)| - ( ((freq&0xFF)<<8)|0x10 )); - apu_set_register(s, 1, 3, freq>>8); -} - -static void set_adc_rate(struct ess_state *s, unsigned rate) -{ - u32 freq; - - /* Sample Rate conversion APUs don't like 0x10000 for their rate */ - if (rate > 47999) - rate = 47999; - if (rate < 4000) - rate = 4000; - - s->rateadc = rate; - - freq = compute_rate(s, rate); - - /* Load the frequency, turn on 6dB */ - apu_set_register(s, 2, 2,(apu_get_register(s, 2, 2)&0x00FF)| - ( ((freq&0xFF)<<8)|0x10 )); - apu_set_register(s, 2, 3, freq>>8); - apu_set_register(s, 3, 2,(apu_get_register(s, 3, 2)&0x00FF)| - ( ((freq&0xFF)<<8)|0x10 )); - apu_set_register(s, 3, 3, freq>>8); - - /* fix mixer rate at 48khz. and its _must_ be 0x10000. */ - freq = 0x10000; - - apu_set_register(s, 4, 2,(apu_get_register(s, 4, 2)&0x00FF)| - ( ((freq&0xFF)<<8)|0x10 )); - apu_set_register(s, 4, 3, freq>>8); - apu_set_register(s, 5, 2,(apu_get_register(s, 5, 2)&0x00FF)| - ( ((freq&0xFF)<<8)|0x10 )); - apu_set_register(s, 5, 3, freq>>8); -} - -/* Stop our host of recording apus */ -static inline void stop_adc(struct ess_state *s) -{ - /* XXX lets hope we don't have to lock around this */ - if (! (s->enable & ADC_RUNNING)) return; - - s->enable &= ~ADC_RUNNING; - apu_set_register(s, 2, 0, apu_get_register(s, 2, 0)&0xFF0F); - apu_set_register(s, 3, 0, apu_get_register(s, 3, 0)&0xFF0F); - apu_set_register(s, 4, 0, apu_get_register(s, 2, 0)&0xFF0F); - apu_set_register(s, 5, 0, apu_get_register(s, 3, 0)&0xFF0F); -} - -/* stop output apus */ -static void stop_dac(struct ess_state *s) -{ - /* XXX have to lock around this? */ - if (! (s->enable & DAC_RUNNING)) return; - - s->enable &= ~DAC_RUNNING; - apu_set_register(s, 0, 0, apu_get_register(s, 0, 0)&0xFF0F); - apu_set_register(s, 1, 0, apu_get_register(s, 1, 0)&0xFF0F); -} - -static void start_dac(struct ess_state *s) -{ - /* XXX locks? */ - if ( (s->dma_dac.mapped || s->dma_dac.count > 0) && - s->dma_dac.ready && - (! (s->enable & DAC_RUNNING)) ) { - - s->enable |= DAC_RUNNING; - - apu_set_register(s, 0, 0, - (apu_get_register(s, 0, 0)&0xFF0F)|s->apu_mode[0]); - - if((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_STEREO) - apu_set_register(s, 1, 0, - (apu_get_register(s, 1, 0)&0xFF0F)|s->apu_mode[1]); - } -} - -static void start_adc(struct ess_state *s) -{ - /* XXX locks? */ - if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) - && s->dma_adc.ready && (! (s->enable & ADC_RUNNING)) ) { - - s->enable |= ADC_RUNNING; - apu_set_register(s, 2, 0, - (apu_get_register(s, 2, 0)&0xFF0F)|s->apu_mode[2]); - apu_set_register(s, 4, 0, - (apu_get_register(s, 4, 0)&0xFF0F)|s->apu_mode[4]); - - if( s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) { - apu_set_register(s, 3, 0, - (apu_get_register(s, 3, 0)&0xFF0F)|s->apu_mode[3]); - apu_set_register(s, 5, 0, - (apu_get_register(s, 5, 0)&0xFF0F)|s->apu_mode[5]); - } - - } -} - - -/* - * Native play back driver - */ - -/* the mode passed should be already shifted and masked */ -static void -ess_play_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size) -{ - u32 pa; - u32 tmpval; - int high_apu = 0; - int channel; - - M_printk("mode=%d rate=%d buf=%p len=%d.\n", - mode, rate, buffer, size); - - /* all maestro sizes are in 16bit words */ - size >>=1; - - if(mode&ESS_FMT_STEREO) { - high_apu++; - /* only 16/stereo gets size divided */ - if(mode&ESS_FMT_16BIT) - size>>=1; - } - - for(channel=0; channel <= high_apu; channel++) - { - pa = virt_to_bus(buffer); - - /* set the wavecache control reg */ - tmpval = (pa - 0x10) & 0xFFF8; - if(!(mode & ESS_FMT_16BIT)) tmpval |= 4; - if(mode & ESS_FMT_STEREO) tmpval |= 2; - ess->apu_base[channel]=tmpval; - wave_set_register(ess, ess->apu[channel]<<3, tmpval); - - pa -= virt_to_bus(ess->card->dmapages); - pa>>=1; /* words */ - - /* base offset of dma calcs when reading the pointer - on the left one */ - if(!channel) ess->dma_dac.base = pa&0xFFFF; - - pa|=0x00400000; /* System RAM */ - - /* XXX the 16bit here might not be needed.. */ - if((mode & ESS_FMT_STEREO) && (mode & ESS_FMT_16BIT)) { - if(channel) - pa|=0x00800000; /* Stereo */ - pa>>=1; - } - -/* XXX think about endianess when writing these registers */ - M_printk("maestro: ess_play_setup: APU[%d] pa = 0x%x\n", ess->apu[channel], pa); - /* start of sample */ - apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8); - apu_set_register(ess, channel, 5, pa&0xFFFF); - /* sample end */ - apu_set_register(ess, channel, 6, (pa+size)&0xFFFF); - /* setting loop len == sample len */ - apu_set_register(ess, channel, 7, size); - - /* clear effects/env.. */ - apu_set_register(ess, channel, 8, 0x0000); - /* set amp now to 0xd0 (?), low byte is 'amplitude dest'? */ - apu_set_register(ess, channel, 9, 0xD000); - - /* clear routing stuff */ - apu_set_register(ess, channel, 11, 0x0000); - /* dma on, no envelopes, filter to all 1s) */ - apu_set_register(ess, channel, 0, 0x400F); - - if(mode&ESS_FMT_16BIT) - ess->apu_mode[channel]=0x10; - else - ess->apu_mode[channel]=0x30; - - if(mode&ESS_FMT_STEREO) { - /* set panning: left or right */ - apu_set_register(ess, channel, 10, 0x8F00 | (channel ? 0 : 0x10)); - ess->apu_mode[channel] += 0x10; - } else - apu_set_register(ess, channel, 10, 0x8F08); - } - - /* clear WP interrupts */ - outw(1, ess->card->iobase+0x04); - /* enable WP ints */ - outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18); - - /* go team! */ - set_dac_rate(ess,rate); - start_dac(ess); -} - -/* - * Native record driver - */ - -/* again, passed mode is alrady shifted/masked */ -static void -ess_rec_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size) -{ - int apu_step = 2; - int channel; - - M_printk("maestro: ess_rec_setup: mode=%d rate=%d buf=0x%p len=%d.\n", - mode, rate, buffer, size); - - /* all maestro sizes are in 16bit words */ - size >>=1; - - /* we're given the full size of the buffer, but - in stereo each channel will only use its half */ - if(mode&ESS_FMT_STEREO) { - size >>=1; - apu_step = 1; - } - - /* APU assignments: 2 = mono/left SRC - 3 = right SRC - 4 = mono/left Input Mixer - 5 = right Input Mixer */ - for(channel=2;channel<6;channel+=apu_step) - { - int i; - int bsize, route; - u32 pa; - u32 tmpval; - - /* data seems to flow from the codec, through an apu into - the 'mixbuf' bit of page, then through the SRC apu - and out to the real 'buffer'. ok. sure. */ - - if(channel & 0x04) { - /* ok, we're an input mixer going from adc - through the mixbuf to the other apus */ - - if(!(channel & 0x01)) { - pa = virt_to_bus(ess->mixbuf); - } else { - pa = virt_to_bus(ess->mixbuf + (PAGE_SIZE >> 4)); - } - - /* we source from a 'magic' apu */ - bsize = PAGE_SIZE >> 5; /* half of this channels alloc, in words */ - route = 0x14 + (channel - 4); /* parallel in crap, see maestro reg 0xC [8-11] */ - ess->apu_mode[channel] = 0x90; /* Input Mixer */ - - } else { - /* we're a rate converter taking - input from the input apus and outputing it to - system memory */ - if(!(channel & 0x01)) { - pa = virt_to_bus(buffer); - } else { - /* right channel records its split half. - *2 accommodates for rampant shifting earlier */ - pa = virt_to_bus(buffer + size*2); - } - - ess->apu_mode[channel] = 0xB0; /* Sample Rate Converter */ - - bsize = size; - /* get input from inputing apu */ - route = channel + 2; - } - - M_printk("maestro: ess_rec_setup: getting pa 0x%x from %d\n",pa,channel); - - /* set the wavecache control reg */ - tmpval = (pa - 0x10) & 0xFFF8; - ess->apu_base[channel]=tmpval; - wave_set_register(ess, ess->apu[channel]<<3, tmpval); - - pa -= virt_to_bus(ess->card->dmapages); - pa>>=1; /* words */ - - /* base offset of dma calcs when reading the pointer - on this left one */ - if(channel==2) ess->dma_adc.base = pa&0xFFFF; - - pa|=0x00400000; /* bit 22 -> System RAM */ - - M_printk("maestro: ess_rec_setup: APU[%d] pa = 0x%x size = 0x%x route = 0x%x\n", - ess->apu[channel], pa, bsize, route); - - /* Begin loading the APU */ - for(i=0;i<15;i++) /* clear all PBRs */ - apu_set_register(ess, channel, i, 0x0000); - - apu_set_register(ess, channel, 0, 0x400F); - - /* need to enable subgroups.. and we should probably - have different groups for different /dev/dsps.. */ - apu_set_register(ess, channel, 2, 0x8); - - /* Load the buffer into the wave engine */ - apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8); - /* XXX reg is little endian.. */ - apu_set_register(ess, channel, 5, pa&0xFFFF); - apu_set_register(ess, channel, 6, (pa+bsize)&0xFFFF); - apu_set_register(ess, channel, 7, bsize); - - /* clear effects/env.. */ - apu_set_register(ess, channel, 8, 0x00F0); - - /* amplitude now? sure. why not. */ - apu_set_register(ess, channel, 9, 0x0000); - - /* set filter tune, radius, polar pan */ - apu_set_register(ess, channel, 10, 0x8F08); - - /* route input */ - apu_set_register(ess, channel, 11, route); - } - - /* clear WP interrupts */ - outw(1, ess->card->iobase+0x04); - /* enable WP ints */ - outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18); - - /* let 'er rip */ - set_adc_rate(ess,rate); - start_adc(ess); -} -/* --------------------------------------------------------------------- */ - -static void set_dmaa(struct ess_state *s, unsigned int addr, unsigned int count) -{ - M_printk("set_dmaa??\n"); -} - -static void set_dmac(struct ess_state *s, unsigned int addr, unsigned int count) -{ - M_printk("set_dmac??\n"); -} - -/* Playback pointer */ -static inline unsigned get_dmaa(struct ess_state *s) -{ - int offset; - - offset = apu_get_register(s,0,5); - -/* M_printk("dmaa: offset: %d, base: %d\n",offset,s->dma_dac.base); */ - - offset-=s->dma_dac.base; - - return (offset&0xFFFE)<<1; /* hardware is in words */ -} - -/* Record pointer */ -static inline unsigned get_dmac(struct ess_state *s) -{ - int offset; - - offset = apu_get_register(s,2,5); - -/* M_printk("dmac: offset: %d, base: %d\n",offset,s->dma_adc.base); */ - - /* The offset is an address not a position relative to base */ - offset-=s->dma_adc.base; - - return (offset&0xFFFE)<<1; /* hardware is in words */ -} - -/* - * Meet Bob, the timer... - */ - -static irqreturn_t ess_interrupt(int irq, void *dev_id, struct pt_regs *regs); - -static void stop_bob(struct ess_state *s) -{ - /* Mask IDR 11,17 */ - maestro_write(s, 0x11, maestro_read(s, 0x11)&~1); - maestro_write(s, 0x17, maestro_read(s, 0x17)&~1); -} - -/* eventually we could be clever and limit bob ints - to the frequency at which our smallest duration - chunks may expire */ -#define ESS_SYSCLK 50000000 -static void start_bob(struct ess_state *s) -{ - int prescale; - int divide; - - /* XXX make freq selector much smarter, see calc_bob_rate */ - int freq = 200; - - /* compute ideal interrupt frequency for buffer size & play rate */ - /* first, find best prescaler value to match freq */ - for(prescale=5;prescale<12;prescale++) - if(freq > (ESS_SYSCLK>>(prescale+9))) - break; - - /* next, back off prescaler whilst getting divider into optimum range */ - divide=1; - while((prescale > 5) && (divide<32)) - { - prescale--; - divide <<=1; - } - divide>>=1; - - /* now fine-tune the divider for best match */ - for(;divide<31;divide++) - if(freq >= ((ESS_SYSCLK>>(prescale+9))/(divide+1))) - break; - - /* divide = 0 is illegal, but don't let prescale = 4! */ - if(divide == 0) - { - divide++; - if(prescale>5) - prescale--; - } - - maestro_write(s, 6, 0x9000 | (prescale<<5) | divide); /* set reg */ - - /* Now set IDR 11/17 */ - maestro_write(s, 0x11, maestro_read(s, 0x11)|1); - maestro_write(s, 0x17, maestro_read(s, 0x17)|1); -} -/* --------------------------------------------------------------------- */ - -/* this quickly calculates the frequency needed for bob - and sets it if its different than what bob is - currently running at. its called often so - needs to be fairly quick. */ -#define BOB_MIN 50 -#define BOB_MAX 400 -static void calc_bob_rate(struct ess_state *s) { -#if 0 /* this thing tries to set the frequency of bob such that - there are 2 interrupts / buffer walked by the dac/adc. That - is probably very wrong for people who actually care about - mid buffer positioning. it should be calculated as bytes/interrupt - and that needs to be decided :) so for now just use the static 150 - in start_bob.*/ - - unsigned int dac_rate=2,adc_rate=1,newrate; - static int israte=-1; - - if (s->dma_dac.fragsize == 0) dac_rate = BOB_MIN; - else { - dac_rate = (2 * s->ratedac * sample_size[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK]) / - (s->dma_dac.fragsize) ; - } - - if (s->dma_adc.fragsize == 0) adc_rate = BOB_MIN; - else { - adc_rate = (2 * s->rateadc * sample_size[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK]) / - (s->dma_adc.fragsize) ; - } - - if(dac_rate > adc_rate) newrate = adc_rate; - else newrate=dac_rate; - - if(newrate > BOB_MAX) newrate = BOB_MAX; - else { - if(newrate < BOB_MIN) - newrate = BOB_MIN; - } - - if( israte != newrate) { - printk("dac: %d adc: %d rate: %d\n",dac_rate,adc_rate,israte); - israte=newrate; - } -#endif - -} - -static int -prog_dmabuf(struct ess_state *s, unsigned rec) -{ - struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac; - unsigned rate = rec ? s->rateadc : s->ratedac; - unsigned bytepersec; - unsigned bufs; - unsigned char fmt; - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - fmt = s->fmt; - if (rec) { - stop_adc(s); - fmt >>= ESS_ADC_SHIFT; - } else { - stop_dac(s); - fmt >>= ESS_DAC_SHIFT; - } - spin_unlock_irqrestore(&s->lock, flags); - fmt &= ESS_FMT_MASK; - - db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; - - /* this algorithm is a little nuts.. where did /1000 come from? */ - bytepersec = rate << sample_shift[fmt]; - bufs = PAGE_SIZE << db->buforder; - if (db->ossfragshift) { - if ((1000 << db->ossfragshift) < bytepersec) - db->fragshift = ld2(bytepersec/1000); - else - db->fragshift = db->ossfragshift; - } else { - db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1)); - if (db->fragshift < 3) - db->fragshift = 3; - } - db->numfrag = bufs >> db->fragshift; - while (db->numfrag < 4 && db->fragshift > 3) { - db->fragshift--; - db->numfrag = bufs >> db->fragshift; - } - db->fragsize = 1 << db->fragshift; - if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) - db->numfrag = db->ossmaxfrags; - db->fragsamples = db->fragsize >> sample_shift[fmt]; - db->dmasize = db->numfrag << db->fragshift; - - M_printk("maestro: setup oss: numfrag: %d fragsize: %d dmasize: %d\n",db->numfrag,db->fragsize,db->dmasize); - - memset(db->rawbuf, (fmt & ESS_FMT_16BIT) ? 0 : 0x80, db->dmasize); - - spin_lock_irqsave(&s->lock, flags); - if (rec) - ess_rec_setup(s, fmt, s->rateadc, db->rawbuf, db->dmasize); - else - ess_play_setup(s, fmt, s->ratedac, db->rawbuf, db->dmasize); - - spin_unlock_irqrestore(&s->lock, flags); - db->ready = 1; - - return 0; -} - -static __inline__ void -clear_advance(struct ess_state *s) -{ - unsigned char c = ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT) ? 0 : 0x80; - - unsigned char *buf = s->dma_dac.rawbuf; - unsigned bsize = s->dma_dac.dmasize; - unsigned bptr = s->dma_dac.swptr; - unsigned len = s->dma_dac.fragsize; - - if (bptr + len > bsize) { - unsigned x = bsize - bptr; - memset(buf + bptr, c, x); - /* account for wrapping? */ - bptr = 0; - len -= x; - } - memset(buf + bptr, c, len); -} - -/* call with spinlock held! */ -static void -ess_update_ptr(struct ess_state *s) -{ - unsigned hwptr; - int diff; - - /* update ADC pointer */ - if (s->dma_adc.ready) { - /* oh boy should this all be re-written. everything in the current code paths think - that the various counters/pointers are expressed in bytes to the user but we have - two apus doing stereo stuff so we fix it up here.. it propagates to all the various - counters from here. */ - if ( s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) { - hwptr = (get_dmac(s)*2) % s->dma_adc.dmasize; - } else { - hwptr = get_dmac(s) % s->dma_adc.dmasize; - } - diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize; - s->dma_adc.hwptr = hwptr; - s->dma_adc.total_bytes += diff; - s->dma_adc.count += diff; - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) - wake_up(&s->dma_adc.wait); - if (!s->dma_adc.mapped) { - if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) { - /* FILL ME - wrindir(s, SV_CIENABLE, s->enable); */ - stop_adc(s); - /* brute force everyone back in sync, sigh */ - s->dma_adc.count = 0; - s->dma_adc.swptr = 0; - s->dma_adc.hwptr = 0; - s->dma_adc.error++; - } - } - } - /* update DAC pointer */ - if (s->dma_dac.ready) { - hwptr = get_dmaa(s) % s->dma_dac.dmasize; - /* the apu only reports the length it has seen, not the - length of the memory that has been used (the WP - knows that) */ - if ( ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK) == (ESS_FMT_STEREO|ESS_FMT_16BIT)) - hwptr<<=1; - - diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize; -/* M_printk("updating dac: hwptr: %d diff: %d\n",hwptr,diff);*/ - s->dma_dac.hwptr = hwptr; - s->dma_dac.total_bytes += diff; - if (s->dma_dac.mapped) { - s->dma_dac.count += diff; - if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) { - wake_up(&s->dma_dac.wait); - } - } else { - s->dma_dac.count -= diff; -/* M_printk("maestro: ess_update_ptr: diff: %d, count: %d\n", diff, s->dma_dac.count); */ - if (s->dma_dac.count <= 0) { - M_printk("underflow! diff: %d count: %d hw: %d sw: %d\n", diff, s->dma_dac.count, - hwptr, s->dma_dac.swptr); - /* FILL ME - wrindir(s, SV_CIENABLE, s->enable); */ - /* XXX how on earth can calling this with the lock held work.. */ - stop_dac(s); - /* brute force everyone back in sync, sigh */ - s->dma_dac.count = 0; - s->dma_dac.swptr = hwptr; - s->dma_dac.error++; - } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) { - clear_advance(s); - s->dma_dac.endcleared = 1; - } - if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) { - wake_up(&s->dma_dac.wait); -/* printk("waking up DAC count: %d sw: %d hw: %d\n",s->dma_dac.count, s->dma_dac.swptr, - hwptr);*/ - } - } - } -} - -static irqreturn_t -ess_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct ess_state *s; - struct ess_card *c = (struct ess_card *)dev_id; - int i; - u32 event; - - if ( ! (event = inb(c->iobase+0x1A)) ) - return IRQ_NONE; - - outw(inw(c->iobase+4)&1, c->iobase+4); - -/* M_printk("maestro int: %x\n",event);*/ - if(event&(1<<6)) - { - int x; - enum {UP_EVT, DOWN_EVT, MUTE_EVT} vol_evt; - int volume; - - /* Figure out which volume control button was pushed, - based on differences from the default register - values. */ - x = inb(c->iobase+0x1c); - if (x&1) vol_evt = MUTE_EVT; - else if (((x>>1)&7) > 4) vol_evt = UP_EVT; - else vol_evt = DOWN_EVT; - - /* Reset the volume control registers. */ - outb(0x88, c->iobase+0x1c); - outb(0x88, c->iobase+0x1d); - outb(0x88, c->iobase+0x1e); - outb(0x88, c->iobase+0x1f); - - /* Deal with the button press in a hammer-handed - manner by adjusting the master mixer volume. */ - volume = c->mix.mixer_state[0] & 0xff; - if (vol_evt == UP_EVT) { - volume += 5; - if (volume > 100) - volume = 100; - } - else if (vol_evt == DOWN_EVT) { - volume -= 5; - if (volume < 0) - volume = 0; - } else { - /* vol_evt == MUTE_EVT */ - if (volume == 0) - volume = c->dock_mute_vol; - else { - c->dock_mute_vol = volume; - volume = 0; - } - } - set_mixer (c, 0, (volume << 8) | volume); - } - - /* Ack all the interrupts. */ - outb(0xFF, c->iobase+0x1A); - - /* - * Update the pointers for all APU's we are running. - */ - for(i=0;ichannels[i]; - if(s->dev_audio == -1) - break; - spin_lock(&s->lock); - ess_update_ptr(s); - spin_unlock(&s->lock); - } - return IRQ_HANDLED; -} - - -/* --------------------------------------------------------------------- */ - -static const char invalid_magic[] = KERN_CRIT "maestro: invalid magic value in %s\n"; - -#define VALIDATE_MAGIC(FOO,MAG) \ -({ \ - if (!(FOO) || (FOO)->magic != MAG) { \ - printk(invalid_magic,__FUNCTION__); \ - return -ENXIO; \ - } \ -}) - -#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,ESS_STATE_MAGIC) -#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,ESS_CARD_MAGIC) - -static void set_mixer(struct ess_card *card,unsigned int mixer, unsigned int val ) -{ - unsigned int left,right; - /* cleanse input a little */ - right = ((val >> 8) & 0xff) ; - left = (val & 0xff) ; - - if(right > 100) right = 100; - if(left > 100) left = 100; - - card->mix.mixer_state[mixer]=(right << 8) | left; - card->mix.write_mixer(card,mixer,left,right); -} - -static void -mixer_push_state(struct ess_card *card) -{ - int i; - for(i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++) { - if( ! supported_mixer(card,i)) continue; - - set_mixer(card,i,card->mix.mixer_state[i]); - } -} - -static int mixer_ioctl(struct ess_card *card, unsigned int cmd, unsigned long arg) -{ - int i, val=0; - unsigned long flags; - void __user *argp = (void __user *)arg; - int __user *p = argp; - - VALIDATE_CARD(card); - if (cmd == SOUND_MIXER_INFO) { - mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, card_names[card->card_type], sizeof(info.id)); - strlcpy(info.name, card_names[card->card_type], sizeof(info.name)); - info.modify_counter = card->mix.modcnt; - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == SOUND_OLD_MIXER_INFO) { - _old_mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, card_names[card->card_type], sizeof(info.id)); - strlcpy(info.name, card_names[card->card_type], sizeof(info.name)); - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == OSS_GETVERSION) - return put_user(SOUND_VERSION, p); - - if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int)) - return -EINVAL; - - if (_IOC_DIR(cmd) == _IOC_READ) { - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* give them the current record source */ - - if(!card->mix.recmask_io) { - val = 0; - } else { - spin_lock_irqsave(&card->lock, flags); - val = card->mix.recmask_io(card,1,0); - spin_unlock_irqrestore(&card->lock, flags); - } - break; - - case SOUND_MIXER_DEVMASK: /* give them the supported mixers */ - val = card->mix.supported_mixers; - break; - - case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ - val = card->mix.record_sources; - break; - - case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ - val = card->mix.stereo_mixers; - break; - - case SOUND_MIXER_CAPS: - val = SOUND_CAP_EXCL_INPUT; - break; - - default: /* read a specific mixer */ - i = _IOC_NR(cmd); - - if ( ! supported_mixer(card,i)) - return -EINVAL; - - /* do we ever want to touch the hardware? */ -/* spin_lock_irqsave(&card->lock, flags); - val = card->mix.read_mixer(card,i); - spin_unlock_irqrestore(&card->lock, flags);*/ - - val = card->mix.mixer_state[i]; -/* M_printk("returned 0x%x for mixer %d\n",val,i);*/ - - break; - } - return put_user(val, p); - } - - if (_IOC_DIR(cmd) != (_IOC_WRITE|_IOC_READ)) - return -EINVAL; - - card->mix.modcnt++; - - if (get_user(val, p)) - return -EFAULT; - - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - - if (!card->mix.recmask_io) return -EINVAL; - if(!val) return 0; - if(! (val &= card->mix.record_sources)) return -EINVAL; - - spin_lock_irqsave(&card->lock, flags); - card->mix.recmask_io(card,0,val); - spin_unlock_irqrestore(&card->lock, flags); - return 0; - - default: - i = _IOC_NR(cmd); - - if ( ! supported_mixer(card,i)) - return -EINVAL; - - spin_lock_irqsave(&card->lock, flags); - set_mixer(card,i,val); - spin_unlock_irqrestore(&card->lock, flags); - - return 0; - } -} - -/* --------------------------------------------------------------------- */ -static int ess_open_mixdev(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode); - struct ess_card *card = NULL; - struct pci_dev *pdev = NULL; - struct pci_driver *drvr; - - while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { - drvr = pci_dev_driver (pdev); - if (drvr == &maestro_pci_driver) { - card = (struct ess_card*)pci_get_drvdata (pdev); - if (!card) - continue; - if (card->dev_mixer == minor) - break; - } - } - if (!card) - return -ENODEV; - file->private_data = card; - return nonseekable_open(inode, file); -} - -static int ess_release_mixdev(struct inode *inode, struct file *file) -{ - struct ess_card *card = (struct ess_card *)file->private_data; - - VALIDATE_CARD(card); - - return 0; -} - -static int ess_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct ess_card *card = (struct ess_card *)file->private_data; - - VALIDATE_CARD(card); - - return mixer_ioctl(card, cmd, arg); -} - -static /*const*/ struct file_operations ess_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = ess_ioctl_mixdev, - .open = ess_open_mixdev, - .release = ess_release_mixdev, -}; - -/* --------------------------------------------------------------------- */ - -static int drain_dac(struct ess_state *s, int nonblock) -{ - DECLARE_WAITQUEUE(wait,current); - unsigned long flags; - int count; - signed long tmo; - - if (s->dma_dac.mapped || !s->dma_dac.ready) - return 0; - current->state = TASK_INTERRUPTIBLE; - add_wait_queue(&s->dma_dac.wait, &wait); - for (;;) { - /* XXX uhm.. questionable locking*/ - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - if (nonblock) { - remove_wait_queue(&s->dma_dac.wait, &wait); - current->state = TASK_RUNNING; - return -EBUSY; - } - tmo = (count * HZ) / s->ratedac; - tmo >>= sample_shift[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK]; - /* XXX this is just broken. someone is waking us up alot, or schedule_timeout is broken. - or something. who cares. - zach */ - if (!schedule_timeout(tmo ? tmo : 1) && tmo) - M_printk(KERN_DEBUG "maestro: dma timed out?? %ld\n",jiffies); - } - remove_wait_queue(&s->dma_dac.wait, &wait); - current->state = TASK_RUNNING; - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -/* --------------------------------------------------------------------- */ -/* Zach sez: "god this is gross.." */ -static int -comb_stereo(unsigned char *real_buffer,unsigned char *tmp_buffer, int offset, - int count, int bufsize) -{ - /* No such thing as stereo recording, so we - use dual input mixers. which means we have to - combine mono to stereo buffer. yuck. - - but we don't have to be able to work a byte at a time..*/ - - unsigned char *so,*left,*right; - int i; - - so = tmp_buffer; - left = real_buffer + offset; - right = real_buffer + bufsize/2 + offset; - -/* M_printk("comb_stereo writing %d to %p from %p and %p, offset: %d size: %d\n",count/2, tmp_buffer,left,right,offset,bufsize);*/ - - for(i=count/4; i ; i--) { - (*(so+2)) = *(right++); - (*(so+3)) = *(right++); - (*so) = *(left++); - (*(so+1)) = *(left++); - so+=4; - } - - return 0; -} - -/* in this loop, dma_adc.count signifies the amount of data thats waiting - to be copied to the user's buffer. it is filled by the interrupt - handler and drained by this loop. */ -static ssize_t -ess_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct ess_state *s = (struct ess_state *)file->private_data; - ssize_t ret; - unsigned long flags; - unsigned swptr; - int cnt; - unsigned char *combbuf = NULL; - - VALIDATE_STATE(s); - if (s->dma_adc.mapped) - return -ENXIO; - if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) - return ret; - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - if(!(combbuf = kmalloc(count,GFP_KERNEL))) - return -ENOMEM; - ret = 0; - - calc_bob_rate(s); - - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - /* remember, all these things are expressed in bytes to be - sent to the user.. hence the evil / 2 down below */ - swptr = s->dma_adc.swptr; - cnt = s->dma_adc.dmasize-swptr; - if (s->dma_adc.count < cnt) - cnt = s->dma_adc.count; - spin_unlock_irqrestore(&s->lock, flags); - - if (cnt > count) - cnt = count; - - if ( cnt > 0 ) cnt &= ~3; - - if (cnt <= 0) { - start_adc(s); - if (file->f_flags & O_NONBLOCK) - { - ret = ret ? ret : -EAGAIN; - goto rec_return_free; - } - if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) { - if(! s->card->in_suspend) printk(KERN_DEBUG "maestro: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", - s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, - s->dma_adc.hwptr, s->dma_adc.swptr); - stop_adc(s); - spin_lock_irqsave(&s->lock, flags); - set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift); - /* program enhanced mode registers */ - /* FILL ME */ -/* wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8); - wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1); */ - s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0; - spin_unlock_irqrestore(&s->lock, flags); - } - if (signal_pending(current)) - { - ret = ret ? ret : -ERESTARTSYS; - goto rec_return_free; - } - continue; - } - - if(s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) { - /* swptr/2 so that we know the real offset in each apu's buffer */ - comb_stereo(s->dma_adc.rawbuf,combbuf,swptr/2,cnt,s->dma_adc.dmasize); - if (copy_to_user(buffer, combbuf, cnt)) { - ret = ret ? ret : -EFAULT; - goto rec_return_free; - } - } else { - if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) { - ret = ret ? ret : -EFAULT; - goto rec_return_free; - } - } - - swptr = (swptr + cnt) % s->dma_adc.dmasize; - spin_lock_irqsave(&s->lock, flags); - s->dma_adc.swptr = swptr; - s->dma_adc.count -= cnt; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - start_adc(s); - } - -rec_return_free: - kfree(combbuf); - return ret; -} - -static ssize_t -ess_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct ess_state *s = (struct ess_state *)file->private_data; - ssize_t ret; - unsigned long flags; - unsigned swptr; - int cnt; - - VALIDATE_STATE(s); - if (s->dma_dac.mapped) - return -ENXIO; - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - ret = 0; - - calc_bob_rate(s); - - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - - if (s->dma_dac.count < 0) { - s->dma_dac.count = 0; - s->dma_dac.swptr = s->dma_dac.hwptr; - } - swptr = s->dma_dac.swptr; - - cnt = s->dma_dac.dmasize-swptr; - - if (s->dma_dac.count + cnt > s->dma_dac.dmasize) - cnt = s->dma_dac.dmasize - s->dma_dac.count; - - spin_unlock_irqrestore(&s->lock, flags); - - if (cnt > count) - cnt = count; - - if (cnt <= 0) { - start_dac(s); - if (file->f_flags & O_NONBLOCK) { - if(!ret) ret = -EAGAIN; - goto return_free; - } - if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) { - if(! s->card->in_suspend) printk(KERN_DEBUG "maestro: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", - s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, - s->dma_dac.hwptr, s->dma_dac.swptr); - stop_dac(s); - spin_lock_irqsave(&s->lock, flags); - set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift); - /* program enhanced mode registers */ -/* wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8); - wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1); */ - /* FILL ME */ - s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0; - spin_unlock_irqrestore(&s->lock, flags); - } - if (signal_pending(current)) { - if (!ret) ret = -ERESTARTSYS; - goto return_free; - } - continue; - } - if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) { - if (!ret) ret = -EFAULT; - goto return_free; - } -/* printk("wrote %d bytes at sw: %d cnt: %d while hw: %d\n",cnt, swptr, s->dma_dac.count, s->dma_dac.hwptr);*/ - - swptr = (swptr + cnt) % s->dma_dac.dmasize; - - spin_lock_irqsave(&s->lock, flags); - s->dma_dac.swptr = swptr; - s->dma_dac.count += cnt; - s->dma_dac.endcleared = 0; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - start_dac(s); - } -return_free: - return ret; -} - -/* No kernel lock - we have our own spinlock */ -static unsigned int ess_poll(struct file *file, struct poll_table_struct *wait) -{ - struct ess_state *s = (struct ess_state *)file->private_data; - unsigned long flags; - unsigned int mask = 0; - - VALIDATE_STATE(s); - -/* In 0.14 prog_dmabuf always returns success anyway ... */ - if (file->f_mode & FMODE_WRITE) { - if (!s->dma_dac.ready && prog_dmabuf(s, 0)) - return 0; - } - if (file->f_mode & FMODE_READ) { - if (!s->dma_adc.ready && prog_dmabuf(s, 1)) - return 0; - } - - if (file->f_mode & FMODE_WRITE) - poll_wait(file, &s->dma_dac.wait, wait); - if (file->f_mode & FMODE_READ) - poll_wait(file, &s->dma_adc.wait, wait); - spin_lock_irqsave(&s->lock, flags); - ess_update_ptr(s); - if (file->f_mode & FMODE_READ) { - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_mode & FMODE_WRITE) { - if (s->dma_dac.mapped) { - if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) - mask |= POLLOUT | POLLWRNORM; - } else { - if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize) - mask |= POLLOUT | POLLWRNORM; - } - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; -} - -static int ess_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct ess_state *s = (struct ess_state *)file->private_data; - struct dmabuf *db; - int ret = -EINVAL; - unsigned long size; - - VALIDATE_STATE(s); - lock_kernel(); - if (vma->vm_flags & VM_WRITE) { - if ((ret = prog_dmabuf(s, 1)) != 0) - goto out; - db = &s->dma_dac; - } else -#if 0 - /* if we can have the wp/wc do the combining - we can turn this back on. */ - if (vma->vm_flags & VM_READ) { - if ((ret = prog_dmabuf(s, 0)) != 0) - goto out; - db = &s->dma_adc; - } else -#endif - goto out; - ret = -EINVAL; - if (vma->vm_pgoff != 0) - goto out; - size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << db->buforder)) - goto out; - ret = -EAGAIN; - if (remap_pfn_range(vma, vma->vm_start, - virt_to_phys(db->rawbuf) >> PAGE_SHIFT, - size, vma->vm_page_prot)) - goto out; - db->mapped = 1; - ret = 0; -out: - unlock_kernel(); - return ret; -} - -static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct ess_state *s = (struct ess_state *)file->private_data; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int val, mapped, ret; - unsigned char fmtm, fmtd; - void __user *argp = (void __user *)arg; - int __user *p = argp; - -/* printk("maestro: ess_ioctl: cmd %d\n", cmd);*/ - - VALIDATE_STATE(s); - mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || - ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, p); - - case SNDCTL_DSP_SYNC: - if (file->f_mode & FMODE_WRITE) - return drain_dac(s, file->f_flags & O_NONBLOCK); - return 0; - - case SNDCTL_DSP_SETDUPLEX: - /* XXX fix */ - return 0; - - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p); - - case SNDCTL_DSP_RESET: - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - synchronize_irq(s->card->pcidev->irq); - s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0; - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - synchronize_irq(s->card->pcidev->irq); - s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; - } - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, p)) - return -EFAULT; - if (val >= 0) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - set_adc_rate(s, val); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - set_dac_rate(s, val); - } - } - return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p); - - case SNDCTL_DSP_STEREO: - if (get_user(val, p)) - return -EFAULT; - fmtd = 0; - fmtm = ~0; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - if (val) - fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT; - else - fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val) - fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT; - else - fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT); - } - set_fmt(s, fmtm, fmtd); - return 0; - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, p)) - return -EFAULT; - if (val != 0) { - fmtd = 0; - fmtm = ~0; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - if (val >= 2) - fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT; - else - fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val >= 2) - fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT; - else - fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT); - } - set_fmt(s, fmtm, fmtd); - } - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT) - : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_U8|AFMT_S16_LE, p); - - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - if (get_user(val, p)) - return -EFAULT; - if (val != AFMT_QUERY) { - fmtd = 0; - fmtm = ~0; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - /* fixed at 16bit for now */ - fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT; -#if 0 - if (val == AFMT_S16_LE) - fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT; - else - fmtm &= ~(ESS_FMT_16BIT << ESS_ADC_SHIFT); -#endif - } - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - s->dma_dac.ready = 0; - if (val == AFMT_S16_LE) - fmtd |= ESS_FMT_16BIT << ESS_DAC_SHIFT; - else - fmtm &= ~(ESS_FMT_16BIT << ESS_DAC_SHIFT); - } - set_fmt(s, fmtm, fmtd); - } - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? - (ESS_FMT_16BIT << ESS_ADC_SHIFT) - : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? - AFMT_S16_LE : - AFMT_U8, - p); - - case SNDCTL_DSP_POST: - return 0; - - case SNDCTL_DSP_GETTRIGGER: - val = 0; - if ((file->f_mode & FMODE_READ) && (s->enable & ADC_RUNNING)) - val |= PCM_ENABLE_INPUT; - if ((file->f_mode & FMODE_WRITE) && (s->enable & DAC_RUNNING)) - val |= PCM_ENABLE_OUTPUT; - return put_user(val, p); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, p)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - if (val & PCM_ENABLE_INPUT) { - if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) - return ret; - start_adc(s); - } else - stop_adc(s); - } - if (file->f_mode & FMODE_WRITE) { - if (val & PCM_ENABLE_OUTPUT) { - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; - start_dac(s); - } else - stop_dac(s); - } - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; - spin_lock_irqsave(&s->lock, flags); - ess_update_ptr(s); - abinfo.fragsize = s->dma_dac.fragsize; - abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count; - abinfo.fragstotal = s->dma_dac.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) - return ret; - spin_lock_irqsave(&s->lock, flags); - ess_update_ptr(s); - abinfo.fragsize = s->dma_adc.fragsize; - abinfo.bytes = s->dma_adc.count; - abinfo.fragstotal = s->dma_adc.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; - spin_lock_irqsave(&s->lock, flags); - ess_update_ptr(s); - val = s->dma_dac.count; - spin_unlock_irqrestore(&s->lock, flags); - return put_user(val, p); - - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) - return ret; - spin_lock_irqsave(&s->lock, flags); - ess_update_ptr(s); - cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; - cinfo.ptr = s->dma_adc.hwptr; - if (s->dma_adc.mapped) - s->dma_adc.count &= s->dma_adc.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); - if (copy_to_user(argp, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) - return ret; - spin_lock_irqsave(&s->lock, flags); - ess_update_ptr(s); - cinfo.bytes = s->dma_dac.total_bytes; - cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift; - cinfo.ptr = s->dma_dac.hwptr; - if (s->dma_dac.mapped) - s->dma_dac.count &= s->dma_dac.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); - if (copy_to_user(argp, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETBLKSIZE: - if (file->f_mode & FMODE_WRITE) { - if ((val = prog_dmabuf(s, 0))) - return val; - return put_user(s->dma_dac.fragsize, p); - } - if ((val = prog_dmabuf(s, 1))) - return val; - return put_user(s->dma_adc.fragsize, p); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, p)) - return -EFAULT; - M_printk("maestro: SETFRAGMENT: %0x\n",val); - if (file->f_mode & FMODE_READ) { - s->dma_adc.ossfragshift = val & 0xffff; - s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_adc.ossfragshift < 4) - s->dma_adc.ossfragshift = 4; - if (s->dma_adc.ossfragshift > 15) - s->dma_adc.ossfragshift = 15; - if (s->dma_adc.ossmaxfrags < 4) - s->dma_adc.ossmaxfrags = 4; - } - if (file->f_mode & FMODE_WRITE) { - s->dma_dac.ossfragshift = val & 0xffff; - s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_dac.ossfragshift < 4) - s->dma_dac.ossfragshift = 4; - if (s->dma_dac.ossfragshift > 15) - s->dma_dac.ossfragshift = 15; - if (s->dma_dac.ossmaxfrags < 4) - s->dma_dac.ossmaxfrags = 4; - } - return 0; - - case SNDCTL_DSP_SUBDIVIDE: - if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || - (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) - return -EINVAL; - if (get_user(val, p)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - if (file->f_mode & FMODE_READ) - s->dma_adc.subdivision = val; - if (file->f_mode & FMODE_WRITE) - s->dma_dac.subdivision = val; - return 0; - - case SOUND_PCM_READ_RATE: - return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p); - - case SOUND_PCM_READ_CHANNELS: - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT) - : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p); - - case SOUND_PCM_READ_BITS: - return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_16BIT << ESS_ADC_SHIFT) - : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 16 : 8, p); - - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - - } - return -EINVAL; -} - -static void -set_base_registers(struct ess_state *s,void *vaddr) -{ - unsigned long packed_phys = virt_to_bus(vaddr)>>12; - wave_set_register(s, 0x01FC , packed_phys); - wave_set_register(s, 0x01FD , packed_phys); - wave_set_register(s, 0x01FE , packed_phys); - wave_set_register(s, 0x01FF , packed_phys); -} - -/* - * this guy makes sure we're in the right power - * state for what we want to be doing - */ -static void maestro_power(struct ess_card *card, int tostate) -{ - u16 active_mask = acpi_state_mask[tostate]; - u8 state; - - if(!use_pm) return; - - pci_read_config_byte(card->pcidev, card->power_regs+0x4, &state); - state&=3; - - /* make sure we're in the right state */ - if(state != tostate) { - M_printk(KERN_WARNING "maestro: dev %02x:%02x.%x switching from D%d to D%d\n", - card->pcidev->bus->number, - PCI_SLOT(card->pcidev->devfn), - PCI_FUNC(card->pcidev->devfn), - state,tostate); - pci_write_config_byte(card->pcidev, card->power_regs+0x4, tostate); - } - - /* and make sure the units we care about are on - XXX we might want to do this before state flipping? */ - pci_write_config_word(card->pcidev, 0x54, ~ active_mask); - pci_write_config_word(card->pcidev, 0x56, ~ active_mask); -} - -/* we allocate a large power of two for all our memory. - this is cut up into (not to scale :): - |silly fifo word | 512byte mixbuf per adc | dac/adc * channels | -*/ -static int -allocate_buffers(struct ess_state *s) -{ - void *rawbuf=NULL; - int order,i; - struct page *page, *pend; - - /* alloc as big a chunk as we can */ - for (order = (dsps_order + (16-PAGE_SHIFT) + 1); order >= (dsps_order + 2 + 1); order--) - if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order))) - break; - - if (!rawbuf) - return 1; - - M_printk("maestro: allocated %ld (%d) bytes at %p\n",PAGE_SIZE<card->dmapages = rawbuf; - s->card->dmaorder = order; - - for(i=0;icard->channels[i]; - - if(ess->dev_audio == -1) - continue; - - ess->dma_dac.ready = s->dma_dac.mapped = 0; - ess->dma_adc.ready = s->dma_adc.mapped = 0; - ess->dma_adc.buforder = ess->dma_dac.buforder = order - 1 - dsps_order - 1; - - /* offset dac and adc buffers starting half way through and then at each [da][ad]c's - order's intervals.. */ - ess->dma_dac.rawbuf = rawbuf + (PAGE_SIZE<<(order-1)) + (i * ( PAGE_SIZE << (ess->dma_dac.buforder + 1 ))); - ess->dma_adc.rawbuf = ess->dma_dac.rawbuf + ( PAGE_SIZE << ess->dma_dac.buforder); - /* offset mixbuf by a mixbuf so that the lame status fifo can - happily scribble away.. */ - ess->mixbuf = rawbuf + (512 * (i+1)); - - M_printk("maestro: setup apu %d: dac: %p adc: %p mix: %p\n",i,ess->dma_dac.rawbuf, - ess->dma_adc.rawbuf, ess->mixbuf); - - } - - /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */ - pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1); - for (page = virt_to_page(rawbuf); page <= pend; page++) - SetPageReserved(page); - - return 0; -} -static void -free_buffers(struct ess_state *s) -{ - struct page *page, *pend; - - s->dma_dac.rawbuf = s->dma_adc.rawbuf = NULL; - s->dma_dac.mapped = s->dma_adc.mapped = 0; - s->dma_dac.ready = s->dma_adc.ready = 0; - - M_printk("maestro: freeing %p\n",s->card->dmapages); - /* undo marking the pages as reserved */ - - pend = virt_to_page(s->card->dmapages + (PAGE_SIZE << s->card->dmaorder) - 1); - for (page = virt_to_page(s->card->dmapages); page <= pend; page++) - ClearPageReserved(page); - - free_pages((unsigned long)s->card->dmapages,s->card->dmaorder); - s->card->dmapages = NULL; -} - -static int -ess_open(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode); - struct ess_state *s = NULL; - unsigned char fmtm = ~0, fmts = 0; - struct pci_dev *pdev = NULL; - /* - * Scan the cards and find the channel. We only - * do this at open time so it is ok - */ - - while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { - struct ess_card *c; - struct pci_driver *drvr; - - drvr = pci_dev_driver (pdev); - if (drvr == &maestro_pci_driver) { - int i; - struct ess_state *sp; - - c = (struct ess_card*)pci_get_drvdata (pdev); - if (!c) - continue; - for(i=0;ichannels[i]; - if(sp->dev_audio < 0) - continue; - if((sp->dev_audio ^ minor) & ~0xf) - continue; - s=sp; - } - } - } - if (!s) - return -ENODEV; - - VALIDATE_STATE(s); - file->private_data = s; - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & file->f_mode) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_mutex); - return -EWOULDBLOCK; - } - mutex_unlock(&s->open_mutex); - interruptible_sleep_on(&s->open_wait); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_mutex); - } - - /* under semaphore.. */ - if ((s->card->dmapages==NULL) && allocate_buffers(s)) { - mutex_unlock(&s->open_mutex); - return -ENOMEM; - } - - /* we're covered by the open_mutex */ - if( ! s->card->dsps_open ) { - maestro_power(s->card,ACPI_D0); - start_bob(s); - } - s->card->dsps_open++; - M_printk("maestro: open, %d bobs now\n",s->card->dsps_open); - - /* ok, lets write WC base regs now that we've - powered up the chip */ - M_printk("maestro: writing 0x%lx (bus 0x%lx) to the wp\n",virt_to_bus(s->card->dmapages), - ((virt_to_bus(s->card->dmapages))&0xFFE00000)>>12); - set_base_registers(s,s->card->dmapages); - - if (file->f_mode & FMODE_READ) { -/* - fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT); - if ((minor & 0xf) == SND_DEV_DSP16) - fmts |= ESS_FMT_16BIT << ESS_ADC_SHIFT; */ - - fmtm &= ~((ESS_FMT_STEREO|ESS_FMT_16BIT) << ESS_ADC_SHIFT); - fmts = (ESS_FMT_STEREO|ESS_FMT_16BIT) << ESS_ADC_SHIFT; - - s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; - set_adc_rate(s, 8000); - } - if (file->f_mode & FMODE_WRITE) { - fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_DAC_SHIFT); - if ((minor & 0xf) == SND_DEV_DSP16) - fmts |= ESS_FMT_16BIT << ESS_DAC_SHIFT; - - s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0; - set_dac_rate(s, 8000); - } - set_fmt(s, fmtm, fmts); - s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - - mutex_unlock(&s->open_mutex); - return nonseekable_open(inode, file); -} - -static int -ess_release(struct inode *inode, struct file *file) -{ - struct ess_state *s = (struct ess_state *)file->private_data; - - VALIDATE_STATE(s); - lock_kernel(); - if (file->f_mode & FMODE_WRITE) - drain_dac(s, file->f_flags & O_NONBLOCK); - mutex_lock(&s->open_mutex); - if (file->f_mode & FMODE_WRITE) { - stop_dac(s); - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - } - - s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); - /* we're covered by the open_mutex */ - M_printk("maestro: %d dsps now alive\n",s->card->dsps_open-1); - if( --s->card->dsps_open <= 0) { - s->card->dsps_open = 0; - stop_bob(s); - free_buffers(s); - maestro_power(s->card,ACPI_D2); - } - mutex_unlock(&s->open_mutex); - wake_up(&s->open_wait); - unlock_kernel(); - return 0; -} - -static struct file_operations ess_audio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = ess_read, - .write = ess_write, - .poll = ess_poll, - .ioctl = ess_ioctl, - .mmap = ess_mmap, - .open = ess_open, - .release = ess_release, -}; - -static int -maestro_config(struct ess_card *card) -{ - struct pci_dev *pcidev = card->pcidev; - struct ess_state *ess = &card->channels[0]; - int apu,iobase = card->iobase; - u16 w; - u32 n; - - /* We used to muck around with pci config space that - * we had no business messing with. We don't know enough - * about the machine to know which DMA mode is appropriate, - * etc. We were guessing wrong on some machines and making - * them unhappy. We now trust in the BIOS to do things right, - * which almost certainly means a new host of problems will - * arise with broken BIOS implementations. screw 'em. - * We're already intolerant of machines that don't assign - * IRQs. - */ - - /* do config work at full power */ - maestro_power(card,ACPI_D0); - - pci_read_config_word(pcidev, 0x50, &w); - - w&=~(1<<5); /* Don't swap left/right (undoc)*/ - - pci_write_config_word(pcidev, 0x50, w); - - pci_read_config_word(pcidev, 0x52, &w); - w&=~(1<<15); /* Turn off internal clock multiplier */ - /* XXX how do we know which to use? */ - w&=~(1<<14); /* External clock */ - - w|= (1<<7); /* Hardware volume control on */ - w|= (1<<6); /* Debounce off: easier to push the HWV buttons. */ - w&=~(1<<5); /* GPIO 4:5 */ - w|= (1<<4); /* Disconnect from the CHI. Enabling this made a dell 7500 work. */ - w&=~(1<<2); /* MIDI fix off (undoc) */ - w&=~(1<<1); /* reserved, always write 0 */ - pci_write_config_word(pcidev, 0x52, w); - - /* - * Legacy mode - */ - - pci_read_config_word(pcidev, 0x40, &w); - w|=(1<<15); /* legacy decode off */ - w&=~(1<<14); /* Disable SIRQ */ - w&=~(0x1f); /* disable mpu irq/io, game port, fm, SB */ - - pci_write_config_word(pcidev, 0x40, w); - - /* Set up 978 docking control chip. */ - pci_read_config_word(pcidev, 0x58, &w); - w|=1<<2; /* Enable 978. */ - w|=1<<3; /* Turn on 978 hardware volume control. */ - w&=~(1<<11); /* Turn on 978 mixer volume control. */ - pci_write_config_word(pcidev, 0x58, w); - - sound_reset(iobase); - - /* - * Ring Bus Setup - */ - - /* setup usual 0x34 stuff.. 0x36 may be chip specific */ - outw(0xC090, iobase+0x34); /* direct sound, stereo */ - udelay(20); - outw(0x3000, iobase+0x36); /* direct sound, stereo */ - udelay(20); - - - /* - * Reset the CODEC - */ - - maestro_ac97_reset(iobase,pcidev); - - /* - * Ring Bus Setup - */ - - n=inl(iobase+0x34); - n&=~0xF000; - n|=12<<12; /* Direct Sound, Stereo */ - outl(n, iobase+0x34); - - n=inl(iobase+0x34); - n&=~0x0F00; /* Modem off */ - outl(n, iobase+0x34); - - n=inl(iobase+0x34); - n&=~0x00F0; - n|=9<<4; /* DAC, Stereo */ - outl(n, iobase+0x34); - - n=inl(iobase+0x34); - n&=~0x000F; /* ASSP off */ - outl(n, iobase+0x34); - - n=inl(iobase+0x34); - n|=(1<<29); /* Enable ring bus */ - outl(n, iobase+0x34); - - n=inl(iobase+0x34); - n|=(1<<28); /* Enable serial bus */ - outl(n, iobase+0x34); - - n=inl(iobase+0x34); - n&=~0x00F00000; /* MIC off */ - outl(n, iobase+0x34); - - n=inl(iobase+0x34); - n&=~0x000F0000; /* I2S off */ - outl(n, iobase+0x34); - - - w=inw(iobase+0x18); - w&=~(1<<7); /* ClkRun off */ - outw(w, iobase+0x18); - - w=inw(iobase+0x18); - w&=~(1<<6); /* Hardware volume control interrupt off... for now. */ - outw(w, iobase+0x18); - - w=inw(iobase+0x18); - w&=~(1<<4); /* ASSP irq off */ - outw(w, iobase+0x18); - - w=inw(iobase+0x18); - w&=~(1<<3); /* ISDN irq off */ - outw(w, iobase+0x18); - - w=inw(iobase+0x18); - w|=(1<<2); /* Direct Sound IRQ on */ - outw(w, iobase+0x18); - - w=inw(iobase+0x18); - w&=~(1<<1); /* MPU401 IRQ off */ - outw(w, iobase+0x18); - - w=inw(iobase+0x18); - w|=(1<<0); /* SB IRQ on */ - outw(w, iobase+0x18); - - /* Set hardware volume control registers to midpoints. - We can tell which button was pushed based on how they change. */ - outb(0x88, iobase+0x1c); - outb(0x88, iobase+0x1d); - outb(0x88, iobase+0x1e); - outb(0x88, iobase+0x1f); - - /* it appears some maestros (dell 7500) only work if these are set, - regardless of whether we use the assp or not. */ - - outb(0, iobase+0xA4); - outb(3, iobase+0xA2); - outb(0, iobase+0xA6); - - for(apu=0;apu<16;apu++) - { - /* Write 0 into the buffer area 0x1E0->1EF */ - outw(0x01E0+apu, 0x10+iobase); - outw(0x0000, 0x12+iobase); - - /* - * The 1.10 test program seem to write 0 into the buffer area - * 0x1D0-0x1DF too. - */ - outw(0x01D0+apu, 0x10+iobase); - outw(0x0000, 0x12+iobase); - } - -#if 1 - wave_set_register(ess, IDR7_WAVE_ROMRAM, - (wave_get_register(ess, IDR7_WAVE_ROMRAM)&0xFF00)); - wave_set_register(ess, IDR7_WAVE_ROMRAM, - wave_get_register(ess, IDR7_WAVE_ROMRAM)|0x100); - wave_set_register(ess, IDR7_WAVE_ROMRAM, - wave_get_register(ess, IDR7_WAVE_ROMRAM)&~0x200); - wave_set_register(ess, IDR7_WAVE_ROMRAM, - wave_get_register(ess, IDR7_WAVE_ROMRAM)|~0x400); -#else - maestro_write(ess, IDR7_WAVE_ROMRAM, - (maestro_read(ess, IDR7_WAVE_ROMRAM)&0xFF00)); - maestro_write(ess, IDR7_WAVE_ROMRAM, - maestro_read(ess, IDR7_WAVE_ROMRAM)|0x100); - maestro_write(ess, IDR7_WAVE_ROMRAM, - maestro_read(ess, IDR7_WAVE_ROMRAM)&~0x200); - maestro_write(ess, IDR7_WAVE_ROMRAM, - maestro_read(ess, IDR7_WAVE_ROMRAM)|0x400); -#endif - - maestro_write(ess, IDR2_CRAM_DATA, 0x0000); - maestro_write(ess, 0x08, 0xB004); - /* Now back to the DirectSound stuff */ - maestro_write(ess, 0x09, 0x001B); - maestro_write(ess, 0x0A, 0x8000); - maestro_write(ess, 0x0B, 0x3F37); - maestro_write(ess, 0x0C, 0x0098); - - /* parallel out ?? */ - maestro_write(ess, 0x0C, - (maestro_read(ess, 0x0C)&~0xF000)|0x8000); - /* parallel in, has something to do with recording :) */ - maestro_write(ess, 0x0C, - (maestro_read(ess, 0x0C)&~0x0F00)|0x0500); - - maestro_write(ess, 0x0D, 0x7632); - - /* Wave cache control on - test off, sg off, - enable, enable extra chans 1Mb */ - - outw(inw(0x14+iobase)|(1<<8),0x14+iobase); - outw(inw(0x14+iobase)&0xFE03,0x14+iobase); - outw((inw(0x14+iobase)&0xFFFC), 0x14+iobase); - outw(inw(0x14+iobase)|(1<<7),0x14+iobase); - - outw(0xA1A0, 0x14+iobase); /* 0300 ? */ - - /* Now clear the APU control ram */ - for(apu=0;apupower_regs = 0; - - /* check to see if we have a capabilities list in - the config register */ - pci_read_config_word(pcidev, PCI_STATUS, &w); - if(!(w & PCI_STATUS_CAP_LIST)) return 0; - - /* walk the list, starting at the head. */ - pci_read_config_byte(pcidev,PCI_CAPABILITY_LIST,&next); - - while(next && max--) { - pci_read_config_dword(pcidev, next & ~3, &n); - if((n & 0xff) == PCI_CAP_ID_PM) { - card->power_regs = next; - break; - } - next = ((n>>8) & 0xff); - } - - return card->power_regs ? 1 : 0; -} - -static int __init -maestro_probe(struct pci_dev *pcidev,const struct pci_device_id *pdid) -{ - int card_type = pdid->driver_data; - u32 n; - int iobase; - int i, ret; - struct ess_card *card; - struct ess_state *ess; - int num = 0; - -/* when built into the kernel, we only print version if device is found */ -#ifndef MODULE - static int printed_version; - if (!printed_version++) - printk(version); -#endif - - /* don't pick up weird modem maestros */ - if(((pcidev->class >> 8) & 0xffff) != PCI_CLASS_MULTIMEDIA_AUDIO) - return -ENODEV; - - - if ((ret=pci_enable_device(pcidev))) - return ret; - - iobase = pci_resource_start(pcidev,0); - if (!iobase || !(pci_resource_flags(pcidev, 0 ) & IORESOURCE_IO)) - return -ENODEV; - - if(pcidev->irq == 0) - return -ENODEV; - - /* stake our claim on the iospace */ - if( request_region(iobase, 256, card_names[card_type]) == NULL ) - { - printk(KERN_WARNING "maestro: can't allocate 256 bytes I/O at 0x%4.4x\n", iobase); - return -EBUSY; - } - - /* just to be sure */ - pci_set_master(pcidev); - - card = kmalloc(sizeof(struct ess_card), GFP_KERNEL); - if(card == NULL) - { - printk(KERN_WARNING "maestro: out of memory\n"); - release_region(iobase, 256); - return -ENOMEM; - } - - memset(card, 0, sizeof(*card)); - card->pcidev = pcidev; - - card->iobase = iobase; - card->card_type = card_type; - card->irq = pcidev->irq; - card->magic = ESS_CARD_MAGIC; - spin_lock_init(&card->lock); - init_waitqueue_head(&card->suspend_queue); - - card->dock_mute_vol = 50; - - /* init our groups of 6 apus */ - for(i=0;ichannels[i]; - - s->index = i; - - s->card = card; - init_waitqueue_head(&s->dma_adc.wait); - init_waitqueue_head(&s->dma_dac.wait); - init_waitqueue_head(&s->open_wait); - spin_lock_init(&s->lock); - mutex_init(&s->open_mutex); - s->magic = ESS_STATE_MAGIC; - - s->apu[0] = 6*i; - s->apu[1] = (6*i)+1; - s->apu[2] = (6*i)+2; - s->apu[3] = (6*i)+3; - s->apu[4] = (6*i)+4; - s->apu[5] = (6*i)+5; - - if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf) - printk("maestro: BOTCH!\n"); - /* register devices */ - if ((s->dev_audio = register_sound_dsp(&ess_audio_fops, -1)) < 0) - break; - } - - num = i; - - /* clear the rest if we ran out of slots to register */ - for(;ichannels[i]; - s->dev_audio = -1; - } - - ess = &card->channels[0]; - - /* - * Ok card ready. Begin setup proper - */ - - printk(KERN_INFO "maestro: Configuring %s found at IO 0x%04X IRQ %d\n", - card_names[card_type],iobase,card->irq); - pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &n); - printk(KERN_INFO "maestro: subvendor id: 0x%08x\n",n); - - /* turn off power management unless: - * - the user explicitly asks for it - * or - * - we're not a 2e, lesser chipps seem to have problems. - * - we're not on our _very_ small whitelist. some implemenetations - * really don't like the pm code, others require it. - * feel free to expand this as required. - */ -#define SUBSYSTEM_VENDOR(x) (x&0xffff) - if( (use_pm != 1) && - ((card_type != TYPE_MAESTRO2E) || (SUBSYSTEM_VENDOR(n) != 0x1028))) - use_pm = 0; - - if(!use_pm) - printk(KERN_INFO "maestro: not attempting power management.\n"); - else { - if(!parse_power(card,pcidev)) - printk(KERN_INFO "maestro: no PCI power management interface found.\n"); - else { - pci_read_config_dword(pcidev, card->power_regs, &n); - printk(KERN_INFO "maestro: PCI power management capability: 0x%x\n",n>>16); - } - } - - maestro_config(card); - - if(maestro_ac97_get(card, 0x00)==0x0080) { - printk(KERN_ERR "maestro: my goodness! you seem to have a pt101 codec, which is quite rare.\n" - "\tyou should tell someone about this.\n"); - } else { - maestro_ac97_init(card); - } - - if ((card->dev_mixer = register_sound_mixer(&ess_mixer_fops, -1)) < 0) { - printk("maestro: couldn't register mixer!\n"); - } else { - memcpy(card->mix.mixer_state,mixer_defaults,sizeof(card->mix.mixer_state)); - mixer_push_state(card); - } - - if((ret=request_irq(card->irq, ess_interrupt, IRQF_SHARED, card_names[card_type], card))) - { - printk(KERN_ERR "maestro: unable to allocate irq %d,\n", card->irq); - unregister_sound_mixer(card->dev_mixer); - for(i=0;ichannels[i]; - if(s->dev_audio != -1) - unregister_sound_dsp(s->dev_audio); - } - release_region(card->iobase, 256); - unregister_reboot_notifier(&maestro_nb); - kfree(card); - return ret; - } - - /* Turn on hardware volume control interrupt. - This has to come after we grab the IRQ above, - or a crash will result on installation if a button has been pressed, - because in that case we'll get an immediate interrupt. */ - n = inw(iobase+0x18); - n|=(1<<6); - outw(n, iobase+0x18); - - pci_set_drvdata(pcidev,card); - /* now go to sleep 'till something interesting happens */ - maestro_power(card,ACPI_D2); - - printk(KERN_INFO "maestro: %d channels configured.\n", num); - return 0; -} - -static void maestro_remove(struct pci_dev *pcidev) { - struct ess_card *card = pci_get_drvdata(pcidev); - int i; - u32 n; - - /* XXX maybe should force stop bob, but should be all - stopped by _release by now */ - - /* Turn off hardware volume control interrupt. - This has to come before we leave the IRQ below, - or a crash results if a button is pressed ! */ - n = inw(card->iobase+0x18); - n&=~(1<<6); - outw(n, card->iobase+0x18); - - free_irq(card->irq, card); - unregister_sound_mixer(card->dev_mixer); - for(i=0;ichannels[i]; - if(ess->dev_audio != -1) - unregister_sound_dsp(ess->dev_audio); - } - /* Goodbye, Mr. Bond. */ - maestro_power(card,ACPI_D3); - release_region(card->iobase, 256); - kfree(card); - pci_set_drvdata(pcidev,NULL); -} - -static struct pci_device_id maestro_pci_tbl[] = { - {PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1968, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO2}, - {PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1978, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO2E}, - {PCI_VENDOR_ESS_OLD, PCI_DEVICE_ID_ESS_ESS0100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO}, - {0,} -}; -MODULE_DEVICE_TABLE(pci, maestro_pci_tbl); - -static struct pci_driver maestro_pci_driver = { - .name = "maestro", - .id_table = maestro_pci_tbl, - .probe = maestro_probe, - .remove = maestro_remove, -}; - -static int __init init_maestro(void) -{ - int rc; - - rc = pci_register_driver(&maestro_pci_driver); - if (rc < 0) - return rc; - - if (register_reboot_notifier(&maestro_nb)) - printk(KERN_WARNING "maestro: reboot notifier registration failed; may not reboot properly.\n"); -#ifdef MODULE - printk(version); -#endif - if (dsps_order < 0) { - dsps_order = 1; - printk(KERN_WARNING "maestro: clipping dsps_order to %d\n",dsps_order); - } - else if (dsps_order > MAX_DSP_ORDER) { - dsps_order = MAX_DSP_ORDER; - printk(KERN_WARNING "maestro: clipping dsps_order to %d\n",dsps_order); - } - return 0; -} - -static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf) -{ - /* this notifier is called when the kernel is really shut down. */ - M_printk("maestro: shutting down\n"); - /* this will remove all card instances too */ - pci_unregister_driver(&maestro_pci_driver); - /* XXX dunno about power management */ - return NOTIFY_OK; -} - -/* --------------------------------------------------------------------- */ - - -static void cleanup_maestro(void) { - M_printk("maestro: unloading\n"); - pci_unregister_driver(&maestro_pci_driver); - unregister_reboot_notifier(&maestro_nb); -} - -/* --------------------------------------------------------------------- */ - -void -check_suspend(struct ess_card *card) -{ - DECLARE_WAITQUEUE(wait, current); - - if(!card->in_suspend) return; - - card->in_suspend++; - add_wait_queue(&(card->suspend_queue), &wait); - current->state = TASK_UNINTERRUPTIBLE; - schedule(); - remove_wait_queue(&(card->suspend_queue), &wait); - current->state = TASK_RUNNING; -} - -module_init(init_maestro); -module_exit(cleanup_maestro); -- cgit v1.2.3-59-g8ed1b