summaryrefslogtreecommitdiffstats
path: root/drivers/sound/dmasound.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
commitd6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch)
treee2be02f33984c48ec019c654051d27964e42c441 /drivers/sound/dmasound.c
parent609d1e803baf519487233b765eb487f9ec227a18 (diff)
Merge with 2.3.19.
Diffstat (limited to 'drivers/sound/dmasound.c')
-rw-r--r--drivers/sound/dmasound.c792
1 files changed, 696 insertions, 96 deletions
diff --git a/drivers/sound/dmasound.c b/drivers/sound/dmasound.c
index fe1cd95aa..341fb6f97 100644
--- a/drivers/sound/dmasound.c
+++ b/drivers/sound/dmasound.c
@@ -108,12 +108,13 @@ History:
#include <asm/amigaints.h>
#endif /* CONFIG_AMIGA */
#ifdef CONFIG_PPC
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
#include <asm/prom.h>
+#include <asm/machdep.h>
#include <asm/io.h>
#include <asm/dbdma.h>
-#include <asm/adb.h>
-#include <asm/cuda.h>
-#include <asm/pmu.h>
#include "awacs_defs.h"
#include <linux/nvram.h>
#include <linux/vt_kern.h>
@@ -131,7 +132,9 @@ static int state_unit = -1;
static int irq_installed = 0;
#endif /* MODULE */
static char **sound_buffers = NULL;
-
+#ifdef CONFIG_PPC
+static char **sound_read_buffers = NULL;
+#endif
#ifdef CONFIG_ATARI
extern void atari_microwire_cmd(int cmd);
@@ -184,6 +187,9 @@ static int awacs_revision;
static void *awacs_tx_cmd_space;
static volatile struct dbdma_cmd *awacs_tx_cmds;
+static void *awacs_rx_cmd_space;
+static volatile struct dbdma_cmd *awacs_rx_cmds;
+
/*
* Cached values of AWACS registers (we can't read them).
* Except on the burgundy. XXX
@@ -239,9 +245,13 @@ static short beep_wform[256] = {
static int beep_volume = BEEP_VOLUME;
static int beep_playing = 0;
+static int awacs_beep_state = 0;
static short *beep_buf;
static volatile struct dbdma_cmd *beep_dbdma_cmd;
static void (*orig_mksound)(unsigned int, unsigned int);
+static int is_pbook_3400;
+static int is_pbook_G3;
+static unsigned char *macio_base;
/* Burgundy functions */
static void awacs_burgundy_wcw(unsigned addr,unsigned newval);
@@ -255,9 +265,9 @@ static int awacs_burgundy_read_mvolume(unsigned address);
/*
* Stuff for restoring after a sleep.
*/
-static int awacs_sleep_notify(struct notifier_block *, unsigned long, void *);
-struct notifier_block awacs_sleep_notifier = {
- awacs_sleep_notify
+static int 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_PMAC_PBOOK */
@@ -276,10 +286,17 @@ struct notifier_block awacs_sleep_notifier = {
#define MIN_BUFSIZE 4
#define MAX_BUFSIZE 128 /* Limit for Amiga */
-static int catchRadius = 0, numBufs = 4, bufSize = 32;
+static int catchRadius = 0;
+static int numBufs = 4, bufSize = 32;
+#ifdef CONFIG_PPC
+static int numReadBufs = 4, readbufSize = 32;
+#endif
+
MODULE_PARM(catchRadius, "i");
MODULE_PARM(numBufs, "i");
MODULE_PARM(bufSize, "i");
+MODULE_PARM(numreadBufs, "i");
+MODULE_PARM(readbufSize, "i");
#define arraysize(x) (sizeof(x)/sizeof(*(x)))
#define min(x, y) ((x) < (y) ? (x) : (y))
@@ -630,6 +647,12 @@ static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,
static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
u_char frame[], ssize_t *frameUsed,
ssize_t frameLeft);
+static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
#endif /* CONFIG_PPC */
/*** Machine definitions *****************************************************/
@@ -681,6 +704,9 @@ struct sound_settings {
SETTINGS soft; /* software settings */
SETTINGS dsp; /* /dev/dsp default settings */
TRANS *trans; /* supported translations */
+#if defined(CONFIG_PPC)
+ TRANS *read_trans; /* supported translations */
+#endif
int volume_left; /* volume (range is machine dependent) */
int volume_right;
int bass; /* tone (range is machine dependent) */
@@ -746,9 +772,11 @@ static void PMacIrqCleanup(void);
static void PMacSilence(void);
static void PMacInit(void);
static void PMacPlay(void);
+static void PMacRecord(void);
static int PMacSetFormat(int format);
static int PMacSetVolume(int volume);
static void pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs);
+static void pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs);
static void pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs);
static void awacs_write(int val);
static int awacs_get_volume(int reg, int lshift);
@@ -776,6 +804,12 @@ static ssize_t sound_copy_translate(const u_char *userPtr,
size_t userCount,
u_char frame[], ssize_t *frameUsed,
ssize_t frameLeft);
+#ifdef CONFIG_PPC
+static ssize_t sound_copy_translate_read(const u_char *userPtr,
+ size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+#endif
/*
@@ -809,8 +843,8 @@ struct sound_queue {
* Amiga: Bit 0 is set: a frame is loaded
* Bit 1 is set: a frame is playing
*/
- int playing;
- wait_queue_head_t write_queue, open_queue, sync_queue;
+ int active;
+ wait_queue_head_t action_queue, open_queue, sync_queue;
int open_mode;
int busy, syncing;
#ifdef CONFIG_ATARI
@@ -822,6 +856,9 @@ struct sound_queue {
};
static struct sound_queue sq;
+#ifdef CONFIG_PPC
+static struct sound_queue read_sq;
+#endif
#define sq_block_address(i) (sq.buffers[i])
#define SIGNAL_RECEIVED (signal_pending(current))
@@ -852,7 +889,7 @@ static inline int ioctl_return(int *addr, int value)
if (value < 0)
return(value);
- return put_user(value, addr)? -EFAULT: 0;
+ return put_user(value, addr);
}
@@ -2172,6 +2209,135 @@ static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
return stereo? utotal * 4: utotal * 2;
}
+static ssize_t pmac_ct_s8_read(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ short *p = (short *) &frame[*frameUsed];
+ int val, stereo = sound.soft.stereo;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ u_char data;
+
+ val = *p++;
+ data = val >> 8;
+ if (put_user(data, (u_char *)userPtr++))
+ return -EFAULT;
+ if (stereo) {
+ val = *p;
+ data = val >> 8;
+ if (put_user(data, (u_char *)userPtr++))
+ return -EFAULT;
+ }
+ p++;
+ count--;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 2: used;
+}
+
+
+static ssize_t pmac_ct_u8_read(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ short *p = (short *) &frame[*frameUsed];
+ int val, stereo = sound.soft.stereo;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ u_char data;
+
+ val = *p++;
+ data = (val >> 8) ^ 0x80;
+ if (put_user(data, (u_char *)userPtr++))
+ return -EFAULT;
+ if (stereo) {
+ val = *p;
+ data = (val >> 8) ^ 0x80;
+ if (put_user(data, (u_char *)userPtr++))
+ return -EFAULT;
+ }
+ p++;
+ count--;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 2: used;
+}
+
+
+static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ int stereo = sound.soft.stereo;
+ short *fp = (short *) &frame[*frameUsed];
+
+ frameLeft >>= 2;
+ userCount >>= (stereo? 2: 1);
+ used = count = min(userCount, frameLeft);
+ if (!stereo) {
+ short *up = (short *) userPtr;
+ while (count > 0) {
+ short data;
+ data = *fp;
+ if (put_user(data, up++))
+ return -EFAULT;
+ fp+=2;
+ count--;
+ }
+ } else {
+ if (copy_to_user((u_char *)userPtr, fp, count * 4))
+ return -EFAULT;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 4: used * 2;
+}
+
+static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
+ int stereo = sound.soft.stereo;
+ short *fp = (short *) &frame[*frameUsed];
+ short *up = (short *) userPtr;
+
+ frameLeft >>= 2;
+ userCount >>= (stereo? 2: 1);
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ int data;
+
+ data = *fp++;
+ data ^= mask;
+ if (put_user(data, up++))
+ return -EFAULT;
+ if (stereo) {
+ data = *fp;
+ data ^= mask;
+ if (put_user(data, up++))
+ return -EFAULT;
+ }
+ fp++;
+ count--;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 4: used * 2;
+}
+
+
#endif /* CONFIG_PPC */
@@ -2212,6 +2378,11 @@ static TRANS transAwacsExpand = {
pmac_ctx_law, pmac_ctx_law, pmac_ctx_s8, pmac_ctx_u8,
pmac_ctx_s16, pmac_ctx_u16, pmac_ctx_s16, pmac_ctx_u16
};
+
+static TRANS transAwacsNormalRead = {
+ NULL, NULL, pmac_ct_s8_read, pmac_ct_u8_read,
+ pmac_ct_s16_read, pmac_ct_u16_read, pmac_ct_s16_read, pmac_ct_u16_read
+};
#endif /* CONFIG_PPC */
/*** Low level stuff *********************************************************/
@@ -2569,23 +2740,23 @@ static void ata_sq_play_next_frame(int index)
start = sq_block_address(sq.front);
end = start+((sq.count == index) ? sq.rear_size : sq.block_size);
/* end might not be a legal virtual address. */
- DMASNDSetEnd(VTOP(end - 1) + 1);
- DMASNDSetBase(VTOP(start));
+ DMASNDSetEnd(virt_to_phys(end - 1) + 1);
+ DMASNDSetBase(virt_to_phys(start));
/* Since only an even number of samples per frame can
be played, we might lose one byte here. (TO DO) */
sq.front = (sq.front+1) % sq.max_count;
- sq.playing++;
+ sq.active++;
tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;
}
static void AtaPlay(void)
{
- /* ++TeSche: Note that sq.playing is no longer just a flag but holds
+ /* ++TeSche: Note that sq.active is no longer just a flag but holds
* the number of frames the DMA is currently programmed for instead,
* may be 0, 1 (currently being played) or 2 (pre-programmed).
*
- * Changes done to sq.count and sq.playing are a bit more subtle again
+ * Changes done to sq.count and sq.active are a bit more subtle again
* so now I must admit I also prefer disabling the irq here rather
* than considering all possible situations. But the point is that
* disabling the irq doesn't have any bad influence on this version of
@@ -2596,13 +2767,13 @@ static void AtaPlay(void)
*/
atari_disable_irq(IRQ_MFP_TIMA);
- if (sq.playing == 2 || /* DMA is 'full' */
+ if (sq.active == 2 || /* DMA is 'full' */
sq.count <= 0) { /* nothing to do */
atari_enable_irq(IRQ_MFP_TIMA);
return;
}
- if (sq.playing == 0) {
+ if (sq.active == 0) {
/* looks like there's nothing 'in' the DMA yet, so try
* to put two frames into it (at least one is available).
*/
@@ -2650,7 +2821,7 @@ static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
#if 0
/* ++TeSche: if you should want to test this... */
static int cnt = 0;
- if (sq.playing == 2)
+ if (sq.active == 2)
if (++cnt == 10) {
/* simulate losing an interrupt */
cnt = 0;
@@ -2667,7 +2838,7 @@ static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
return;
}
- if (!sq.playing) {
+ if (!sq.active) {
/* playing was interrupted and sq_reset() has already cleared
* the sq variables, so better don't do anything here.
*/
@@ -2683,29 +2854,29 @@ static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
* as soon as the irq gets through.
*/
sq.count--;
- sq.playing--;
+ sq.active--;
- if (!sq.playing) {
+ if (!sq.active) {
tt_dmasnd.ctrl = DMASND_CTRL_OFF;
sq.ignore_int = 1;
}
- WAKE_UP(sq.write_queue);
+ WAKE_UP(sq.action_queue);
/* At least one block of the queue is free now
so wake up a writing process blocked because
of a full queue. */
- if ((sq.playing != 1) || (sq.count != 1))
+ if ((sq.active != 1) || (sq.count != 1))
/* We must be a bit carefully here: sq.count indicates the
* number of buffers used and not the number of frames to
- * be played. If sq.count==1 and sq.playing==1 that means
+ * be played. If sq.count==1 and sq.active==1 that means
* the only remaining frame was already programmed earlier
* (and is currently running) so we mustn't call AtaPlay()
* here, otherwise we'll play one frame too much.
*/
AtaPlay();
- if (!sq.playing) WAKE_UP(sq.sync_queue);
+ if (!sq.active) WAKE_UP(sq.sync_queue);
/* We are not playing after AtaPlay(), so there
is nothing to play any more. Wake up a process
waiting for audio output to drain. */
@@ -2902,7 +3073,7 @@ static void ami_sq_play_next_frame(int index)
custom.dmacon = AMI_AUDIO_8;
}
sq.front = (sq.front+1) % sq.max_count;
- sq.playing |= AMI_PLAY_LOADED;
+ sq.active |= AMI_PLAY_LOADED;
}
@@ -2912,13 +3083,13 @@ static void AmiPlay(void)
custom.intena = IF_AUD0;
- if (sq.playing & AMI_PLAY_LOADED) {
+ if (sq.active & AMI_PLAY_LOADED) {
/* There's already a frame loaded */
custom.intena = IF_SETCLR | IF_AUD0;
return;
}
- if (sq.playing & AMI_PLAY_PLAYING)
+ if (sq.active & AMI_PLAY_PLAYING)
/* Increase threshold: frame 1 is already being played */
minframes = 2;
@@ -2946,7 +3117,7 @@ static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
{
int minframes = 1;
- if (!sq.playing) {
+ if (!sq.active) {
/* Playing was interrupted and sq_reset() has already cleared
* the sq variables, so better don't do anything here.
*/
@@ -2954,20 +3125,20 @@ static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
return;
}
- if (sq.playing & AMI_PLAY_PLAYING) {
+ if (sq.active & AMI_PLAY_PLAYING) {
/* We've just finished a frame */
sq.count--;
- WAKE_UP(sq.write_queue);
+ WAKE_UP(sq.action_queue);
}
- if (sq.playing & AMI_PLAY_LOADED)
+ if (sq.active & AMI_PLAY_LOADED)
/* Increase threshold: frame 1 is already being played */
minframes = 2;
/* Shift the flags */
- sq.playing = (sq.playing<<1) & AMI_PLAY_MASK;
+ sq.active = (sq.active<<1) & AMI_PLAY_MASK;
- if (!sq.playing)
+ if (!sq.active)
/* No frame is playing, disable audio DMA */
custom.dmacon = AMI_AUDIO_OFF;
@@ -2975,7 +3146,7 @@ static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
/* Try to play the next frame */
AmiPlay();
- if (!sq.playing)
+ if (!sq.active)
/* Nothing to play anymore.
Wake up a process waiting for audio output to drain. */
WAKE_UP(sq.sync_queue);
@@ -3001,7 +3172,8 @@ static void PMacFree(void *ptr, unsigned int size)
static int __init PMacIrqInit(void)
{
if (request_irq(awacs_irq, pmac_awacs_intr, 0, "AWACS", 0)
- || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "AWACS out", 0))
+ || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "AWACS out", 0)
+ || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "AWACS in", 0))
return 0;
return 1;
}
@@ -3015,12 +3187,15 @@ static void PMacIrqCleanup(void)
out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);
free_irq(awacs_irq, pmac_awacs_intr);
free_irq(awacs_tx_irq, pmac_awacs_tx_intr);
+ free_irq(awacs_rx_irq, pmac_awacs_rx_intr);
kfree(awacs_tx_cmd_space);
+ if (awacs_rx_cmd_space)
+ kfree(awacs_rx_cmd_space);
if (beep_buf)
kfree(beep_buf);
kd_mksound = orig_mksound;
#ifdef CONFIG_PMAC_PBOOK
- notifier_chain_unregister(&sleep_notifier_list, &awacs_sleep_notifier);
+ pmu_unregister_sleep_notifier(&awacs_sleep_notifier);
#endif
}
#endif /* MODULE */
@@ -3065,10 +3240,10 @@ static void PMacInit(void)
sound.trans = &transAwacsNormal;
else
sound.trans = &transAwacsExpand;
+ sound.read_trans = &transAwacsNormalRead;
sound.hard.speed = awacs_freqs[i];
awacs_rate_index = i;
- PMacSilence();
/* XXX disable error interrupt on burgundy for now */
out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11
| (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));
@@ -3076,6 +3251,18 @@ static void PMacInit(void)
awacs_write(awacs_reg[1] | MASK_ADDR1);
out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
+ /* We really want to execute a DMA stop command, after the AWACS
+ * is initialized.
+ * For reasons I don't understand, it stops the hissing noise
+ * common to many PowerBook G3 systems (like mine :-). Maybe it
+ * is just the AWACS control register change......
+ */
+ out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
+ st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
+ out_le32(&awacs->control, (in_le32(&awacs->control) & ~0x1f00));
+ out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
+ out_le32(&awacs_txdma->control, RUN | (RUN << 16));
+
sound.bal = -sound.soft.speed;
}
@@ -3163,20 +3350,23 @@ static void PMacPlay(void)
unsigned long flags;
save_flags(flags); cli();
- if (beep_playing) {
+ if (awacs_beep_state) {
/* sound takes precedence over beeps */
out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
out_le32(&awacs->control,
(in_le32(&awacs->control) & ~0x1f00)
- || (awacs_rate_index << 8));
+ | (awacs_rate_index << 8));
out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
+ out_le32(&awacs_txdma->cmdptr, virt_to_bus(&(awacs_tx_cmds[(sq.front+sq.active) % sq.max_count])));
+
beep_playing = 0;
+ awacs_beep_state = 0;
}
- i = sq.front + sq.playing;
+ i = sq.front + sq.active;
if (i >= sq.max_count)
i -= sq.max_count;
- while (sq.playing < 2 && sq.playing < sq.count) {
- count = (sq.count == sq.playing + 1)? sq.rear_size: sq.block_size;
+ while (sq.active < 2 && sq.active < sq.count) {
+ count = (sq.count == sq.active + 1)?sq.rear_size:sq.block_size;
if (count < sq.block_size && !sq.syncing)
/* last block not yet filled, and we're not syncing. */
break;
@@ -3187,14 +3377,33 @@ static void PMacPlay(void)
i = 0;
out_le16(&awacs_tx_cmds[i].command, DBDMA_STOP);
out_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS);
- if (sq.playing == 0)
+ if (sq.active == 0)
out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp));
out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
- ++sq.playing;
+ ++sq.active;
}
restore_flags(flags);
}
+
+static void PMacRecord(void)
+{
+ unsigned long flags;
+
+ if (read_sq.active)
+ return;
+
+ save_flags(flags); cli();
+
+ /* 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;
+
+ restore_flags(flags);
+}
+
+
static void
pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs)
{
@@ -3202,26 +3411,78 @@ pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs)
int stat;
volatile struct dbdma_cmd *cp;
- while (sq.playing > 0) {
+ while (sq.active > 0) {
cp = &awacs_tx_cmds[i];
stat = ld_le16(&cp->xfer_status);
if ((stat & ACTIVE) == 0)
break; /* this frame is still going */
--sq.count;
- --sq.playing;
+ --sq.active;
if (++i >= sq.max_count)
i = 0;
}
if (i != sq.front)
- WAKE_UP(sq.write_queue);
+ WAKE_UP(sq.action_queue);
sq.front = i;
PMacPlay();
- if (!sq.playing)
+ if (!sq.active)
WAKE_UP(sq.sync_queue);
}
+
+static void
+pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs)
+{
+
+ /* For some reason on my PowerBook G3, I get one interrupt
+ * when the interrupt vector is installed (like something is
+ * pending). This happens before the dbdma is initialize by
+ * us, so I just check the command pointer and if it is zero,
+ * just blow it off.
+ */
+ if (in_le32(&awacs_rxdma->cmdptr) == 0)
+ return;
+
+ /* We also want to blow 'em off when shutting down.
+ */
+ if (read_sq.active == 0)
+ return;
+
+ /* Check multiple buffers in case we were held off from
+ * interrupt processing for a long time. Geeze, I really hope
+ * this doesn't happen.
+ */
+ while (awacs_rx_cmds[read_sq.rear].xfer_status) {
+
+ /* Clear status and move on to next buffer.
+ */
+ awacs_rx_cmds[read_sq.rear].xfer_status = 0;
+ read_sq.rear++;
+
+ /* Wrap the buffer ring.
+ */
+ if (read_sq.rear >= read_sq.max_active)
+ read_sq.rear = 0;
+
+ /* If we have caught up to the front buffer, bump it.
+ * This will cause weird (but not fatal) results if the
+ * read loop is currently using this buffer. The user is
+ * behind in this case anyway, so weird things are going
+ * to happen.
+ */
+ if (read_sq.rear == read_sq.front) {
+ read_sq.front++;
+ if (read_sq.front >= read_sq.max_active)
+ read_sq.front = 0;
+ }
+ }
+
+ WAKE_UP(read_sq.action_queue);
+}
+
+
static void
pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs)
{
@@ -3294,7 +3555,7 @@ static void awacs_mksound(unsigned int hz, unsigned int ticks)
beep_timer.expires = jiffies + ticks;
add_timer(&beep_timer);
}
- if (beep_playing || sq.playing || beep_buf == NULL) {
+ if (beep_playing || sq.active || beep_buf == NULL) {
restore_flags(flags);
return; /* too hard, sorry :-( */
}
@@ -3324,6 +3585,7 @@ static void awacs_mksound(unsigned int hz, unsigned int ticks)
st_le16(&beep_dbdma_cmd->xfer_status, 0);
st_le32(&beep_dbdma_cmd->cmd_dep, virt_to_bus(beep_dbdma_cmd));
st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf));
+ awacs_beep_state = 1;
save_flags(flags); cli();
if (beep_playing) { /* i.e. haven't been terminated already */
@@ -3342,14 +3604,15 @@ static void awacs_mksound(unsigned int hz, unsigned int ticks)
/*
* Save state when going to sleep, restore it afterwards.
*/
-static int awacs_sleep_notify(struct notifier_block *this,
- unsigned long code, void *x)
+static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
{
- switch (code) {
- case PBOOK_SLEEP:
+ switch (when) {
+ case PBOOK_SLEEP_NOW:
/* XXX we should stop any dma in progress when going to sleep
and restart it when we wake. */
PMacSilence();
+ disable_irq(awacs_irq);
+ disable_irq(awacs_tx_irq);
break;
case PBOOK_WAKE:
out_le32(&awacs->control, MASK_IEPC
@@ -3360,8 +3623,10 @@ static int awacs_sleep_notify(struct notifier_block *this,
awacs_write(awacs_reg[2] | MASK_ADDR2);
awacs_write(awacs_reg[4] | MASK_ADDR4);
out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
+ enable_irq(awacs_irq);
+ enable_irq(awacs_tx_irq);
}
- return NOTIFY_DONE;
+ return PBOOK_SLEEP_OK;
}
#endif /* CONFIG_PMAC_PBOOK */
@@ -3586,7 +3851,7 @@ awacs_enable_amp(int spkr_vol)
struct adb_request req;
awacs_spkr_vol = spkr_vol;
- if (adb_hardware != ADB_VIACUDA)
+ if (sys_ctrler != SYS_CTRLER_CUDA)
return;
/* turn on headphones */
@@ -3781,6 +4046,47 @@ static ssize_t sound_copy_translate(const u_char *userPtr,
return 0;
}
+#ifdef CONFIG_PPC
+static ssize_t sound_copy_translate_read(const u_char *userPtr,
+ size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
+
+ switch (sound.soft.format) {
+ case AFMT_MU_LAW:
+ ct_func = sound.read_trans->ct_ulaw;
+ break;
+ case AFMT_A_LAW:
+ ct_func = sound.read_trans->ct_alaw;
+ break;
+ case AFMT_S8:
+ ct_func = sound.read_trans->ct_s8;
+ break;
+ case AFMT_U8:
+ ct_func = sound.read_trans->ct_u8;
+ break;
+ case AFMT_S16_BE:
+ ct_func = sound.read_trans->ct_s16be;
+ break;
+ case AFMT_U16_BE:
+ ct_func = sound.read_trans->ct_u16be;
+ break;
+ case AFMT_S16_LE:
+ ct_func = sound.read_trans->ct_s16le;
+ break;
+ case AFMT_U16_LE:
+ ct_func = sound.read_trans->ct_u16le;
+ break;
+ }
+ if (ct_func)
+ return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
+ else
+ return 0;
+}
+#endif
+
/*
* /dev/mixer abstraction
@@ -3983,7 +4289,8 @@ static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
#ifdef CONFIG_PPC
case DMASND_AWACS:
- if (awacs_revision<AWACS_BURGUNDY) { /* Different IOCTLS for burgundy*/
+ /* Different IOCTLS for burgundy*/
+ if (awacs_revision < AWACS_BURGUNDY) {
switch (cmd) {
case SOUND_MIXER_INFO: {
mixer_info info;
@@ -3999,7 +4306,8 @@ static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
| SOUND_MASK_LINE | SOUND_MASK_MIC
| SOUND_MASK_CD | SOUND_MASK_RECLEV
- | SOUND_MASK_ALTPCM;
+ | SOUND_MASK_ALTPCM
+ | SOUND_MASK_MONITOR;
return IOCTL_OUT(arg, data);
case SOUND_MIXER_READ_RECMASK:
data = SOUND_MASK_LINE | SOUND_MASK_MIC
@@ -4013,20 +4321,27 @@ static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
data |= SOUND_MASK_MIC;
if (awacs_reg[0] & MASK_MUX_CD)
data |= SOUND_MASK_CD;
+ if (awacs_reg[1] & MASK_LOOPTHRU)
+ data |= SOUND_MASK_MONITOR;
return IOCTL_OUT(arg, data);
case SOUND_MIXER_WRITE_RECSRC:
IOCTL_IN(arg, data);
data &= (SOUND_MASK_LINE
- | SOUND_MASK_MIC | SOUND_MASK_CD);
+ | SOUND_MASK_MIC | SOUND_MASK_CD
+ | SOUND_MASK_MONITOR);
awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC
| MASK_MUX_AUDIN);
+ awacs_reg[1] &= ~MASK_LOOPTHRU;
if (data & SOUND_MASK_LINE)
awacs_reg[0] |= MASK_MUX_AUDIN;
if (data & SOUND_MASK_MIC)
awacs_reg[0] |= MASK_MUX_MIC;
if (data & SOUND_MASK_CD)
awacs_reg[0] |= MASK_MUX_CD;
+ if (data & SOUND_MASK_MONITOR)
+ awacs_reg[1] |= MASK_LOOPTHRU;
awacs_write(awacs_reg[0] | MASK_ADDR0);
+ awacs_write(awacs_reg[1] | MASK_ADDR1);
return IOCTL_OUT(arg, data);
case SOUND_MIXER_READ_STEREODEVS:
data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
@@ -4042,7 +4357,8 @@ static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
IOCTL_IN(arg, data);
return IOCTL_OUT(arg, sound_set_volume(data));
case SOUND_MIXER_READ_SPEAKER:
- if (awacs_revision == 3 && adb_hardware == ADB_VIACUDA)
+ if (awacs_revision == 3
+ && sys_ctrler == SYS_CTRLER_CUDA)
data = awacs_spkr_vol;
else
data = (awacs_reg[1] & MASK_CMUTE)? 0:
@@ -4050,7 +4366,8 @@ static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
return IOCTL_OUT(arg, data);
case SOUND_MIXER_WRITE_SPEAKER:
IOCTL_IN(arg, data);
- if (awacs_revision == 3 && adb_hardware == ADB_VIACUDA)
+ if (awacs_revision == 3
+ && sys_ctrler == SYS_CTRLER_CUDA)
awacs_enable_amp(data);
else
data = awacs_volume_setter(data, 4, MASK_CMUTE, 6);
@@ -4347,7 +4664,60 @@ static void sq_release_buffers(void)
}
-static void sq_setup(int numBufs, int bufSize, char **buffers)
+#ifdef CONFIG_PPC
+static int sq_allocate_read_buffers(void)
+{
+ int i;
+ int j;
+
+ if (sound_read_buffers)
+ return 0;
+ sound_read_buffers = kmalloc(numReadBufs * sizeof(char *), GFP_KERNEL);
+ if (!sound_read_buffers)
+ return -ENOMEM;
+ for (i = 0; i < numBufs; i++) {
+ sound_read_buffers[i] = sound.mach.dma_alloc (readbufSize<<10,
+ GFP_KERNEL);
+ if (!sound_read_buffers[i]) {
+ while (i--)
+ sound.mach.dma_free (sound_read_buffers[i],
+ readbufSize << 10);
+ kfree (sound_read_buffers);
+ sound_read_buffers = 0;
+ return -ENOMEM;
+ }
+ /* XXXX debugging code */
+ for (j=0; j<readbufSize; j++) {
+ sound_read_buffers[i][j] = 0xef;
+ }
+ }
+ return 0;
+}
+
+static void sq_release_read_buffers(void)
+{
+ int i;
+ volatile struct dbdma_cmd *cp;
+
+
+ if (sound_read_buffers) {
+ cp = awacs_rx_cmds;
+ for (i = 0; i < numReadBufs; i++,cp++) {
+ st_le16(&cp->command, DBDMA_STOP);
+ }
+ /* We should probably wait for the thing to stop before we
+ release the memory */
+ for (i = 0; i < numBufs; i++)
+ sound.mach.dma_free (sound_read_buffers[i],
+ bufSize << 10);
+ kfree (sound_read_buffers);
+ sound_read_buffers = 0;
+ }
+}
+#endif
+
+
+static void sq_setup(int numBufs, int bufSize, char **write_buffers)
{
#ifdef CONFIG_PPC
int i;
@@ -4357,12 +4727,12 @@ static void sq_setup(int numBufs, int bufSize, char **buffers)
sq.max_count = numBufs;
sq.max_active = numBufs;
sq.block_size = bufSize;
- sq.buffers = buffers;
+ sq.buffers = write_buffers;
sq.front = sq.count = 0;
sq.rear = -1;
sq.syncing = 0;
- sq.playing = 0;
+ sq.active = 0;
#ifdef CONFIG_ATARI
sq.ignore_int = 0;
@@ -4375,7 +4745,7 @@ static void sq_setup(int numBufs, int bufSize, char **buffers)
cp = awacs_tx_cmds;
memset((void *) cp, 0, (numBufs + 1) * sizeof(struct dbdma_cmd));
for (i = 0; i < numBufs; ++i, ++cp) {
- st_le32(&cp->phy_addr, virt_to_bus(buffers[i]));
+ st_le32(&cp->phy_addr, virt_to_bus(write_buffers[i]));
}
st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds));
@@ -4384,6 +4754,50 @@ static void sq_setup(int numBufs, int bufSize, char **buffers)
#endif /* CONFIG_PPC */
}
+#ifdef CONFIG_PPC
+static void read_sq_setup(int numBufs, int bufSize, char **read_buffers)
+{
+ int i;
+ volatile struct dbdma_cmd *cp;
+
+ read_sq.max_count = numBufs;
+ read_sq.max_active = numBufs;
+ read_sq.block_size = bufSize;
+ read_sq.buffers = read_buffers;
+
+ read_sq.front = read_sq.count = 0;
+ read_sq.rear = 0;
+ read_sq.rear_size = 0;
+ read_sq.syncing = 0;
+ read_sq.active = 0;
+
+ cp = awacs_rx_cmds;
+ memset((void *) cp, 0, (numBufs + 1) * sizeof(struct dbdma_cmd));
+
+ /* Set dma buffers up in a loop */
+ for (i = 0; i < numBufs; i++,cp++) {
+ st_le32(&cp->phy_addr, virt_to_bus(read_buffers[i]));
+ st_le16(&cp->command, INPUT_MORE + INTR_ALWAYS);
+ st_le16(&cp->req_count, read_sq.block_size);
+ st_le16(&cp->xfer_status, 0);
+ }
+
+ /* The next two lines make the thing loop around.
+ */
+ st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
+ st_le32(&cp->cmd_dep, virt_to_bus(awacs_rx_cmds));
+
+ /* Don't start until the first read is done.
+ * This will also abort any operations in progress if the DMA
+ * happens to be running (and it shouldn't).
+ */
+ out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+ out_le32(&awacs_rxdma->cmdptr, virt_to_bus(awacs_rx_cmds));
+
+}
+#endif /* CONFIG_PPC */
+
+
static void sq_play(void)
{
(*sound.mach.play)();
@@ -4428,7 +4842,7 @@ static ssize_t sq_write(struct file *file, const char *src, size_t uLeft,
sq_play();
if (NON_BLOCKING(sq.open_mode))
return uWritten > 0 ? uWritten : -EAGAIN;
- SLEEP(sq.write_queue, ONE_SECOND);
+ SLEEP(sq.action_queue, ONE_SECOND);
if (SIGNAL_RECEIVED)
return uWritten > 0 ? uWritten : -EINTR;
}
@@ -4462,29 +4876,122 @@ static ssize_t sq_write(struct file *file, const char *src, size_t uLeft,
}
+/***********/
+
+#ifdef CONFIG_PPC
+
+/* Here is how the values are used for reading.
+ * The value 'active' simply indicates the DMA is running. This is
+ * done so the driver semantics are DMA starts when the first read is
+ * posted. The value 'front' indicates the buffer we should next
+ * send to the user. The value 'rear' indicates the buffer the DMA is
+ * currently filling. When 'front' == 'rear' the buffer "ring" is
+ * empty (we always have an empty available). The 'rear_size' is used
+ * to track partial offsets into the current buffer. Right now, I just keep
+ * the DMA running. If the reader can't keep up, the interrupt tosses
+ * the oldest buffer. We could also shut down the DMA in this case.
+ */
+static ssize_t sq_read(struct file *file, char *dst, size_t uLeft,
+ loff_t *ppos)
+{
+
+ ssize_t uRead, bLeft, bUsed, uUsed;
+
+ if (uLeft == 0)
+ return 0;
+
+ if (!read_sq.active)
+ PMacRecord(); /* Kick off the record process. */
+
+ uRead = 0;
+
+ /* Move what the user requests, depending upon other options.
+ */
+ while (uLeft > 0) {
+
+ /* When front == rear, the DMA is not done yet.
+ */
+ while (read_sq.front == read_sq.rear) {
+ if (NON_BLOCKING(read_sq.open_mode)) {
+ return uRead > 0 ? uRead : -EAGAIN;
+ }
+ SLEEP(read_sq.action_queue, ONE_SECOND);
+ if (SIGNAL_RECEIVED)
+ return uRead > 0 ? uRead : -EINTR;
+ }
+
+ /* The amount we move is either what is left in the
+ * current buffer or what the user wants.
+ */
+ bLeft = read_sq.block_size - read_sq.rear_size;
+ bUsed = read_sq.rear_size;
+ uUsed = sound_copy_translate_read(dst, uLeft,
+ read_sq.buffers[read_sq.front], &bUsed, bLeft);
+ if (uUsed <= 0)
+ return uUsed;
+ dst += uUsed;
+ uRead += uUsed;
+ uLeft -= uUsed;
+ read_sq.rear_size += bUsed;
+ if (read_sq.rear_size >= read_sq.block_size) {
+ read_sq.rear_size = 0;
+ read_sq.front++;
+ if (read_sq.front >= read_sq.max_active)
+ read_sq.front = 0;
+ }
+ }
+ return uRead;
+}
+#endif
+
static int sq_open(struct inode *inode, struct file *file)
{
int rc = 0;
MOD_INC_USE_COUNT;
- if (sq.busy) {
- rc = -EBUSY;
- if (NON_BLOCKING(file->f_flags))
- goto err_out;
- rc = -EINTR;
- while (sq.busy) {
- SLEEP(sq.open_queue, ONE_SECOND);
- if (SIGNAL_RECEIVED)
+ if (file->f_mode & FMODE_WRITE) {
+ if (sq.busy) {
+ rc = -EBUSY;
+ if (NON_BLOCKING(file->f_flags))
goto err_out;
+ rc = -EINTR;
+ while (sq.busy) {
+ SLEEP(sq.open_queue, ONE_SECOND);
+ if (SIGNAL_RECEIVED)
+ goto err_out;
+ }
}
- rc = 0;
+ sq.busy = 1; /* Let's play spot-the-race-condition */
+
+ if (sq_allocate_buffers()) goto err_out_nobusy;
+
+ sq_setup(numBufs, bufSize<<10,sound_buffers);
+ sq.open_mode = file->f_mode;
}
- sq.busy = 1;
- rc = sq_allocate_buffers();
- if (rc)
- goto err_out_nobusy;
- sq_setup(numBufs, bufSize << 10, sound_buffers);
- sq.open_mode = file->f_flags;
+
+
+#ifdef CONFIG_PPC
+ if (file->f_mode & FMODE_READ) {
+ if (read_sq.busy) {
+ rc = -EBUSY;
+ if (NON_BLOCKING(file->f_flags))
+ goto err_out;
+ rc = -EINTR;
+ while (read_sq.busy) {
+ SLEEP(read_sq.open_queue, ONE_SECOND);
+ if (SIGNAL_RECEIVED)
+ goto err_out;
+ }
+ rc = 0;
+ }
+ read_sq.busy = 1;
+ if (sq_allocate_read_buffers()) goto err_out_nobusy;
+
+ read_sq_setup(numReadBufs,readbufSize<<10, sound_read_buffers);
+ read_sq.open_mode = file->f_mode;
+ }
+#endif
+
#ifdef CONFIG_ATARI
sq.ignore_int = 1;
#endif /* CONFIG_ATARI */
@@ -4497,10 +5004,27 @@ static int sq_open(struct inode *inode, struct file *file)
sound_set_stereo(0);
sound_set_format(AFMT_MU_LAW);
}
+
+#if 0
+ if (file->f_mode == FMODE_READ) {
+ /* Start dma'ing straight away */
+ PMacRecord();
+ }
+#endif
+
return 0;
+
err_out_nobusy:
- sq.busy = 0;
- WAKE_UP(sq.open_queue);
+ if (file->f_mode & FMODE_WRITE) {
+ sq.busy = 0;
+ WAKE_UP(sq.open_queue);
+ }
+#ifdef CONFIG_PPC
+ if (file->f_mode & FMODE_READ) {
+ read_sq.busy = 0;
+ WAKE_UP(read_sq.open_queue);
+ }
+#endif
err_out:
MOD_DEC_USE_COUNT;
return rc;
@@ -4510,7 +5034,7 @@ err_out:
static void sq_reset(void)
{
sound_silence();
- sq.playing = 0;
+ sq.active = 0;
sq.count = 0;
sq.front = (sq.rear+1) % sq.max_count;
}
@@ -4523,7 +5047,7 @@ static int sq_fsync(struct file *filp, struct dentry *dentry)
sq.syncing = 1;
sq_play(); /* there may be an incomplete frame waiting */
- while (sq.playing) {
+ while (sq.active) {
SLEEP(sq.sync_queue, ONE_SECOND);
if (SIGNAL_RECEIVED) {
/* While waiting for audio output to drain, an
@@ -4548,11 +5072,27 @@ static int sq_release(struct inode *inode, struct file *file)
sound.soft = sound.dsp;
sound.hard = sound.dsp;
sound_silence();
+
+#ifdef CONFIG_PPC
+ sq_release_read_buffers();
+#endif
sq_release_buffers();
MOD_DEC_USE_COUNT;
- sq.busy = 0;
- WAKE_UP(sq.open_queue);
+ /* There is probably a DOS atack here. They change the mode flag. */
+ /* XXX add check here */
+#ifdef CONFIG_PPC
+ if (file->f_mode & FMODE_READ) {
+ read_sq.busy = 0;
+ WAKE_UP(read_sq.open_queue);
+ }
+#endif
+
+ if (file->f_mode & FMODE_WRITE) {
+ sq.busy = 0;
+ WAKE_UP(sq.open_queue);
+ }
+
/* Wake up a process waiting for the queue being released.
* Note: There may be several processes waiting for a call
* to open() returning. */
@@ -4624,14 +5164,14 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
case SNDCTL_DSP_SUBDIVIDE:
break;
case SNDCTL_DSP_SETFRAGMENT:
- if (sq.count || sq.playing || sq.syncing)
+ if (sq.count || sq.active || sq.syncing)
return -EINVAL;
IOCTL_IN(arg, size);
nbufs = size >> 16;
if (nbufs < 2 || nbufs > numBufs)
nbufs = numBufs;
size &= 0xffff;
- if (size >= 8 && size <= 30) {
+ if (size >= 8 && size <= 29) {
size = 1 << size;
size *= sound.hard.size * (sound.hard.stereo + 1);
size /= sound.soft.size * (sound.soft.stereo + 1);
@@ -4654,7 +5194,11 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
static struct file_operations sq_fops =
{
sound_lseek,
+#ifdef CONFIG_PPC
+ sq_read, /* sq_read */
+#else
NULL, /* sq_read */
+#endif
sq_write,
NULL, /* sq_readdir */
NULL, /* sq_poll */
@@ -4675,10 +5219,20 @@ static void __init sq_init(void)
if (sq_unit < 0)
return;
- init_waitqueue_head(&sq.write_queue);
+ init_waitqueue_head(&sq.action_queue);
init_waitqueue_head(&sq.open_queue);
init_waitqueue_head(&sq.sync_queue);
+
+#ifdef CONFIG_PPC
+ init_waitqueue_head(&read_sq.action_queue);
+ init_waitqueue_head(&read_sq.open_queue);
+ init_waitqueue_head(&read_sq.sync_queue);
+#endif
+
sq.busy = 0;
+#ifdef CONFIG_PPC
+ read_sq.busy = 0;
+#endif
/* whatever you like as startup mode for /dev/dsp,
* (/dev/audio hasn't got a startup mode). note that
@@ -4727,6 +5281,9 @@ static void __init sq_init(void)
static int state_open(struct inode *inode, struct file *file)
{
char *buffer = state.buf, *mach = "";
+#ifdef CONFIG_PPC
+ char awacs_buf[50];
+#endif
int len = 0;
if (state.busy)
@@ -4750,7 +5307,8 @@ static int state_open(struct inode *inode, struct file *file)
#endif /* CONFIG_AMIGA */
#ifdef CONFIG_PPC
case DMASND_AWACS:
- sprintf(mach, "PowerMac (AWACS rev %d) ", awacs_revision);
+ sprintf(awacs_buf, "PowerMac (AWACS rev %d) ", awacs_revision);
+ mach = awacs_buf;
break;
#endif /* CONFIG_PPC */
}
@@ -4821,8 +5379,8 @@ static int state_open(struct inode *inode, struct file *file)
sq.block_size, sq.max_count, sq.max_active);
len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count,
sq.rear_size);
- len += sprintf(buffer+len, "\tsq.playing = %d sq.syncing = %d\n",
- sq.playing, sq.syncing);
+ len += sprintf(buffer+len, "\tsq.active = %d sq.syncing = %d\n",
+ sq.active, sq.syncing);
state.len = len;
return 0;
}
@@ -4951,15 +5509,18 @@ void __init dmasound_init(void)
int vol;
sound.mach = machPMac;
has_sound = 1;
+
awacs = (volatile struct awacs_regs *)
ioremap(np->addrs[0].address, 0x80);
awacs_txdma = (volatile struct dbdma_regs *)
ioremap(np->addrs[1].address, 0x100);
awacs_rxdma = (volatile struct dbdma_regs *)
ioremap(np->addrs[2].address, 0x100);
+
awacs_irq = np->intrs[0].line;
awacs_tx_irq = np->intrs[1].line;
awacs_rx_irq = np->intrs[2].line;
+
awacs_tx_cmd_space = kmalloc((numBufs + 4) * sizeof(struct dbdma_cmd),
GFP_KERNEL);
if (awacs_tx_cmd_space == NULL) {
@@ -4968,6 +5529,18 @@ void __init dmasound_init(void)
}
awacs_tx_cmds = (volatile struct dbdma_cmd *)
DBDMA_ALIGN(awacs_tx_cmd_space);
+
+
+ awacs_rx_cmd_space = kmalloc((numReadBufs + 4) * sizeof(struct dbdma_cmd),
+ GFP_KERNEL);
+ if (awacs_rx_cmd_space == NULL) {
+ printk("DMA sound driver: No memory for input");
+ }
+ awacs_rx_cmds = (volatile struct dbdma_cmd *)
+ DBDMA_ALIGN(awacs_rx_cmd_space);
+
+
+
awacs_reg[0] = MASK_MUX_CD;
awacs_reg[1] = MASK_LOOPTHRU | MASK_PAROUT;
/* get default volume from nvram */
@@ -5001,9 +5574,33 @@ void __init dmasound_init(void)
printk(KERN_WARNING "dmasound: no memory for "
"beep buffer\n");
#ifdef CONFIG_PMAC_PBOOK
- notifier_chain_register(&sleep_notifier_list,
- &awacs_sleep_notifier);
+ pmu_register_sleep_notifier(&awacs_sleep_notifier);
#endif /* CONFIG_PMAC_PBOOK */
+
+ /* Powerbooks have odd ways of enabling inputs such as
+ an expansion-bay CD or sound from an internal modem
+ or a PC-card modem. */
+ if (machine_is_compatible("AAPL,3400/2400")) {
+ is_pbook_3400 = 1;
+ /*
+ * Enable CD and PC-card sound inputs.
+ * This is done by reading from address
+ * f301a000, + 0x10 to enable the expansion-bay
+ * CD sound input, + 0x80 to enable the PC-card
+ * sound input. The 0x100 seems to enable the
+ * MESH and/or its SCSI bus drivers.
+ */
+ in_8((unsigned char *)0xf301a190);
+ } else if (machine_is_compatible("PowerBook1,1")) {
+ np = find_devices("mac-io");
+ if (np && np->n_addrs > 0) {
+ is_pbook_G3 = 1;
+ macio_base = (unsigned char *)
+ ioremap(np->addrs[0].address, 0x40);
+ /* enable CD sound input */
+ out_8(macio_base + 0x37, 3);
+ }
+ }
}
#endif /* CONFIG_PPC */
@@ -5083,6 +5680,9 @@ void cleanup_module(void)
sound.mach.irqcleanup();
}
+#ifdef CONFIG_PPC
+ sq_release_read_buffers();
+#endif
sq_release_buffers();
if (mixer_unit >= 0)