patch-1.3.9 linux/drivers/sound/dmabuf.c
Next file: linux/drivers/sound/experimental.txt
Previous file: linux/drivers/sound/dev_table.h
Back to the patch index
Back to the overall index
- Lines: 418
- Date:
Mon Jul 10 01:45:06 1995
- Orig file:
v1.3.8/linux/drivers/sound/dmabuf.c
- Orig date:
Mon Mar 6 11:22:09 1995
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c
@@ -3,7 +3,7 @@
*
* The DMA buffer manager for digitized voice applications
*
- * Copyright by Hannu Savolainen 1993, 1994
+ * Copyright by Hannu Savolainen 1993, 1994, 1995
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -38,11 +38,13 @@
DEFINE_WAIT_QUEUES (dev_sleeper[MAX_AUDIO_DEV], dev_sleep_flag[MAX_AUDIO_DEV]);
static struct dma_buffparms dmaps[MAX_AUDIO_DEV] =
-{{0}}; /*
- * Primitive way to allocate
- * such a large array.
- * Needs dynamic run-time allocation.
- */
+{
+ {0}}; /*
+
+ * Primitive way to allocate
+ * such a large array.
+ * Needs dynamic run-time alloction.
+ */
static void
reorganize_buffers (int dev)
@@ -78,10 +80,10 @@
sz = sr * nc * sz;
/*
- * Compute a buffer size for time not exceeding 1 second.
- * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds
- * of sound (using the current speed, sample size and #channels).
- */
+ * Compute a buffer size for time not exeeding 1 second.
+ * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds
+ * of sound (using the current speed, sample size and #channels).
+ */
bsz = dsp_dev->buffsize;
while (bsz > sz)
@@ -106,9 +108,9 @@
else
{
/*
- * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or
- * the buffer size computation has already been done.
- */
+ * The process has specified the buffer sice with SNDCTL_DSP_SETFRAGMENT or
+ * the buffer sice computation has already been done.
+ */
if (dmap->fragment_size > audio_devs[dev]->buffsize)
dmap->fragment_size = audio_devs[dev]->buffsize;
bsz = dmap->fragment_size;
@@ -157,7 +159,6 @@
dmap->flags = DMA_BUSY; /* Other flags off */
dmap->qlen = dmap->qhead = dmap->qtail = 0;
- dmap->qlen = dmap->qtail = dmap->qhead = 0;
dmap->dma_mode = DMODE_NONE;
}
@@ -250,7 +251,7 @@
/*
* Some devices such as GUS have huge amount of on board RAM for the
- * audio data. We have to wait util the device has finished playing.
+ * audio data. We have to wait until the device has finished playing.
*/
DISABLE_INTR (flags);
@@ -295,7 +296,7 @@
}
int
-DMAbuf_getrdbuffer (int dev, char **buf, int *len)
+DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock)
{
unsigned long flags;
int err = EIO;
@@ -342,6 +343,12 @@
dmap->flags |= DMA_ACTIVE | DMA_STARTED;
}
+ if (dontblock)
+ {
+ RESTORE_INTR (flags);
+ return RET_ERROR (EAGAIN);
+ }
+
/* Wait for the next block */
DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ);
@@ -425,7 +432,7 @@
}
if (dmap->subdivision != 0 ||
- dmap->fragment_size)/* Too late to change */
+ dmap->fragment_size) /* Loo late to change */
return RET_ERROR (EINVAL);
if (fact > MAX_REALTIME_FACTOR)
@@ -448,7 +455,7 @@
return RET_ERROR (EIO);
if (dmap->subdivision != 0 ||
- dmap->fragment_size)/* Too late to change */
+ dmap->fragment_size) /* Loo late to change */
return RET_ERROR (EINVAL);
bytes = fact & 0xffff;
@@ -478,11 +485,24 @@
}
break;
+ case SNDCTL_DSP_GETISPACE:
+ case SNDCTL_DSP_GETOSPACE:
+ if (!local)
+ return RET_ERROR (EINVAL);
+
+ {
+ audio_buf_info *info = (audio_buf_info *) arg;
+
+ info->fragments = dmap->qlen;
+ info->fragsize = dmap->fragment_size;
+ info->bytes = dmap->qlen * dmap->fragment_size;
+ }
+ return 0;
+
default:
return audio_devs[dev]->ioctl (dev, cmd, arg, local);
}
- return RET_ERROR (EIO);
}
static int
@@ -491,13 +511,13 @@
int len, max, tmp;
struct dma_buffparms *dmap = audio_devs[dev]->dmap;
- if (dmap->qlen == dmap->nbufs)/* No space at all */
+ if (dmap->qlen == dmap->nbufs) /* No space at all */
return 0;
/*
- * Verify that there are no more pending buffers than the limit
- * defined by the process.
- */
+ * Verify that there are no more pending buffers than the limit
+ * defined by the process.
+ */
max = dmap->max_fragments;
len = dmap->qlen;
@@ -507,8 +527,8 @@
tmp = audio_devs[dev]->local_qlen (dev);
if (tmp & len)
tmp--; /*
- * This buffer has been counted twice
- */
+ * This buffer has been counted twice
+ */
len += tmp;
}
@@ -518,7 +538,7 @@
}
int
-DMAbuf_getwrbuffer (int dev, char **buf, int *size)
+DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock)
{
unsigned long flags;
int abort, err = EIO;
@@ -551,6 +571,9 @@
}
+ if (dontblock)
+ return RET_ERROR (EAGAIN);
+
DISABLE_INTR (flags);
abort = 0;
@@ -669,13 +692,24 @@
#ifndef DMAMODE_AUTO
printk ("sound: Invalid DMA mode for device %d\n", dev);
#endif
+#if defined(SVR42)
+
+ /*
+ ** send full count to snd_dma_prog, it will take care of subtracting
+ ** one if it is required.
+ */
+ snd_dma_prog (chan, dmap->raw_buf_phys[0], dmap->bytes_in_use,
+ dma_mode, TRUE);
+
+#else /* !SVR42 */
dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode)
#ifdef DMAMODE_AUTO
| DMAMODE_AUTO
#endif
,
- dmap->raw_buf_phys[0], dmap->bytes_in_use);
+ dmap->raw_buf_phys[0], dmap->bytes_in_use - 1);
dma_enable (chan);
+#endif /* ! SVR42 */
#else
#error This routine is not valid for this OS.
#endif
@@ -703,9 +737,15 @@
#else
#if defined(GENERIC_SYSV)
+#if defined(SVR42)
+
+ snd_dma_prog (chan, physaddr, count, dma_mode, FALSE);
+
+#else /* ! SVR42 */
dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode),
physaddr, count);
dma_enable (chan);
+#endif /* SVR42 */
#else
#error This routine is not valid for this OS.
#endif /* GENERIC_SYSV */
@@ -722,9 +762,13 @@
{
int dev;
+#if defined(SVR42)
+ snd_dma_init ();
+#endif /* SVR42 */
+
/*
- * NOTE! This routine could be called several times.
- */
+ * NOTE! This routine could be called several times.
+ */
for (dev = 0; dev < num_audiodevs; dev++)
audio_devs[dev]->dmap = &dmaps[dev];
@@ -735,18 +779,22 @@
DMAbuf_outputintr (int dev, int event_type)
{
/*
- * Event types:
- * 0 = DMA transfer done. Device still has more data in the local
- * buffer.
- * 1 = DMA transfer done. Device doesn't have local buffer or it's
- * empty now.
- * 2 = No DMA transfer but the device has now more space in its local
- * buffer.
- */
+ * Event types:
+ * 0 = DMA transfer done. Device still has more data in the local
+ * buffer.
+ * 1 = DMA transfer done. Device doesn't have local buffer or it's
+ * empty now.
+ * 2 = No DMA transfer but the device has now more space in it's local
+ * buffer.
+ */
unsigned long flags;
struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+#if defined(SVR42)
+ snd_dma_intr (audio_devs[dev]->dmachan);
+#endif /* SVR42 */
+
if (event_type != 2)
{
if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
@@ -793,6 +841,10 @@
unsigned long flags;
struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+#if defined(SVR42)
+ snd_dma_intr (audio_devs[dev]->dmachan);
+#endif /* SVR42 */
+
if (dmap->qlen == (dmap->nbufs - 1))
{
printk ("Sound: Recording overrun\n");
@@ -832,7 +884,7 @@
unsigned long flags;
int chan = audio_devs[dev]->dmachan;
- if (ALLOC_DMA_CHN (chan,"audio"))
+ if (ALLOC_DMA_CHN (chan, audio_devs[dev]->name))
{
printk ("Unable to grab DMA%d for the audio driver\n", chan);
return RET_ERROR (EBUSY);
@@ -853,24 +905,72 @@
{
int chan = audio_devs[dev]->dmachan;
- DMAbuf_reset_dma (chan);
+ DMAbuf_reset_dma (dev);
RELEASE_DMA_CHN (chan);
}
void
-DMAbuf_reset_dma (int chan)
+DMAbuf_reset_dma (int dev)
{
+#if 0
+ int chan = audio_devs[dev]->dmachan;
+
+ disable_dma (chan);
+#endif
}
-/*
- * The sound_mem_init() is called by mem_init() immediately after mem_map is
- * initialized and before free_page_list is created.
- *
- * This routine allocates DMA buffers at the end of available physical memory (
- * <16M) and marks pages reserved at mem_map.
- */
+#ifdef ALLOW_SELECT
+int
+DMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
+{
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ unsigned long flags;
-#else
+ switch (sel_type)
+ {
+ case SEL_IN:
+ if (dmap->dma_mode != DMODE_INPUT)
+ return 0;
+
+ if (!dmap->qlen)
+ {
+ DISABLE_INTR (flags);
+ dev_sleep_flag[dev].mode = WK_SLEEP;
+ select_wait (&dev_sleeper[dev], wait);
+ RESTORE_INTR (flags);
+ return 0;
+ }
+ return 1;
+ break;
+
+ case SEL_OUT:
+ if (dmap->dma_mode == DMODE_INPUT)
+ return 0;
+
+ if (dmap->dma_mode == DMODE_NONE)
+ return 1;
+
+ if (!space_in_queue (dev))
+ {
+ DISABLE_INTR (flags);
+ dev_sleep_flag[dev].mode = WK_SLEEP;
+ select_wait (&dev_sleeper[dev], wait);
+ RESTORE_INTR (flags);
+ return 0;
+ }
+ return 1;
+ break;
+
+ case SEL_EX:
+ return 0;
+ }
+
+ return 0;
+}
+
+#endif /* ALLOW_SELECT */
+
+#else /* EXCLUDE_AUDIO */
/*
* Stub versions if audio services not included
*/
@@ -888,13 +988,13 @@
}
int
-DMAbuf_getwrbuffer (int dev, char **buf, int *size)
+DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock)
{
return RET_ERROR (EIO);
}
int
-DMAbuf_getrdbuffer (int dev, char **buf, int *len)
+DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock)
{
return RET_ERROR (EIO);
}
@@ -930,19 +1030,19 @@
}
int
-DMAbuf_open_dma (int chan)
+DMAbuf_open_dma (int dev)
{
return RET_ERROR (ENXIO);
}
void
-DMAbuf_close_dma (int chan)
+DMAbuf_close_dma (int dev)
{
return;
}
void
-DMAbuf_reset_dma (int chan)
+DMAbuf_reset_dma (int dev)
{
return;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this