summaryrefslogtreecommitdiffstats
path: root/sound/oss/dmasound/dmasound_awacs.c
diff options
context:
space:
mode:
authorAdrian Bunk <bunk@stusta.de>2007-10-18 03:06:12 -0700
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-18 14:37:26 -0700
commitfc37449f7959aeedc2d38b183468ae73c9166fb6 (patch)
tree3aaf169f3b9d9c9deb69802aa7c81354d55cf0c8 /sound/oss/dmasound/dmasound_awacs.c
parent5b4db0c2f25925fcfc17fa7233b7b90dc023d207 (diff)
The next round of scheduled OSS code removal
This patch contains the next round of scheduled OSS code removal. Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'sound/oss/dmasound/dmasound_awacs.c')
-rw-r--r--sound/oss/dmasound/dmasound_awacs.c3215
1 files changed, 0 insertions, 3215 deletions
diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c
deleted file mode 100644
index 8f6388004f44..000000000000
--- a/sound/oss/dmasound/dmasound_awacs.c
+++ /dev/null
@@ -1,3215 +0,0 @@
-/*
- * linux/sound/oss/dmasound/dmasound_awacs.c
- *
- * PowerMac `AWACS' and `Burgundy' DMA Sound Driver
- * with some limited support for DACA & Tumbler
- *
- * See linux/sound/oss/dmasound/dmasound_core.c for copyright and
- * history prior to 2001/01/26.
- *
- * 26/01/2001 ed 0.1 Iain Sandoe
- * - added version info.
- * - moved dbdma command buffer allocation to PMacXXXSqSetup()
- * - fixed up beep dbdma cmd buffers
- *
- * 08/02/2001 [0.2]
- * - make SNDCTL_DSP_GETFMTS return the correct info for the h/w
- * - move soft format translations to a separate file
- * - [0.3] make SNDCTL_DSP_GETCAPS return correct info.
- * - [0.4] more informative machine name strings.
- * - [0.5]
- * - record changes.
- * - made the default_hard/soft entries.
- * 04/04/2001 [0.6]
- * - minor correction to bit assignments in awacs_defs.h
- * - incorporate mixer changes from 2.2.x back-port.
- * - take out passthru as a rec input (it isn't).
- * - make Input Gain slider work the 'right way up'.
- * - try to make the mixer sliders more logical - so now the
- * input selectors are just two-state (>50% == ON) and the
- * Input Gain slider handles the rest of the gain issues.
- * - try to pick slider representations that most closely match
- * the actual use - e.g. IGain for input gain...
- * - first stab at over/under-run detection.
- * - minor cosmetic changes to IRQ identification.
- * - fix bug where rates > max would be reported as supported.
- * - first stab at over/under-run detection.
- * - make use of i2c for mixer settings conditional on perch
- * rather than cuda (some machines without perch have cuda).
- * - fix bug where TX stops when dbdma status comes up "DEAD"
- * so far only reported on PowerComputing clones ... but.
- * - put in AWACS/Screamer register write timeouts.
- * - part way to partitioning the init() stuff
- * - first pass at 'tumbler' stuff (not support - just an attempt
- * to allow the driver to load on new G4s).
- * 01/02/2002 [0.7] - BenH
- * - all sort of minor bits went in since the latest update, I
- * bumped the version number for that reason
- *
- * 07/26/2002 [0.8] - BenH
- * - More minor bits since last changelog (I should be more careful
- * with those)
- * - Support for snapper & better tumbler integration by Toby Sargeant
- * - Headphone detect for scremer by Julien Blache
- * - More tumbler fixed by Andreas Schwab
- * 11/29/2003 [0.8.1] - Renzo Davoli (King Enzo)
- * - Support for Snapper line in
- * - snapper input resampling (for rates < 44100)
- * - software line gain control
- */
-
-/* GENERAL FIXME/TODO: check that the assumptions about what is written to
- mac-io is valid for DACA & Tumbler.
-
- This driver is in bad need of a rewrite. The dbdma code has to be split,
- some proper device-tree parsing code has to be written, etc...
-*/
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/soundcard.h>
-#include <linux/adb.h>
-#include <linux/nvram.h>
-#include <linux/tty.h>
-#include <linux/vt_kern.h>
-#include <linux/spinlock.h>
-#include <linux/kmod.h>
-#include <linux/interrupt.h>
-#include <linux/input.h>
-#include <linux/mutex.h>
-#ifdef CONFIG_ADB_CUDA
-#include <linux/cuda.h>
-#endif
-#ifdef CONFIG_ADB_PMU
-#include <linux/pmu.h>
-#endif
-
-#include <asm/uaccess.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/dbdma.h>
-#include <asm/pmac_feature.h>
-#include <asm/irq.h>
-#include <asm/nvram.h>
-
-#include "awacs_defs.h"
-#include "dmasound.h"
-#include "tas3001c.h"
-#include "tas3004.h"
-#include "tas_common.h"
-
-#define DMASOUND_AWACS_REVISION 0
-#define DMASOUND_AWACS_EDITION 7
-
-#define AWACS_SNAPPER 110 /* fake revision # for snapper */
-#define AWACS_BURGUNDY 100 /* fake revision # for burgundy */
-#define AWACS_TUMBLER 90 /* fake revision # for tumbler */
-#define AWACS_DACA 80 /* fake revision # for daca (ibook) */
-#define AWACS_AWACS 2 /* holding revision for AWACS */
-#define AWACS_SCREAMER 3 /* holding revision for Screamer */
-/*
- * Interrupt numbers and addresses, & info obtained from the device tree.
- */
-static int awacs_irq, awacs_tx_irq, awacs_rx_irq;
-static volatile struct awacs_regs __iomem *awacs;
-static volatile u32 __iomem *i2s;
-static volatile struct dbdma_regs __iomem *awacs_txdma, *awacs_rxdma;
-static int awacs_rate_index;
-static int awacs_subframe;
-static struct device_node* awacs_node;
-static struct device_node* i2s_node;
-static struct resource awacs_rsrc[3];
-
-static char awacs_name[64];
-static int awacs_revision;
-static int awacs_sleeping;
-static DEFINE_MUTEX(dmasound_mutex);
-
-static int sound_device_id; /* exists after iMac revA */
-static int hw_can_byteswap = 1 ; /* most pmac sound h/w can */
-
-/* model info */
-/* To be replaced with better interaction with pmac_feature.c */
-static int is_pbook_3X00;
-static int is_pbook_g3;
-
-/* expansion info */
-static int has_perch;
-static int has_ziva;
-
-/* for earlier powerbooks which need fiddling with mac-io to enable
- * cd etc.
-*/
-static unsigned char __iomem *latch_base;
-static unsigned char __iomem *macio_base;
-
-/*
- * Space for the DBDMA command blocks.
- */
-static void *awacs_tx_cmd_space;
-static volatile struct dbdma_cmd *awacs_tx_cmds;
-static int number_of_tx_cmd_buffers;
-
-static void *awacs_rx_cmd_space;
-static volatile struct dbdma_cmd *awacs_rx_cmds;
-static int number_of_rx_cmd_buffers;
-
-/*
- * Cached values of AWACS registers (we can't read them).
- * Except on the burgundy (and screamer). XXX
- */
-
-int awacs_reg[8];
-int awacs_reg1_save;
-
-/* tracking values for the mixer contents
-*/
-
-static int spk_vol;
-static int line_vol;
-static int passthru_vol;
-
-static int ip_gain; /* mic preamp settings */
-static int rec_lev = 0x4545 ; /* default CD gain 69 % */
-static int mic_lev;
-static int cd_lev = 0x6363 ; /* 99 % */
-static int line_lev;
-
-static int hdp_connected;
-
-/*
- * Stuff for outputting a beep. The values range from -327 to +327
- * so we can multiply by an amplitude in the range 0..100 to get a
- * signed short value to put in the output buffer.
- */
-static short beep_wform[256] = {
- 0, 40, 79, 117, 153, 187, 218, 245,
- 269, 288, 304, 316, 323, 327, 327, 324,
- 318, 310, 299, 288, 275, 262, 249, 236,
- 224, 213, 204, 196, 190, 186, 183, 182,
- 182, 183, 186, 189, 192, 196, 200, 203,
- 206, 208, 209, 209, 209, 207, 204, 201,
- 197, 193, 188, 183, 179, 174, 170, 166,
- 163, 161, 160, 159, 159, 160, 161, 162,
- 164, 166, 168, 169, 171, 171, 171, 170,
- 169, 167, 163, 159, 155, 150, 144, 139,
- 133, 128, 122, 117, 113, 110, 107, 105,
- 103, 103, 103, 103, 104, 104, 105, 105,
- 105, 103, 101, 97, 92, 86, 78, 68,
- 58, 45, 32, 18, 3, -11, -26, -41,
- -55, -68, -79, -88, -95, -100, -102, -102,
- -99, -93, -85, -75, -62, -48, -33, -16,
- 0, 16, 33, 48, 62, 75, 85, 93,
- 99, 102, 102, 100, 95, 88, 79, 68,
- 55, 41, 26, 11, -3, -18, -32, -45,
- -58, -68, -78, -86, -92, -97, -101, -103,
- -105, -105, -105, -104, -104, -103, -103, -103,
- -103, -105, -107, -110, -113, -117, -122, -128,
- -133, -139, -144, -150, -155, -159, -163, -167,
- -169, -170, -171, -171, -171, -169, -168, -166,
- -164, -162, -161, -160, -159, -159, -160, -161,
- -163, -166, -170, -174, -179, -183, -188, -193,
- -197, -201, -204, -207, -209, -209, -209, -208,
- -206, -203, -200, -196, -192, -189, -186, -183,
- -182, -182, -183, -186, -190, -196, -204, -213,
- -224, -236, -249, -262, -275, -288, -299, -310,
- -318, -324, -327, -327, -323, -316, -304, -288,
- -269, -245, -218, -187, -153, -117, -79, -40,
-};
-
-/* beep support */
-#define BEEP_SRATE 22050 /* 22050 Hz sample rate */
-#define BEEP_BUFLEN 512
-#define BEEP_VOLUME 15 /* 0 - 100 */
-
-static int beep_vol = BEEP_VOLUME;
-static int beep_playing;
-static int awacs_beep_state;
-static short *beep_buf;
-static void *beep_dbdma_cmd_space;
-static volatile struct dbdma_cmd *beep_dbdma_cmd;
-
-/* Burgundy functions */
-static void awacs_burgundy_wcw(unsigned addr,unsigned newval);
-static unsigned awacs_burgundy_rcw(unsigned addr);
-static void awacs_burgundy_write_volume(unsigned address, int volume);
-static int awacs_burgundy_read_volume(unsigned address);
-static void awacs_burgundy_write_mvolume(unsigned address, int volume);
-static int awacs_burgundy_read_mvolume(unsigned address);
-
-/* we will allocate a single 'emergency' dbdma cmd block to use if the
- tx status comes up "DEAD". This happens on some PowerComputing Pmac
- clones, either owing to a bug in dbdma or some interaction between
- IDE and sound. However, this measure would deal with DEAD status if
- if appeared elsewhere.
-
- for the sake of memory efficiency we'll allocate this cmd as part of
- the beep cmd stuff.
-*/
-
-static volatile struct dbdma_cmd *emergency_dbdma_cmd;
-
-#ifdef CONFIG_PM
-/*
- * Stuff for restoring after a sleep.
- */
-static void awacs_sleep_notify(struct pmu_sleep_notifier *self, int when);
-struct pmu_sleep_notifier awacs_sleep_notifier = {
- awacs_sleep_notify, SLEEP_LEVEL_SOUND,
-};
-#endif /* CONFIG_PM */
-
-/* for (soft) sample rate translations */
-int expand_bal; /* Balance factor for expanding (not volume!) */
-int expand_read_bal; /* Balance factor for expanding reads (not volume!) */
-
-/*** Low level stuff *********************************************************/
-
-static void *PMacAlloc(unsigned int size, gfp_t flags);
-static void PMacFree(void *ptr, unsigned int size);
-static int PMacIrqInit(void);
-#ifdef MODULE
-static void PMacIrqCleanup(void);
-#endif
-static void PMacSilence(void);
-static void PMacInit(void);
-static int PMacSetFormat(int format);
-static int PMacSetVolume(int volume);
-static void PMacPlay(void);
-static void PMacRecord(void);
-static irqreturn_t pmac_awacs_tx_intr(int irq, void *devid);
-static irqreturn_t pmac_awacs_rx_intr(int irq, void *devid);
-static irqreturn_t pmac_awacs_intr(int irq, void *devid);
-static void awacs_write(int val);
-static int awacs_get_volume(int reg, int lshift);
-static int awacs_volume_setter(int volume, int n, int mute, int lshift);
-
-
-/*** Mid level stuff **********************************************************/
-
-static int PMacMixerIoctl(u_int cmd, u_long arg);
-static int PMacWriteSqSetup(void);
-static int PMacReadSqSetup(void);
-static void PMacAbortRead(void);
-
-extern TRANS transAwacsNormal ;
-extern TRANS transAwacsExpand ;
-extern TRANS transAwacsNormalRead ;
-extern TRANS transAwacsExpandRead ;
-
-extern int daca_init(void);
-extern void daca_cleanup(void);
-extern int daca_set_volume(uint left_vol, uint right_vol);
-extern void daca_get_volume(uint * left_vol, uint *right_vol);
-extern int daca_enter_sleep(void);
-extern int daca_leave_sleep(void);
-
-#define TRY_LOCK() \
- if ((rc = mutex_lock_interruptible(&dmasound_mutex)) != 0) \
- return rc;
-#define LOCK() mutex_lock(&dmasound_mutex);
-
-#define UNLOCK() mutex_unlock(&dmasound_mutex);
-
-/* We use different versions that the ones provided in dmasound.h
- *
- * FIXME: Use different names ;)
- */
-#undef IOCTL_IN
-#undef IOCTL_OUT
-
-#define IOCTL_IN(arg, ret) \
- rc = get_user(ret, (int __user *)(arg)); \
- if (rc) break;
-#define IOCTL_OUT(arg, ret) \
- ioctl_return2((int __user *)(arg), ret)
-
-static inline int ioctl_return2(int __user *addr, int value)
-{
- return value < 0 ? value : put_user(value, addr);
-}
-
-
-/*** AE - TUMBLER / SNAPPER START ************************************************/
-
-
-int gpio_audio_reset, gpio_audio_reset_pol;
-int gpio_amp_mute, gpio_amp_mute_pol;
-int gpio_headphone_mute, gpio_headphone_mute_pol;
-int gpio_headphone_detect, gpio_headphone_detect_pol;
-int gpio_headphone_irq;
-
-int
-setup_audio_gpio(const char *name, const char* compatible, int *gpio_addr, int* gpio_pol)
-{
- struct device_node *gpiop;
- struct device_node *np;
- const u32* pp;
- int ret = -ENODEV;
-
- gpiop = of_find_node_by_name(NULL, "gpio");
- if (!gpiop)
- goto done;
-
- np = of_get_next_child(gpiop, NULL);
- while(np != 0) {
- if (name) {
- const char *property =
- of_get_property(np,"audio-gpio",NULL);
- if (property != 0 && strcmp(property,name) == 0)
- break;
- } else if (compatible && of_device_is_compatible(np, compatible))
- break;
- np = of_get_next_child(gpiop, np);
- }
- if (!np)
- goto done;
- pp = of_get_property(np, "AAPL,address", NULL);
- if (!pp)
- goto done;
- *gpio_addr = (*pp) & 0x0000ffff;
- pp = of_get_property(np, "audio-gpio-active-state", NULL);
- if (pp)
- *gpio_pol = *pp;
- else
- *gpio_pol = 1;
- ret = irq_of_parse_and_map(np, 0);
-done:
- of_node_put(np);
- of_node_put(gpiop);
- return ret;
-}
-
-static inline void
-write_audio_gpio(int gpio_addr, int data)
-{
- if (!gpio_addr)
- return;
- pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio_addr, data ? 0x05 : 0x04);
-}
-
-static inline int
-read_audio_gpio(int gpio_addr)
-{
- if (!gpio_addr)
- return 0;
- return ((pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio_addr, 0) & 0x02) !=0);
-}
-
-/*
- * Headphone interrupt via GPIO (Tumbler, Snapper, DACA)
- */
-static irqreturn_t
-headphone_intr(int irq, void *devid)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dmasound.lock, flags);
- if (read_audio_gpio(gpio_headphone_detect) == gpio_headphone_detect_pol) {
- printk(KERN_INFO "Audio jack plugged, muting speakers.\n");
- write_audio_gpio(gpio_headphone_mute, !gpio_headphone_mute_pol);
- write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol);
- tas_output_device_change(sound_device_id,TAS_OUTPUT_HEADPHONES,0);
- } else {
- printk(KERN_INFO "Audio jack unplugged, enabling speakers.\n");
- write_audio_gpio(gpio_amp_mute, !gpio_amp_mute_pol);
- write_audio_gpio(gpio_headphone_mute, gpio_headphone_mute_pol);
- tas_output_device_change(sound_device_id,TAS_OUTPUT_INTERNAL_SPKR,0);
- }
- spin_unlock_irqrestore(&dmasound.lock, flags);
- return IRQ_HANDLED;
-}
-
-
-/* Initialize tumbler */
-
-static int
-tas_dmasound_init(void)
-{
- setup_audio_gpio(
- "audio-hw-reset",
- NULL,
- &gpio_audio_reset,
- &gpio_audio_reset_pol);
- setup_audio_gpio(
- "amp-mute",
- NULL,
- &gpio_amp_mute,
- &gpio_amp_mute_pol);
- setup_audio_gpio("headphone-mute",
- NULL,
- &gpio_headphone_mute,
- &gpio_headphone_mute_pol);
- gpio_headphone_irq = setup_audio_gpio(
- "headphone-detect",
- NULL,
- &gpio_headphone_detect,
- &gpio_headphone_detect_pol);
- /* Fix some broken OF entries in desktop machines */
- if (!gpio_headphone_irq)
- gpio_headphone_irq = setup_audio_gpio(
- NULL,
- "keywest-gpio15",
- &gpio_headphone_detect,
- &gpio_headphone_detect_pol);
-
- write_audio_gpio(gpio_audio_reset, gpio_audio_reset_pol);
- msleep(100);
- write_audio_gpio(gpio_audio_reset, !gpio_audio_reset_pol);
- msleep(100);
- if (gpio_headphone_irq) {
- if (request_irq(gpio_headphone_irq,headphone_intr,0,"Headphone detect",NULL) < 0) {
- printk(KERN_ERR "tumbler: Can't request headphone interrupt\n");
- gpio_headphone_irq = 0;
- } else {
- u8 val;
- /* Activate headphone status interrupts */
- val = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio_headphone_detect, 0);
- pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio_headphone_detect, val | 0x80);
- /* Trigger it */
- headphone_intr(0, NULL);
- }
- }
- if (!gpio_headphone_irq) {
- /* Some machine enter this case ? */
- printk(KERN_WARNING "tumbler: Headphone detect IRQ not found, enabling all outputs !\n");
- write_audio_gpio(gpio_amp_mute, !gpio_amp_mute_pol);
- write_audio_gpio(gpio_headphone_mute, !gpio_headphone_mute_pol);
- }
- return 0;
-}
-
-
-static int
-tas_dmasound_cleanup(void)
-{
- if (gpio_headphone_irq)
- free_irq(gpio_headphone_irq, NULL);
- return 0;
-}
-
-/* We don't support 48k yet */
-static int tas_freqs[1] = { 44100 } ;
-static int tas_freqs_ok[1] = { 1 } ;
-
-/* don't know what to do really - just have to leave it where
- * OF left things
-*/
-
-static int
-tas_set_frame_rate(void)
-{
- if (i2s) {
- out_le32(i2s + (I2S_REG_SERIAL_FORMAT >> 2), 0x41190000);
- out_le32(i2s + (I2S_REG_DATAWORD_SIZES >> 2), 0x02000200);
- }
- dmasound.hard.speed = 44100 ;
- awacs_rate_index = 0 ;
- return 44100 ;
-}
-
-static int
-tas_mixer_ioctl(u_int cmd, u_long arg)
-{
- int __user *argp = (int __user *)arg;
- int data;
- int rc;
-
- rc=tas_device_ioctl(cmd, arg);
- if (rc != -EINVAL) {
- return rc;
- }
-
- if ((cmd & ~0xff) == MIXER_WRITE(0) &&
- tas_supported_mixers() & (1<<(cmd & 0xff))) {
- rc = get_user(data, argp);
- if (rc<0) return rc;
- tas_set_mixer_level(cmd & 0xff, data);
- tas_get_mixer_level(cmd & 0xff, &data);
- return ioctl_return2(argp, data);
- }
- if ((cmd & ~0xff) == MIXER_READ(0) &&
- tas_supported_mixers() & (1<<(cmd & 0xff))) {
- tas_get_mixer_level(cmd & 0xff, &data);
- return ioctl_return2(argp, data);
- }
-
- switch(cmd) {
- case SOUND_MIXER_READ_DEVMASK:
- data = tas_supported_mixers() | SOUND_MASK_SPEAKER;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_READ_STEREODEVS:
- data = tas_stereo_mixers();
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_READ_CAPS:
- rc = IOCTL_OUT(arg, 0);
- break;
- case SOUND_MIXER_READ_RECMASK:
- // XXX FIXME: find a way to check what is really available */
- data = SOUND_MASK_LINE | SOUND_MASK_MIC;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_READ_RECSRC:
- if (awacs_reg[0] & MASK_MUX_AUDIN)
- data |= SOUND_MASK_LINE;
- if (awacs_reg[0] & MASK_MUX_MIC)
- data |= SOUND_MASK_MIC;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_WRITE_RECSRC:
- IOCTL_IN(arg, data);
- data =0;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_WRITE_SPEAKER: /* really bell volume */
- IOCTL_IN(arg, data);
- beep_vol = data & 0xff;
- /* fall through */
- case SOUND_MIXER_READ_SPEAKER:
- rc = IOCTL_OUT(arg, (beep_vol<<8) | beep_vol);
- break;
- case SOUND_MIXER_OUTMASK:
- case SOUND_MIXER_OUTSRC:
- default:
- rc = -EINVAL;
- }
-
- return rc;
-}
-
-static void __init
-tas_init_frame_rates(const unsigned int *prop, unsigned int l)
-{
- int i ;
- if (prop) {
- for (i=0; i<1; i++)
- tas_freqs_ok[i] = 0;
- for (l /= sizeof(int); l > 0; --l) {
- unsigned int r = *prop++;
- /* Apple 'Fixed' format */
- if (r >= 0x10000)
- r >>= 16;
- for (i = 0; i < 1; ++i) {
- if (r == tas_freqs[i]) {
- tas_freqs_ok[i] = 1;
- break;
- }
- }
- }
- }
- /* else we assume that all the rates are available */
-}
-
-
-/*** AE - TUMBLER / SNAPPER END ************************************************/
-
-
-
-/*** Low level stuff *********************************************************/
-
-/*
- * PCI PowerMac, with AWACS, Screamer, Burgundy, DACA or Tumbler and DBDMA.
- */
-static void *PMacAlloc(unsigned int size, gfp_t flags)
-{
- return kmalloc(size, flags);
-}
-
-static void PMacFree(void *ptr, unsigned int size)
-{
- kfree(ptr);
-}
-
-static int __init PMacIrqInit(void)
-{
- if (awacs)
- if (request_irq(awacs_irq, pmac_awacs_intr, 0, "Built-in Sound misc", NULL))
- return 0;
- if (request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "Built-in Sound out", NULL)
- || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "Built-in Sound in", NULL))
- return 0;
- return 1;
-}
-
-#ifdef MODULE
-static void PMacIrqCleanup(void)
-{
- /* turn off input & output dma */
- DBDMA_DO_STOP(awacs_txdma);
- DBDMA_DO_STOP(awacs_rxdma);
-
- if (awacs)
- /* disable interrupts from awacs interface */
- out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);
-
- /* Switch off the sound clock */
- pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 0);
- /* Make sure proper bits are set on pismo & tipb */
- if ((machine_is_compatible("PowerBook3,1") ||
- machine_is_compatible("PowerBook3,2")) && awacs) {
- awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1;
- awacs_write(MASK_ADDR1 | awacs_reg[1]);
- msleep(200);
- }
- if (awacs)
- free_irq(awacs_irq, NULL);
- free_irq(awacs_tx_irq, NULL);
- free_irq(awacs_rx_irq, NULL);
-
- if (awacs)
- iounmap(awacs);
- if (i2s)
- iounmap(i2s);
- iounmap(awacs_txdma);
- iounmap(awacs_rxdma);
-
- release_mem_region(awacs_rsrc[0].start,
- awacs_rsrc[0].end - awacs_rsrc[0].start + 1);
- release_mem_region(awacs_rsrc[1].start,
- awacs_rsrc[1].end - awacs_rsrc[1].start + 1);
- release_mem_region(awacs_rsrc[2].start,
- awacs_rsrc[2].end - awacs_rsrc[2].start + 1);
-
- kfree(awacs_tx_cmd_space);
- kfree(awacs_rx_cmd_space);
- kfree(beep_dbdma_cmd_space);
- kfree(beep_buf);
-#ifdef CONFIG_PM
- pmu_unregister_sleep_notifier(&awacs_sleep_notifier);
-#endif
-}
-#endif /* MODULE */
-
-static void PMacSilence(void)
-{
- /* turn off output dma */
- DBDMA_DO_STOP(awacs_txdma);
-}
-
-/* don't know what to do really - just have to leave it where
- * OF left things
-*/
-
-static int daca_set_frame_rate(void)
-{
- if (i2s) {
- out_le32(i2s + (I2S_REG_SERIAL_FORMAT >> 2), 0x41190000);
- out_le32(i2s + (I2S_REG_DATAWORD_SIZES >> 2), 0x02000200);
- }
- dmasound.hard.speed = 44100 ;
- awacs_rate_index = 0 ;
- return 44100 ;
-}
-
-static int awacs_freqs[8] = {
- 44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350
-};
-static int awacs_freqs_ok[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };
-
-static int
-awacs_set_frame_rate(int desired, int catch_r)
-{
- int tolerance, i = 8 ;
- /*
- * If we have a sample rate which is within catchRadius percent
- * of the requested value, we don't have to expand the samples.
- * Otherwise choose the next higher rate.
- * N.B.: burgundy awacs only works at 44100 Hz.
- */
- do {
- tolerance = catch_r * awacs_freqs[--i] / 100;
- if (awacs_freqs_ok[i]
- && dmasound.soft.speed <= awacs_freqs[i] + tolerance)
- break;
- } while (i > 0);
- dmasound.hard.speed = awacs_freqs[i];
- awacs_rate_index = i;
-
- out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11 );
- awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) | (i << 3);
- awacs_write(awacs_reg[1] | MASK_ADDR1);
- return dmasound.hard.speed;
-}
-
-static int
-burgundy_set_frame_rate(void)
-{
- awacs_rate_index = 0 ;
- awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) ;
- /* XXX disable error interrupt on burgundy for now */
- out_le32(&awacs->control, MASK_IEPC | 0 | 0x11 | MASK_IEE);
- return 44100 ;
-}
-
-static int
-set_frame_rate(int desired, int catch_r)
-{
- switch (awacs_revision) {
- case AWACS_BURGUNDY:
- dmasound.hard.speed = burgundy_set_frame_rate();
- break ;
- case AWACS_TUMBLER:
- case AWACS_SNAPPER:
- dmasound.hard.speed = tas_set_frame_rate();
- break ;
- case AWACS_DACA:
- dmasound.hard.speed =
- daca_set_frame_rate();
- break ;
- default:
- dmasound.hard.speed = awacs_set_frame_rate(desired,
- catch_r);
- break ;
- }
- return dmasound.hard.speed ;
-}
-
-static void
-awacs_recalibrate(void)
-{
- /* Sorry for the horrible delays... I hope to get that improved
- * by making the whole PM process asynchronous in a future version
- */
- msleep(750);
- awacs_reg[1] |= MASK_CMUTE | MASK_AMUTE;
- awacs_write(awacs_reg[1] | MASK_RECALIBRATE | MASK_ADDR1);
- msleep(1000);
- awacs_write(awacs_reg[1] | MASK_ADDR1);
-}
-
-static void PMacInit(void)
-{
- int tolerance;
-
- switch (dmasound.soft.format) {
- case AFMT_S16_LE:
- case AFMT_U16_LE:
- if (hw_can_byteswap)
- dmasound.hard.format = AFMT_S16_LE;
- else
- dmasound.hard.format = AFMT_S16_BE;
- break;
- default:
- dmasound.hard.format = AFMT_S16_BE;
- break;
- }
- dmasound.hard.stereo = 1;
- dmasound.hard.size = 16;
-
- /* set dmasound.hard.speed - on the basis of what we want (soft)
- * and the tolerance we'll allow.
- */
- set_frame_rate(dmasound.soft.speed, catchRadius) ;
-
- tolerance = (catchRadius * dmasound.hard.speed) / 100;
- if (dmasound.soft.speed >= dmasound.hard.speed - tolerance) {
- dmasound.trans_write = &transAwacsNormal;
- dmasound.trans_read = &transAwacsNormalRead;
- } else {
- dmasound.trans_write = &transAwacsExpand;
- dmasound.trans_read = &transAwacsExpandRead;
- }
-
- if (awacs) {
- if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE))
- out_le32(&awacs->byteswap, BS_VAL);
- else
- out_le32(&awacs->byteswap, 0);
- }
-
- expand_bal = -dmasound.soft.speed;
- expand_read_bal = -dmasound.soft.speed;
-}
-
-static int PMacSetFormat(int format)
-{
- int size;
- int req_format = format;
-
- switch (format) {
- case AFMT_QUERY:
- return dmasound.soft.format;
- case AFMT_MU_LAW:
- case AFMT_A_LAW:
- case AFMT_U8:
- case AFMT_S8:
- size = 8;
- break;
- case AFMT_S16_LE:
- if(!hw_can_byteswap)
- format = AFMT_S16_BE;
- case AFMT_S16_BE:
- size = 16;
- break;
- case AFMT_U16_LE:
- if(!hw_can_byteswap)
- format = AFMT_U16_BE;
- case AFMT_U16_BE:
- size = 16;
- break;
- default: /* :-) */
- printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n",
- format);
- size = 8;
- format = AFMT_U8;
- }
-
- if (req_format == format) {
- dmasound.soft.format = format;
- dmasound.soft.size = size;
- if (dmasound.minDev == SND_DEV_DSP) {
- dmasound.dsp.format = format;
- dmasound.dsp.size = size;
- }
- }
-
- return format;
-}
-
-#define AWACS_VOLUME_TO_MASK(x) (15 - ((((x) - 1) * 15) / 99))
-#define AWACS_MASK_TO_VOLUME(y) (100 - ((y) * 99 / 15))
-
-static int awacs_get_volume(int reg, int lshift)
-{
- int volume;
-
- volume = AWACS_MASK_TO_VOLUME((reg >> lshift) & 0xf);
- volume |= AWACS_MASK_TO_VOLUME(reg & 0xf) << 8;
- return volume;
-}
-
-static int awacs_volume_setter(int volume, int n, int mute, int lshift)
-{
- int r1, rn;
-
- if (mute && volume == 0) {
- r1 = awacs_reg[1] | mute;
- } else {
- r1 = awacs_reg[1] & ~mute;
- rn = awacs_reg[n] & ~(0xf | (0xf << lshift));
- rn |= ((AWACS_VOLUME_TO_MASK(volume & 0xff) & 0xf) << lshift);
- rn |= AWACS_VOLUME_TO_MASK((volume >> 8) & 0xff) & 0xf;
- awacs_reg[n] = rn;
- awacs_write((n << 12) | rn);
- volume = awacs_get_volume(rn, lshift);
- }
- if (r1 != awacs_reg[1]) {
- awacs_reg[1] = r1;
- awacs_write(r1 | MASK_ADDR1);
- }
- return volume;
-}
-
-static int PMacSetVolume(int volume)
-{
- printk(KERN_WARNING "Bogus call to PMacSetVolume !\n");
- return 0;
-}
-
-static void awacs_setup_for_beep(int speed)
-{
- out_le32(&awacs->control,
- (in_le32(&awacs->control) & ~0x1f00)
- | ((speed > 0 ? speed : awacs_rate_index) << 8));
-
- if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE) && speed == -1)
- out_le32(&awacs->byteswap, BS_VAL);
- else
- out_le32(&awacs->byteswap, 0);
-}
-
-/* CHECK: how much of this *really* needs IRQs masked? */
-static void __PMacPlay(void)
-{
- volatile struct dbdma_cmd *cp;
- int next_frg, count;
-
- count = 300 ; /* > two cycles at the lowest sample rate */
-
- /* what we want to send next */
- next_frg = (write_sq.front + write_sq.active) % write_sq.max_count;
-
- if (awacs_beep_state) {
- /* sound takes precedence over beeps */
- /* stop the dma channel */
- out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
- while ( (in_le32(&awacs_txdma->status) & RUN) && count--)
- udelay(1);
- if (awacs)
- awacs_setup_for_beep(-1);
- out_le32(&awacs_txdma->cmdptr,
- virt_to_bus(&(awacs_tx_cmds[next_frg])));
-
- beep_playing = 0;
- awacs_beep_state = 0;
- }
- /* this won't allow more than two frags to be in the output queue at
- once. (or one, if the max frags is 2 - because count can't exceed
- 2 in that case)
- */
- while (write_sq.active < 2 && write_sq.active < write_sq.count) {
- count = (write_sq.count == write_sq.active + 1) ?
- write_sq.rear_size:write_sq.block_size ;
- if (count < write_sq.block_size) {
- if (!write_sq.syncing) /* last block not yet filled,*/
- break; /* and we're not syncing or POST-ed */
- else {
- /* pretend the block is full to force a new
- block to be started on the next write */
- write_sq.rear_size = write_sq.block_size ;
- write_sq.syncing &= ~2 ; /* clear POST */
- }
- }
- cp = &awacs_tx_cmds[next_frg];
- st_le16(&cp->req_count, count);
- st_le16(&cp->xfer_status, 0);
- st_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS);
- /* put a STOP at the end of the queue - but only if we have
- space for it. This means that, if we under-run and we only
- have two fragments, we might re-play sound from an existing
- queued frag. I guess the solution to that is not to set two
- frags if you are likely to under-run...
- */
- if (write_sq.count < write_sq.max_count) {
- if (++next_frg >= write_sq.max_count)
- next_frg = 0 ; /* wrap */
- /* if we get here then we've underrun so we will stop*/
- st_le16(&awacs_tx_cmds[next_frg].command, DBDMA_STOP);
- }
- /* set the dbdma controller going, if it is not already */
- if (write_sq.active == 0)
- out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp));
- (void)in_le32(&awacs_txdma->status);
- out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
- ++write_sq.active;
- }
-}
-
-static void PMacPlay(void)
-{
- LOCK();
- if (!awacs_sleeping) {
- unsigned long flags;
-
- spin_lock_irqsave(&dmasound.lock, flags);
- __PMacPlay();
- spin_unlock_irqrestore(&dmasound.lock, flags);
- }
- UNLOCK();
-}
-
-static void PMacRecord(void)
-{
- unsigned long flags;
-
- if (read_sq.active)
- return;
-
- spin_lock_irqsave(&dmasound.lock, flags);
-
- /* This is all we have to do......Just start it up.
- */
- out_le32(&awacs_rxdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
- read_sq.active = 1;
-
- spin_unlock_irqrestore(&dmasound.lock, flags);
-}
-
-/* if the TX status comes up "DEAD" - reported on some Power Computing machines
- we need to re-start the dbdma - but from a different physical start address
- and with a different transfer length. It would get very messy to do this
- with the normal dbdma_cmd blocks - we would have to re-write the buffer start
- addresses each time. So, we will keep a single dbdma_cmd block which can be
- fiddled with.
- When DEAD status is first reported the content of the faulted dbdma block is
- copied into the emergency buffer and we note that the buffer is in use.
- we then bump the start physical address by the amount that was successfully
- output before it died.
- On any subsequent DEAD result we just do the bump-ups (we know that we are
- already using the emergency dbdma_cmd).
- CHECK: this just tries to "do it". It is possible that we should abandon
- xfers when the number of residual bytes gets below a certain value - I can
- see that this might cause a loop-forever if too small a transfer causes
- DEAD status. However this is a TODO for now - we'll see what gets reported.
- When we get a successful transfer result with the emergency buffer we just
- pretend that it completed using the original dmdma_cmd and carry on. The
- 'next_cmd' field will already point back to the original loop of blocks.
-*/
-
-static irqreturn_t
-pmac_awacs_tx_intr(int irq, void *devid)
-{
- int i = write_sq.front;
- int stat;
- int i_nowrap = write_sq.front;
- volatile struct dbdma_cmd *cp;
- /* != 0 when we are dealing with a DEAD xfer */
- static int emergency_in_use;
-
- spin_lock(&dmasound.lock);
- while (write_sq.active > 0) { /* we expect to have done something*/
- if (emergency_in_use) /* we are dealing with DEAD xfer */
- cp = emergency_dbdma_cmd ;
- else
- cp = &awacs_tx_cmds[i];
- stat = ld_le16(&cp->xfer_status);
- if (stat & DEAD) {
- unsigned short req, res ;
- unsigned int phy ;
-#ifdef DEBUG_DMASOUND
-printk("dmasound_pmac: tx-irq: xfer died - patching it up...\n") ;
-#endif
- /* to clear DEAD status we must first clear RUN
- set it to quiescent to be on the safe side */
- (void)in_le32(&awacs_txdma->status);
- out_le32(&awacs_txdma->control,
- (RUN|PAUSE|FLUSH|WAKE) << 16);
- write_sq.died++ ;
- if (!emergency_in_use) { /* new problem */
- memcpy((void *)emergency_dbdma_cmd, (void *)cp,
- sizeof(struct dbdma_cmd));
- emergency_in_use = 1;
- cp = emergency_dbdma_cmd;
- }
- /* now bump the values to reflect the amount
- we haven't yet shifted */
- req = ld_le16(&cp->req_count);
- res = ld_le16(&cp->res_count);
- phy = ld_le32(&cp->phy_addr);
- phy += (req - res);
- st_le16(&cp->req_count, res);
- st_le16(&cp->res_count, 0);
- st_le16(&cp->xfer_status, 0);
- st_le32(&cp->phy_addr, phy);
- st_le32(&cp->cmd_dep, virt_to_bus(&awacs_tx_cmds[(i+1)%write_sq.max_count]));
- st_le16(&cp->command, OUTPUT_MORE | BR_ALWAYS | INTR_ALWAYS);
-
- /* point at our patched up command block */
- out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp));
- /* we must re-start the controller */
- (void)in_le32(&am