--- vanilla-2.5.32/sound/oss/dmabuf.c Sat Apr 20 18:25:19 2002
+++ linux-2.5-cli-oss/sound/oss/dmabuf.c Fri Aug 16 12:31:59 2002
@@ -199,6 +199,7 @@
return -EBUSY;
}
dma_init_buffers(dmap);
+ spin_lock_init(&dmap->lock);
dmap->open_mode = mode;
dmap->subdivision = dmap->underrun_count = 0;
dmap->fragment_size = 0;
@@ -319,7 +320,7 @@
adev->dmap_out->bytes_in_use);
return 0;
}
-
+/* MUST not hold the spinlock */
void DMAbuf_reset(int dev)
{
if (audio_devs[dev]->open_mode & OPEN_WRITE)
@@ -341,15 +342,17 @@
/*
* First wait until the current fragment has been played completely
*/
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&dmap->lock,flags);
adev->dmap_out->flags |= DMA_SYNCING;
adev->dmap_out->underrun_count = 0;
if (!signal_pending(current) && adev->dmap_out->qlen &&
- adev->dmap_out->underrun_count == 0)
+ adev->dmap_out->underrun_count == 0){
+ spin_unlock_irqrestore(&dmap->lock,flags);
interruptible_sleep_on_timeout(&adev->out_sleeper,
dmabuf_timeout(dmap));
+ spin_lock_irqsave(&dmap->lock,flags);
+ }
adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE);
/*
@@ -366,10 +369,10 @@
disable_dma(dmap->dma);
release_dma_lock(f);
- restore_flags(flags);
dmap->byte_counter = 0;
reorganize_buffers(dev, adev->dmap_out, 0);
dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0;
+ spin_unlock_irqrestore(&dmap->lock,flags);
}
static void dma_reset_input(int dev)
@@ -378,20 +381,19 @@
unsigned long flags;
struct dma_buffparms *dmap = adev->dmap_in;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&dmap->lock,flags);
if (!(adev->flags & DMA_DUPLEX) || !adev->d->halt_input)
adev->d->halt_io(dev);
else
adev->d->halt_input(dev);
adev->dmap_in->flags &= ~DMA_STARTED;
- restore_flags(flags);
dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0;
dmap->byte_counter = 0;
reorganize_buffers(dev, adev->dmap_in, 1);
+ spin_unlock_irqrestore(&dmap->lock,flags);
}
-
+/* MUST be called with holding the dmap->lock */
void DMAbuf_launch_output(int dev, struct dma_buffparms *dmap)
{
struct audio_operations *adev = audio_devs[dev];
@@ -432,8 +434,7 @@
if (adev->dmap_out->dma_mode == DMODE_OUTPUT) {
dmap = adev->dmap_out;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&dmap->lock,flags);
if (dmap->qlen > 0 && !(dmap->flags & DMA_ACTIVE))
DMAbuf_launch_output(dev, dmap);
adev->dmap_out->flags |= DMA_SYNCING;
@@ -441,31 +442,33 @@
while (!signal_pending(current) && n++ <= adev->dmap_out->nbufs &&
adev->dmap_out->qlen && adev->dmap_out->underrun_count == 0) {
long t = dmabuf_timeout(dmap);
- t = interruptible_sleep_on_timeout(&adev->out_sleeper,
- t);
+ spin_unlock_irqrestore(&dmap->lock,flags);
+ t = interruptible_sleep_on_timeout(&adev->out_sleeper, t);
+ spin_lock_irqsave(&dmap->lock,flags);
if (!t) {
adev->dmap_out->flags &= ~DMA_SYNCING;
- restore_flags(flags);
+ spin_unlock_irqrestore(&dmap->lock,flags);
return adev->dmap_out->qlen;
}
}
adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE);
- restore_flags(flags);
/*
* Some devices such as GUS have huge amount of on board RAM for the
* audio data. We have to wait until the device has finished playing.
*/
- save_flags(flags);
- cli();
+ /* still holding the lock */
if (adev->d->local_qlen) { /* Device has hidden buffers */
while (!signal_pending(current) &&
- adev->d->local_qlen(dev))
+ adev->d->local_qlen(dev)){
+ spin_unlock_irqrestore(&dmap->lock,flags);
interruptible_sleep_on_timeout(&adev->out_sleeper,
dmabuf_timeout(dmap));
+ spin_lock_irqsave(&dmap->lock,flags);
+ }
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&dmap->lock,flags);
}
adev->dmap_out->dma_mode = DMODE_NONE;
return adev->dmap_out->qlen;
@@ -474,23 +477,26 @@
int DMAbuf_release(int dev, int mode)
{
struct audio_operations *adev = audio_devs[dev];
+ struct dma_buffparms *dmap;
unsigned long flags;
+ dmap = adev->dmap_out;
if (adev->open_mode & OPEN_WRITE)
adev->dmap_out->closing = 1;
- if (adev->open_mode & OPEN_READ)
- adev->dmap_in->closing = 1;
+ if (adev->open_mode & OPEN_READ){
+ adev->dmap_in->closing = 1;
+ dmap = adev->dmap_in;
+ }
if (adev->open_mode & OPEN_WRITE)
if (!(adev->dmap_out->mapping_flags & DMA_MAP_MAPPED))
if (!signal_pending(current) && (adev->dmap_out->dma_mode == DMODE_OUTPUT))
DMAbuf_sync(dev);
if (adev->dmap_out->dma_mode == DMODE_OUTPUT)
memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte, adev->dmap_out->bytes_in_use);
- save_flags(flags);
- cli();
DMAbuf_reset(dev);
+ spin_lock_irqsave(&dmap->lock,flags);
adev->d->close(dev);
if (adev->open_mode & OPEN_WRITE)
@@ -501,10 +507,10 @@
(adev->flags & DMA_DUPLEX)))
close_dmap(adev, adev->dmap_in);
adev->open_mode = 0;
- restore_flags(flags);
+ spin_unlock_irqrestore(&dmap->lock,flags);
return 0;
}
-
+/* called with dmap->lock dold */
int DMAbuf_activate_recording(int dev, struct dma_buffparms *dmap)
{
struct audio_operations *adev = audio_devs[dev];
@@ -515,8 +521,12 @@
if (!(adev->enable_bits & PCM_ENABLE_INPUT))
return 0;
if (dmap->dma_mode == DMODE_OUTPUT) { /* Direction change */
+ unsigned long flags;
+ /* release lock - it's not recursive */
+ spin_unlock_irqrestore(&dmap->lock,flags);
DMAbuf_sync(dev);
DMAbuf_reset(dev);
+ spin_lock_irqsave(&dmap->lock,flags);
dmap->dma_mode = DMODE_NONE;
}
if (!dmap->dma_mode) {
@@ -538,7 +548,7 @@
}
return 0;
}
-
+/* aquires lock */
int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock)
{
struct audio_operations *adev = audio_devs[dev];
@@ -549,34 +559,36 @@
if (!(adev->open_mode & OPEN_READ))
return -EIO;
+ spin_lock_irqsave(&dmap->lock,flags);
if (dmap->needs_reorg)
reorganize_buffers(dev, dmap, 0);
- save_flags(flags);
- cli();
if (adev->dmap_in->mapping_flags & DMA_MAP_MAPPED) {
/* printk(KERN_WARNING "Sound: Can't read from mmapped device (1)\n");*/
- restore_flags(flags);
+ spin_unlock_irqrestore(&dmap->lock,flags);
return -EINVAL;
} else while (dmap->qlen <= 0 && n++ < 10) {
long timeout = MAX_SCHEDULE_TIMEOUT;
if (!(adev->enable_bits & PCM_ENABLE_INPUT) || !adev->go) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&dmap->lock,flags);
return -EAGAIN;
}
if ((err = DMAbuf_activate_recording(dev, dmap)) < 0) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&dmap->lock,flags);
return err;
}
/* Wait for the next block */
if (dontblock) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&dmap->lock,flags);
return -EAGAIN;
}
if ((go = adev->go))
timeout = dmabuf_timeout(dmap);
+
+ spin_unlock_irqrestore(&dmap->lock,flags);
timeout = interruptible_sleep_on_timeout(&adev->in_sleeper,
timeout);
+ spin_lock_irqsave(&dmap->lock,flags);
if (!timeout) {
/* FIXME: include device name */
err = -EIO;
@@ -585,7 +597,7 @@
} else
err = -EINTR;
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&dmap->lock,flags);
if (dmap->qlen <= 0)
return err ? err : -EINTR;
@@ -617,7 +629,7 @@
return 0;
}
-
+/* MUST be called with dmap->lock hold */
int DMAbuf_get_buffer_pointer(int dev, struct dma_buffparms *dmap, int direction)
{
/*
@@ -626,11 +638,8 @@
*/
int pos;
- unsigned long flags;
unsigned long f;
- save_flags(flags);
- cli();
if (!(dmap->flags & DMA_ACTIVE))
pos = 0;
else {
@@ -667,7 +676,6 @@
release_dma_lock(f);
}
- restore_flags(flags);
/* printk( "%04x ", pos); */
return pos;
@@ -698,7 +706,7 @@
adev->d->trigger(dev,adev->enable_bits * adev->go);
}
}
-
+/* via poll called without a lock ?*/
int DMAbuf_space_in_queue(int dev)
{
struct audio_operations *adev = audio_devs[dev];
@@ -735,7 +743,7 @@
return 0;
return max - len;
}
-
+/* MUST not hold the spinlock - this function may sleep */
static int output_sleep(int dev, int dontblock)
{
struct audio_operations *adev = audio_devs[dev];
@@ -770,12 +778,11 @@
}
return err;
}
-
+/* called with the lock held */
static int find_output_space(int dev, char **buf, int *size)
{
struct audio_operations *adev = audio_devs[dev];
struct dma_buffparms *dmap = adev->dmap_out;
- unsigned long flags;
unsigned long active_offs;
long len, offs;
int maxfrags;
@@ -784,8 +791,6 @@
*buf = dmap->raw_buf;
if (!(maxfrags = DMAbuf_space_in_queue(dev)) && !occupied_bytes)
return 0;
- save_flags(flags);
- cli();
#ifdef BE_CONSERVATIVE
active_offs = dmap->byte_counter + dmap->qhead * dmap->fragment_size;
@@ -799,7 +804,6 @@
offs = (dmap->user_counter % dmap->bytes_in_use) & ~SAMPLE_ROUNDUP;
if (offs < 0 || offs >= dmap->bytes_in_use) {
- restore_flags(flags);
printk(KERN_ERR "Sound: Got unexpected offs %ld. Giving up.\n", offs);
printk("Counter = %ld, bytes=%d\n", dmap->user_counter, dmap->bytes_in_use);
return 0;
@@ -811,16 +815,14 @@
if ((offs + len) > dmap->bytes_in_use)
len = dmap->bytes_in_use - offs;
if (len < 0) {
- restore_flags(flags);
return 0;
}
if (len > ((maxfrags * dmap->fragment_size) - occupied_bytes))
len = (maxfrags * dmap->fragment_size) - occupied_bytes;
*size = len & ~SAMPLE_ROUNDUP;
- restore_flags(flags);
return (*size > 0);
}
-
+/* aquires lock */
int DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock)
{
struct audio_operations *adev = audio_devs[dev];
@@ -828,39 +830,45 @@
int err = -EIO;
struct dma_buffparms *dmap = adev->dmap_out;
- if (dmap->needs_reorg)
- reorganize_buffers(dev, dmap, 0);
-
if (dmap->mapping_flags & DMA_MAP_MAPPED) {
/* printk(KERN_DEBUG "Sound: Can't write to mmapped device (3)\n");*/
return -EINVAL;
}
+ spin_lock_irqsave(&dmap->lock,flags);
+ if (dmap->needs_reorg)
+ reorganize_buffers(dev, dmap, 0);
+
if (dmap->dma_mode == DMODE_INPUT) { /* Direction change */
+ spin_unlock_irqrestore(&dmap->lock,flags);
DMAbuf_reset(dev);
- dmap->dma_mode = DMODE_NONE;
+ spin_lock_irqsave(&dmap->lock,flags);
}
dmap->dma_mode = DMODE_OUTPUT;
- save_flags(flags);
- cli();
while (find_output_space(dev, buf, size) <= 0) {
+ spin_unlock_irqrestore(&dmap->lock,flags);
if ((err = output_sleep(dev, dontblock)) < 0) {
- restore_flags(flags);
return err;
}
+ spin_lock_irqsave(&dmap->lock,flags);
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&dmap->lock,flags);
return 0;
}
-
+/* has to aquire dmap->lock */
int DMAbuf_move_wrpointer(int dev, int l)
{
struct audio_operations *adev = audio_devs[dev];
struct dma_buffparms *dmap = adev->dmap_out;
- unsigned long ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size;
+ unsigned long ptr;
unsigned long end_ptr, p;
- int post = (dmap->flags & DMA_POST);
+ int post;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dmap->lock,flags);
+ post= (dmap->flags & DMA_POST);
+ ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size;
dmap->flags &= ~DMA_POST;
dmap->cfrag = -1;
@@ -890,7 +898,7 @@
dmap->counts[dmap->qtail] = dmap->user_counter - ptr;
/*
- * Let the low level driver to perform some postprocessing to
+ * Let the low level driver perform some postprocessing to
* the written data.
*/
if (adev->d->postprocess_write)
@@ -899,6 +907,8 @@
if (!(dmap->flags & DMA_ACTIVE))
if (dmap->qlen > 1 || (dmap->qlen > 0 && (post || dmap->qlen >= dmap->nbufs - 1)))
DMAbuf_launch_output(dev, dmap);
+
+ spin_unlock_irqrestore(&dmap->lock,flags);
return 0;
}
@@ -945,11 +955,10 @@
wake_up(&adev->out_sleeper);
wake_up(&adev->poll_sleeper);
}
-
+/* called with dmap->lock held in irq context*/
static void do_outputintr(int dev, int dummy)
{
struct audio_operations *adev = audio_devs[dev];
- unsigned long flags;
struct dma_buffparms *dmap = adev->dmap_out;
int this_fragment;
@@ -977,8 +986,6 @@
finish_output_interrupt(dev, dmap);
return;
}
- save_flags(flags);
- cli();
dmap->qlen--;
this_fragment = dmap->qhead;
@@ -1014,18 +1021,16 @@
}
if (dmap->qlen > 0)
DMAbuf_launch_output(dev, dmap);
- restore_flags(flags);
finish_output_interrupt(dev, dmap);
}
-
+/* called in irq context */
void DMAbuf_outputintr(int dev, int notify_only)
{
struct audio_operations *adev = audio_devs[dev];
unsigned long flags;
struct dma_buffparms *dmap = adev->dmap_out;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&dmap->lock,flags);
if (!(dmap->flags & DMA_NODMA)) {
int chan = dmap->dma, pos, n;
unsigned long f;
@@ -1049,9 +1054,9 @@
}
else
do_outputintr(dev, notify_only);
- restore_flags(flags);
+ spin_unlock_irqrestore(&dmap->lock,flags);
}
-
+/* called with dmap->lock held in irq context */
static void do_inputintr(int dev)
{
struct audio_operations *adev = audio_devs[dev];
@@ -1117,15 +1122,14 @@
wake_up(&adev->poll_sleeper);
}
}
-
+/* called in irq context */
void DMAbuf_inputintr(int dev)
{
struct audio_operations *adev = audio_devs[dev];
struct dma_buffparms *dmap = adev->dmap_in;
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&dmap->lock,flags);
if (!(dmap->flags & DMA_NODMA)) {
int chan = dmap->dma, pos, n;
@@ -1149,7 +1153,7 @@
do_inputintr(dev);
} else
do_inputintr(dev);
- restore_flags(flags);
+ spin_unlock_irqrestore(&dmap->lock,flags);
}
int DMAbuf_open_dma(int dev)
@@ -1240,10 +1244,9 @@
!dmap->qlen && adev->go) {
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&dmap->lock,flags);
DMAbuf_activate_recording(dev, dmap);
- restore_flags(flags);
+ spin_unlock_irqrestore(&dmap->lock,flags);
}
return 0;
}
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
This archive was generated by hypermail 2b29 : Sat Aug 31 2002 - 22:00:28 EST