[parisc-linux] Recording with harmony
Matthieu Delahaye
delahaym@esiee.fr
Tue, 06 Mar 2001 22:55:06 +0100
This is a multi-part message in MIME format.
--------------EB42E961D7878AECC355519F
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
If you want to record your voice on your favorite workstation :)
--
Matthieu Delahaye
ESIEE Team
http://www.esiee.fr/puffin
--------------EB42E961D7878AECC355519F
Content-Type: text/plain; charset=us-ascii;
name="harmony.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="harmony.diff"
diff -Nru linux.old/drivers/sound/harmony.c linux.new/drivers/sound/harmony.c
--- linux.old/drivers/sound/harmony.c Tue Mar 6 22:37:56 2001
+++ linux.new/drivers/sound/harmony.c Tue Mar 6 22:41:27 2001
@@ -69,11 +69,13 @@
- modularisation,
- cleanups
+2001-03-07: Matthieu Delahaye <delahaym@esiee.fr>
+ - added record functionality
+
TODO:
-----
- update/cleanup the above documentation
- fix CHECK_xxx functions -> use newer cache flushing functions
- - add recording functionality
- test if loading/unloading this driver as module works
*/
@@ -243,13 +245,21 @@
u8 sample_rate;
u8 stereo_select; /* 1 = stereo, 0 = mono */
int format_initialized;
- int suspended;
- int blocked;
- int done;
- wait_queue_head_t wq;
- int first_filled; /* first buffer containing data (next to play) */
- int nb_filled;
+ int suspended_playing;
+ int suspended_recording;
+ int blocked_playing;
+ int blocked_recording;
+
+ int done;
+ wait_queue_head_t wq_play, wq_record;
+ int first_filled_play; /* first buffer containing data (next to play) */
+ int nb_filled_play;
+ int first_filled_record;
+ int nb_filled_record;
+ int playing;
+ int recording;
+
int audio_open, mixer_open;
int dsp_unit, mixer_unit;
};
@@ -262,13 +272,18 @@
/* Until we have recording working, this is where we're putting the recording data. */
-static char graveyard[4096]
- __attribute__((aligned(4096)));
static struct harmony_dev harmony;
-static unsigned char aligned_buf[MAX_BUFS * HARMONY_BUF_SIZE]
- __attribute__ ((aligned (HARMONY_BUF_SIZE)));
+static unsigned char played_buf[MAX_BUFS * HARMONY_BUF_SIZE]
+ __attribute__ ((aligned (HARMONY_BUF_SIZE)));
+static unsigned char recorded_buf[MAX_BUFS * HARMONY_BUF_SIZE]
+ __attribute__ ((aligned (HARMONY_BUF_SIZE)));
+static char silent[HARMONY_BUF_SIZE]
+ __attribute__((aligned(4096)));
+static char graveyard[HARMONY_BUF_SIZE]
+ __attribute__((aligned(4096)));
+
static void harmony_wait_CNTL(void)
@@ -347,12 +362,15 @@
static int harmony_disable_interrupts(void)
{
+ harmony_wait_CNTL();
+
gsc_writel(0, &(harmony.hpa->dstatus));
return 0;
}
static int harmony_enable_interrupts(void)
{
+ harmony_wait_CNTL();
gsc_writel(DSTATUS_IE, &(harmony.hpa->dstatus));
return 0;
}
@@ -379,7 +397,7 @@
default: silence_char = 0;
}
- memset(aligned_buf+start, silence_char, length);
+ memset(played_buf+start, silence_char, length);
return 0;
}
@@ -393,19 +411,28 @@
harmony.frames_so_far = 0;
harmony.done = 0;
harmony.format_initialized = 0;
- harmony.suspended = 0;
- harmony.blocked = 0;
- harmony.first_filled = 0;
- harmony.nb_filled = 0;
- init_waitqueue_head(&harmony.wq);
+ harmony.suspended_playing = 1;
+ harmony.blocked_playing = 0;
+ harmony.suspended_recording =1;
+ harmony.blocked_recording=0;
+ harmony.first_filled_play = 0;
+ harmony.nb_filled_play = 0;
+ harmony.first_filled_record = 0;
+ harmony.nb_filled_record = 0;
+
+ init_waitqueue_head(&harmony.wq_play);
+ init_waitqueue_head(&harmony.wq_record);
/* Start off in a balanced mode. */
+ harmony_set_control(HARMONY_DF_16BIT_LINEAR, HARMONY_SR_44KHZ, HARMONY_SS_STEREO);
+ harmony_update_control();
+
/* Clear out all the buffers and flush to cache */
- harmony_silence(aligned_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
- CHECK_WBACK_INV(aligned_buf, HARMONY_BUF_SIZE*MAX_BUFS);
+ harmony_silence(played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
+ CHECK_WBACK_INV(played_buf, HARMONY_BUF_SIZE*MAX_BUFS);
- harmony_mixer_mute_all();
+// harmony_mixer_mute_all();
harmony_wait_CNTL();
@@ -434,15 +461,52 @@
static ssize_t harmony_audio_read(struct file *file,
char *buffer,
- size_t count,
+ size_t size_count,
loff_t *ppos)
{
- DPRINTK(KERN_ERR "%s: invalid read\n", __FUNCTION__);
- return -ENODEV;
+ int total_count = (int) size_count;
+ int count = 0;
+ int buf_to_read;
+
+ while (count<total_count) {
+ /* Wait until we're out of control mode */
+ harmony_wait_CNTL();
+
+ /* Figure out which buffer to fill in */
+
+ if(harmony.nb_filled_record<=2) {
+ harmony.blocked_recording = 1;
+ if(harmony.suspended_recording) {
+ harmony.suspended_recording=0;
+ harmony_enable_interrupts();
+ }
+
+ interruptible_sleep_on(&(harmony.wq_record));
+ harmony.blocked_recording=0;
+ }
+ if(harmony.nb_filled_record<2) return -EBUSY;
+
+ buf_to_read = harmony.first_filled_record;
+
+ /* Figure out the size of the frame */
+
+ /* Copy the page to an aligned buffer */
+ copy_to_user(buffer+count,
+ recorded_buf+(HARMONY_BUF_SIZE*buf_to_read),
+ HARMONY_BUF_SIZE);
+
+ harmony.nb_filled_record--;
+ harmony.first_filled_record++;
+ harmony.first_filled_record%=MAX_BUFS;
+
+ count += 4096;
+ }
+ return count;
}
+
/* Here is the place where we try to recognize file format.
Sun/NeXT .au files began with the string .snd
At offset 12 is specified the encoding.
@@ -531,12 +595,16 @@
harmony_wait_CNTL();
/* Figure out which buffer to fill in */
- while (harmony.nb_filled+2 >= MAX_BUFS) {
- harmony.blocked = 1;
- interruptible_sleep_on(&(harmony.wq));
+
+ if(harmony.nb_filled_play+2 >= MAX_BUFS) {
+ harmony.blocked_playing = 1;
+ interruptible_sleep_on(&(harmony.wq_play));
+ harmony.blocked_playing=0;
}
-
- buf_to_fill = (harmony.first_filled+harmony.nb_filled) % MAX_BUFS;
+ if(harmony.nb_filled_play+2 >= MAX_BUFS) return -EBUSY;
+
+
+ buf_to_fill = (harmony.first_filled_play+harmony.nb_filled_play) % MAX_BUFS;
/* Figure out the size of the frame */
if ((total_count-count) > HARMONY_BUF_SIZE) {
@@ -545,33 +613,26 @@
frame_size = total_count - count;
/* Clear out the buffer, since there we'll only be
overlaying part of the old buffer with the new one */
- harmony_silence(aligned_buf, HARMONY_BUF_SIZE*buf_to_fill,
+ harmony_silence(played_buf, HARMONY_BUF_SIZE*buf_to_fill,
HARMONY_BUF_SIZE);
}
/* Copy the page to an aligned buffer */
- copy_from_user(aligned_buf+(HARMONY_BUF_SIZE*buf_to_fill),
+ copy_from_user(played_buf+(HARMONY_BUF_SIZE*buf_to_fill),
buffer+count, frame_size);
- harmony.nb_filled++;
+ harmony.nb_filled_play++;
- CHECK_WBACK_INV(aligned_buf, HARMONY_BUF_SIZE*MAX_BUFS);
+ CHECK_WBACK_INV(played_buf, HARMONY_BUF_SIZE*MAX_BUFS);
harmony.done = 0;
count += frame_size;
- if (harmony.frames_so_far == 1) {
- harmony_mixer_unmute();
- harmony_enable_interrupts();
- }
-
- if (harmony.suspended) {
- harmony.suspended = 0;
+ if (harmony.suspended_playing && (harmony.nb_filled_play>=4)) {
harmony_enable_interrupts();
}
-
- harmony.frames_so_far++;
}
+
return count;
}
@@ -678,37 +739,63 @@
/* Setup the hpa */
hpa = ((struct harmony_dev *)dev)->hpa;
+ harmony_wait_CNTL();
/* Read dstatus and pcuradd (the current address) */
dstatus = gsc_readl(&hpa->dstatus);
/* Turn off interrupts */
harmony_disable_interrupts();
- dstatus = gsc_readl(&hpa->dstatus);
/* Check if this is a request to get the next play buffer */
if (dstatus & DSTATUS_PN) {
- if (!harmony.nb_filled) {
- harmony.suspended = 1;
+ if (!harmony.nb_filled_play) {
+ harmony.suspended_playing = 1;
+ harmony_silence(silent, 0,HARMONY_BUF_SIZE);
+ gsc_writel(__pa(silent), &hpa->pnxtadd);
+
+ if(!harmony.suspended_recording) {
+ harmony_enable_interrupts();
+ }
} else {
- gsc_writel(__pa(aligned_buf+(HARMONY_BUF_SIZE*harmony.first_filled)),
+ harmony.suspended_playing=0;
+ gsc_writel(__pa(played_buf+(HARMONY_BUF_SIZE*harmony.first_filled_play)),
&hpa->pnxtadd);
- harmony.first_filled++;
- harmony.first_filled %= MAX_BUFS;
- harmony.nb_filled--;
- harmony_enable_interrupts();
+ harmony.first_filled_play++;
+ harmony.first_filled_play %= MAX_BUFS;
+ harmony.nb_filled_play--;
+
+ harmony_enable_interrupts();
}
-
- if (harmony.blocked) {
- wake_up_interruptible(&(harmony.wq));
- harmony.blocked = 0;
+ if (harmony.blocked_playing) {
+ wake_up_interruptible(&(harmony.wq_play));
}
}
/* Check if we're being asked to fill in a recording buffer */
if (dstatus & DSTATUS_RN) {
- /* Not supported yet */
- gsc_writel(__pa(graveyard), &hpa->rnxtadd);
+ if((harmony.nb_filled_record+2>=MAX_BUFS) || harmony.suspended_recording)
+ {
+ harmony.nb_filled_record=0;
+ harmony.first_filled_record=0;
+ harmony.suspended_recording = 1;
+ gsc_writel(__pa(graveyard), &hpa->rnxtadd);
+ if(!harmony.suspended_playing)
+ harmony_enable_interrupts();
+ } else {
+ int buf_to_fill;
+ buf_to_fill=(harmony.first_filled_record+harmony.nb_filled_record)%MAX_BUFS;
+ CHECK_WBACK_INV(recorded_buf+(HARMONY_BUF_SIZE*buf_to_fill), HARMONY_BUF_SIZE);
+ gsc_writel(__pa(recorded_buf+(HARMONY_BUF_SIZE*(buf_to_fill))),&hpa->rnxtadd);
+ harmony.nb_filled_record++;
+ harmony_enable_interrupts();
+ }
+
+ if (harmony.blocked_recording &&
+ harmony.nb_filled_record>3) {
+
+ wake_up_interruptible(&(harmony.wq_record));
+ }
}
}
@@ -738,13 +825,12 @@
return -EFAULT;
}
- harmony_set_control(HARMONY_DF_16BIT_LINEAR, HARMONY_SR_22KHZ, HARMONY_SS_MONO);
-
+
/* Clear the buffers so you don't end up with crap in the buffers. */
- harmony_silence(aligned_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
+ harmony_silence(played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
/* Make sure this makes it to cache */
- CHECK_WBACK_INV(aligned_buf, HARMONY_BUF_SIZE*MAX_BUFS);
+ CHECK_WBACK_INV(played_buf, HARMONY_BUF_SIZE*MAX_BUFS);
/* Wait around until we're out of control mode */
harmony_wait_CNTL();
--------------EB42E961D7878AECC355519F--