From: Nathan Bryant <nbryant@optonline.net>
To: linux-kernel@vger.kernel.org, dledford@redhat.com
Subject: i810 audio patch
Date: Mon, 03 Dec 2001 19:20:55 -0500 [thread overview]
Message-ID: <3C0C16E7.70206@optonline.net> (raw)
[-- Attachment #1: Type: text/plain, Size: 765 bytes --]
this patch is slightly differerent from the last one i posted.
it's still diffed against 2.4.17pre1. one obvious thinko is fixed, and a
couple lines that looked bad to me have been changed (goto end in
i810_read seems to be necessary to clean up the wait queue unless I'm
mistaken), and I'm no longer reproducing any OOPSes.
however, i am seeing artsd segfault occasionally. this also seems to
happen with the 4Front driver, however, at least if I load 4Front's
module after unloading this patched driver. I'm not sure if this is a
bug in artsd or specific to my setup or something nasty i've done to my
kernel's data structures ;) so maybe somebody else who's still having
problems with 2.4.17pre1 and KDE can take a look and see how it works
for them.
[-- Attachment #2: i810.diff2 --]
[-- Type: text/plain, Size: 13951 bytes --]
--- i810_audio.c.17p1 Mon Dec 3 14:14:40 2001
+++ linux/drivers/sound/i810_audio.c Mon Dec 3 19:06:33 2001
@@ -197,7 +197,7 @@
#define INT_MASK (INT_SEC|INT_PRI|INT_MC|INT_PO|INT_PI|INT_MO|INT_NI|INT_GPI)
-#define DRIVER_VERSION "0.04"
+#define DRIVER_VERSION "0.05b"
/* magic numbers to protect our data structures */
#define I810_CARD_MAGIC 0x5072696E /* "Prin" */
@@ -357,6 +357,10 @@
struct i810_channel *(*alloc_rec_pcm_channel)(struct i810_card *);
struct i810_channel *(*alloc_rec_mic_channel)(struct i810_card *);
void (*free_pcm_channel)(struct i810_card *, int chan);
+
+ /* We have a *very* long init time possibly, so use this to block */
+ /* attempts to open our devices before we are ready (stops oops'es) */
+ int initializing;
};
static struct i810_card *devs = NULL;
@@ -364,32 +368,6 @@
static int i810_open_mixdev(struct inode *inode, struct file *file);
static int i810_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg);
-
-static inline unsigned ld2(unsigned int x)
-{
- unsigned r = 0;
-
- if (x >= 0x10000) {
- x >>= 16;
- r += 16;
- }
- if (x >= 0x100) {
- x >>= 8;
- r += 8;
- }
- if (x >= 0x10) {
- x >>= 4;
- r += 4;
- }
- if (x >= 4) {
- x >>= 2;
- r += 2;
- }
- if (x >= 2)
- r++;
- return r;
-}
-
static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg);
static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
@@ -969,14 +947,6 @@
else
port += dmabuf->write_channel->port;
- if(dmabuf->mapped) {
- if(rec)
- dmabuf->swptr = (dmabuf->hwptr + dmabuf->dmasize
- - dmabuf->count) % dmabuf->dmasize;
- else
- dmabuf->swptr = (dmabuf->hwptr + dmabuf->count)
- % dmabuf->dmasize;
- }
/*
* two special cases, count == 0 on write
* means no data, and count == dmasize
@@ -993,7 +963,7 @@
/* swptr - 1 is the tail of our transfer */
x = (dmabuf->dmasize + dmabuf->swptr - 1) % dmabuf->dmasize;
x /= dmabuf->fragsize;
- outb(x&31, port+OFF_LVI);
+ outb(x, port+OFF_LVI);
}
static void i810_update_lvi(struct i810_state *state, int rec)
@@ -1020,7 +990,9 @@
/* update hardware pointer */
hwptr = i810_get_dma_addr(state, 1);
diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
-// printk("HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
+#ifdef DEBUG_INTERRUPTS
+ printk("ADC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
+#endif
dmabuf->hwptr = hwptr;
dmabuf->total_bytes += diff;
dmabuf->count += diff;
@@ -1043,7 +1015,9 @@
/* update hardware pointer */
hwptr = i810_get_dma_addr(state, 0);
diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
-// printk("HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
+#ifdef DEBUG_INTERRUPTS
+ printk("DAC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
+#endif
dmabuf->hwptr = hwptr;
dmabuf->total_bytes += diff;
dmabuf->count -= diff;
@@ -1068,6 +1042,40 @@
}
}
+static inline int i810_get_free_write_space(struct i810_state *state)
+{
+ struct dmabuf *dmabuf = &state->dmabuf;
+ int free;
+
+ i810_update_ptr(state);
+ // catch underruns during playback
+ if (dmabuf->count < 0) {
+ dmabuf->count = 0;
+ }
+ free = dmabuf->dmasize - dmabuf->count;
+ free -= (dmabuf->hwptr % dmabuf->fragsize);
+ if(free < 0)
+ return(0);
+ return(free);
+}
+
+static inline int i810_get_available_read_data(struct i810_state *state)
+{
+ struct dmabuf *dmabuf = &state->dmabuf;
+ int avail;
+
+ i810_update_ptr(state);
+ // catch overruns during record
+ if (dmabuf->count > dmabuf->dmasize) {
+ dmabuf->count = dmabuf->dmasize;
+ }
+ avail = dmabuf->count;
+ avail -= (dmabuf->hwptr % dmabuf->fragsize);
+ if(avail < 0)
+ return(0);
+ return(avail);
+}
+
static int drain_dac(struct i810_state *state, int nonblock)
{
DECLARE_WAITQUEUE(wait, current);
@@ -1271,10 +1279,7 @@
continue;
}
swptr = dmabuf->swptr;
- if (dmabuf->count > dmabuf->dmasize) {
- dmabuf->count = dmabuf->dmasize;
- }
- cnt = dmabuf->count - dmabuf->fragsize;
+ cnt = i810_get_available_read_data(state);
// this is to make the copy_to_user simpler below
if(cnt > (dmabuf->dmasize - swptr))
cnt = dmabuf->dmasize - swptr;
@@ -1291,7 +1296,7 @@
i810_update_lvi(state,1);
if (file->f_flags & O_NONBLOCK) {
if (!ret) ret = -EAGAIN;
- return ret;
+ goto done;
}
/* This isnt strictly right for the 810 but it'll do */
tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
@@ -1315,7 +1320,7 @@
}
if (signal_pending(current)) {
ret = ret ? ret : -ERESTARTSYS;
- return ret;
+ goto done;
}
continue;
}
@@ -1402,10 +1407,7 @@
}
swptr = dmabuf->swptr;
- if (dmabuf->count < 0) {
- dmabuf->count = 0;
- }
- cnt = dmabuf->dmasize - swptr;
+ cnt = i810_get_free_write_space(state);
if(cnt > (dmabuf->dmasize - dmabuf->count))
cnt = dmabuf->dmasize - dmabuf->count;
spin_unlock_irqrestore(&state->card->lock, flags);
@@ -1508,13 +1510,8 @@
mask |= POLLIN | POLLRDNORM;
}
if (file->f_mode & FMODE_WRITE && dmabuf->enable & DAC_RUNNING) {
- if (dmabuf->mapped) {
- if (dmabuf->count >= (signed)dmabuf->fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- if ((signed)dmabuf->dmasize >= dmabuf->count + (signed)dmabuf->fragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
+ if ((signed)dmabuf->dmasize >= dmabuf->count + (signed)dmabuf->fragsize)
+ mask |= POLLOUT | POLLWRNORM;
}
spin_unlock_irqrestore(&state->card->lock, flags);
@@ -1559,10 +1556,7 @@
size, vma->vm_page_prot))
goto out;
dmabuf->mapped = 1;
- if(vma->vm_flags & VM_WRITE)
- dmabuf->count = dmabuf->dmasize;
- else
- dmabuf->count = 0;
+ dmabuf->count = 0;
ret = 0;
#ifdef DEBUG
printk("i810_audio: mmap'ed %ld bytes of data space\n", size);
@@ -1580,11 +1574,9 @@
audio_buf_info abinfo;
count_info cinfo;
unsigned int i_glob_cnt;
- int val = 0, mapped, ret;
+ int val = 0, ret;
struct ac97_codec *codec = state->card->ac97_codec[0];
- mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) ||
- ((file->f_mode & FMODE_READ) && dmabuf->mapped);
#ifdef DEBUG
printk("i810_audio: i810_ioctl, arg=0x%x, cmd=", arg ? *(int *)arg : 0);
#endif
@@ -1674,9 +1666,6 @@
#ifdef DEBUG
printk("SNDCTL_DSP_STEREO\n");
#endif
- if (get_user(val, (int *)arg))
- return -EFAULT;
-
if (dmabuf->enable & DAC_RUNNING) {
stop_dac(state);
}
@@ -1820,22 +1809,47 @@
dmabuf->ossfragsize = 1<<(val & 0xffff);
dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
- if (dmabuf->ossmaxfrags <= 4)
- dmabuf->ossmaxfrags = 4;
- else if (dmabuf->ossmaxfrags <= 8)
- dmabuf->ossmaxfrags = 8;
- else if (dmabuf->ossmaxfrags <= 16)
- dmabuf->ossmaxfrags = 16;
- else
- dmabuf->ossmaxfrags = 32;
+ if (!dmabuf->ossfragsize || !dmabuf->ossmaxfrags)
+ return -EINVAL;
+ /*
+ * Bound the frag size into our allowed range of 256 - 4096
+ */
+ if (dmabuf->ossfragsize < 256)
+ dmabuf->ossfragsize = 256;
+ else if (dmabuf->ossfragsize > 4096)
+ dmabuf->ossfragsize = 4096;
+ /*
+ * The numfrags could be something reasonable, or it could
+ * be 0xffff meaning "Give me as much as possible". So,
+ * we check the numfrags * fragsize doesn't exceed our
+ * 64k buffer limit, nor is it less than our 8k minimum.
+ * If it fails either one of these checks, then adjust the
+ * number of fragments, not the size of them. It's OK if
+ * our number of fragments doesn't equal 32 or anything
+ * like our hardware based number now since we are using
+ * a different frag count for the hardware. Before we get
+ * into this though, bound the maxfrags to avoid overflow
+ * issues. A reasonable bound would be 64k / 256 since our
+ * maximum buffer size is 64k and our minimum frag size is
+ * 256. On the other end, our minimum buffer size is 8k and
+ * our maximum frag size is 4k, so the lower bound should
+ * be 2.
+ */
+
+ if(dmabuf->ossmaxfrags > 256)
+ dmabuf->ossmaxfrags = 256;
+ else if (dmabuf->ossmaxfrags < 2)
+ dmabuf->ossmaxfrags = 2;
+
val = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
- if (val < 16384)
- val = 16384;
- if (val > 65536)
- val = 65536;
- dmabuf->ossmaxfrags = val/dmabuf->ossfragsize;
- if(dmabuf->ossmaxfrags<4)
- dmabuf->ossfragsize = val/4;
+ while (val < 8192) {
+ val <<= 1;
+ dmabuf->ossmaxfrags <<= 1;
+ }
+ while (val > 65536) {
+ val >>= 1;
+ dmabuf->ossmaxfrags >>= 1;
+ }
dmabuf->ready = 0;
#ifdef DEBUG
printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val,
@@ -1853,10 +1867,10 @@
i810_update_ptr(state);
abinfo.fragsize = dmabuf->userfragsize;
abinfo.fragstotal = dmabuf->userfrags;
- if(dmabuf->mapped)
- abinfo.bytes = dmabuf->count;
- else
- abinfo.bytes = dmabuf->dmasize - dmabuf->fragsize - dmabuf->count;
+ if (dmabuf->mapped)
+ abinfo.bytes = dmabuf->dmasize;
+ else
+ abinfo.bytes = i810_get_free_write_space(state);
abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
spin_unlock_irqrestore(&state->card->lock, flags);
#ifdef DEBUG
@@ -1871,13 +1885,13 @@
if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
return val;
spin_lock_irqsave(&state->card->lock, flags);
- i810_update_ptr(state);
+ val = i810_get_free_write_space(state);
cinfo.bytes = dmabuf->total_bytes;
cinfo.ptr = dmabuf->hwptr;
- cinfo.blocks = (dmabuf->dmasize - dmabuf->count)/dmabuf->userfragsize;
- if (dmabuf->mapped) {
- dmabuf->count = (dmabuf->dmasize -
- (dmabuf->count & (dmabuf->userfragsize-1)));
+ cinfo.blocks = val/dmabuf->userfragsize;
+ if (dmabuf->mapped && dmabuf->enable && DAC_RUNNING) {
+ dmabuf->count += val;
+ dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
__i810_update_lvi(state, 0);
}
spin_unlock_irqrestore(&state->card->lock, flags);
@@ -1893,10 +1907,9 @@
if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
return val;
spin_lock_irqsave(&state->card->lock, flags);
- i810_update_ptr(state);
+ abinfo.bytes = i810_get_available_read_data(state);
abinfo.fragsize = dmabuf->userfragsize;
abinfo.fragstotal = dmabuf->userfrags;
- abinfo.bytes = dmabuf->dmasize - dmabuf->count;
abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
spin_unlock_irqrestore(&state->card->lock, flags);
#ifdef DEBUG
@@ -1911,12 +1924,13 @@
if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
return val;
spin_lock_irqsave(&state->card->lock, flags);
- i810_update_ptr(state);
+ val = i810_get_available_read_data(state);
cinfo.bytes = dmabuf->total_bytes;
- cinfo.blocks = dmabuf->count/dmabuf->userfragsize;
+ cinfo.blocks = val/dmabuf->userfragsize;
cinfo.ptr = dmabuf->hwptr;
- if (dmabuf->mapped) {
- dmabuf->count &= (dmabuf->userfragsize-1);
+ if (dmabuf->mapped && dmabuf->enable && ADC_RUNNING) {
+ dmabuf->count -= val;
+ dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
__i810_update_lvi(state, 1);
}
spin_unlock_irqrestore(&state->card->lock, flags);
@@ -1970,8 +1984,12 @@
if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
return ret;
if (dmabuf->mapped) {
- dmabuf->count = dmabuf->dmasize;
- i810_update_lvi(state,0);
+ spin_lock_irqsave(&state->card->lock, flags);
+ i810_update_ptr(state);
+ dmabuf->count = 0;
+ dmabuf->count = i810_get_free_write_space(state);
+ __i810_update_lvi(state, 0);
+ spin_unlock_irqrestore(&state->card->lock, flags);
}
if (!dmabuf->enable && dmabuf->count > dmabuf->userfragsize)
start_dac(state);
@@ -1985,10 +2003,6 @@
}
if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
return ret;
- if (dmabuf->mapped) {
- dmabuf->count = 0;
- i810_update_lvi(state,1);
- }
if (!dmabuf->enable && dmabuf->count <
(dmabuf->dmasize - dmabuf->userfragsize))
start_adc(state);
@@ -2195,7 +2209,11 @@
/* find an avaiable virtual channel (instance of /dev/dsp) */
while (card != NULL) {
- for (i = 0; i < NR_HW_CH; i++) {
+ for (i = 0; i < 50 && card->initializing; i++) {
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(HZ/20);
+ }
+ for (i = 0; i < NR_HW_CH && !card->initializing; i++) {
if (card->states[i] == NULL) {
state = card->states[i] = (struct i810_state *)
kmalloc(sizeof(struct i810_state), GFP_KERNEL);
@@ -2344,13 +2362,18 @@
int minor = MINOR(inode->i_rdev);
struct i810_card *card = devs;
- for (card = devs; card != NULL; card = card->next)
- for (i = 0; i < NR_AC97; i++)
+ for (card = devs; card != NULL; card = card->next) {
+ for (i = 0; i < 50 && card->initializing; i++) {
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(HZ/20);
+ }
+ for (i = 0; i < NR_AC97 && !card->initializing; i++)
if (card->ac97_codec[i] != NULL &&
card->ac97_codec[i]->dev_mixer == minor) {
file->private_data = card->ac97_codec[i];
return 0;
}
+ }
return -ENODEV;
}
@@ -2696,6 +2719,7 @@
}
memset(card, 0, sizeof(*card));
+ card->initializing = 1;
card->iobase = pci_resource_start (pci_dev, 1);
card->ac97base = pci_resource_start (pci_dev, 0);
card->pci_dev = pci_dev;
@@ -2771,7 +2795,7 @@
kfree(card);
return -ENODEV;
}
-
+ card->initializing = 0;
return 0;
}
@@ -2789,6 +2813,7 @@
if (card->ac97_codec[i] != NULL) {
unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
kfree (card->ac97_codec[i]);
+ card->ac97_codec[i] = NULL;
}
unregister_sound_dsp(card->dev_audio);
kfree(card);
@@ -2957,9 +2982,6 @@
if(ftsodell != 0) {
printk("i810_audio: ftsodell is now a deprecated option.\n");
}
- if(clocking == 48000) {
- i810_configure_clocking();
- }
if(spdif_locked > 0 ) {
if(spdif_locked == 32000 || spdif_locked == 44100 || spdif_locked == 48000) {
printk("i810_audio: Enabling S/PDIF at sample rate %dHz.\n", spdif_locked);
next reply other threads:[~2001-12-04 1:08 UTC|newest]
Thread overview: 56+ messages / expand[flat|nested] mbox.gz Atom feed top
2001-12-04 0:20 Nathan Bryant [this message]
2001-12-04 4:26 ` i810 audio patch Doug Ledford
[not found] ` <3C0C58DE.9020703@optonline.net>
2001-12-04 5:18 ` Nathan Bryant
2001-12-04 5:40 ` Doug Ledford
2001-12-04 6:07 ` Nathan Bryant
2001-12-04 7:08 ` Nathan Bryant
2001-12-04 16:46 ` Doug Ledford
2001-12-04 20:14 ` Nathan Bryant
2001-12-04 20:16 ` Doug Ledford
2001-12-04 14:35 ` Mario Mikocevic
2001-12-04 19:02 ` Nathan Bryant
2001-12-04 19:21 ` Doug Ledford
2001-12-04 20:41 ` Nathan Bryant
2001-12-04 21:15 ` Doug Ledford
2001-12-04 21:39 ` Nathan Bryant
2001-12-04 21:53 ` Nathan Bryant
2001-12-04 22:29 ` Nathan Bryant
2001-12-04 22:49 ` Nathan Bryant
2001-12-04 23:09 ` Doug Ledford
2001-12-04 23:31 ` Nathan Bryant
2001-12-04 23:44 ` Doug Ledford
2001-12-05 1:26 ` Nathan Bryant
2001-12-05 2:48 ` Nathan Bryant
2001-12-05 3:05 ` Doug Ledford
2001-12-05 3:28 ` Nathan Bryant
2001-12-05 4:25 ` Doug Ledford
2001-12-05 5:14 ` Nathan Bryant
2001-12-05 5:23 ` Doug Ledford
2001-12-05 20:04 ` Nathan Bryant
2001-12-05 20:05 ` Nathan Bryant
2001-12-05 20:10 ` Doug Ledford
2001-12-05 21:12 ` Nathan Bryant
2001-12-05 21:25 ` Doug Ledford
2001-12-05 21:36 ` Nathan Bryant
2001-12-05 21:56 ` Nathan Bryant
2001-12-05 22:31 ` Doug Ledford
2001-12-05 22:43 ` Doug Ledford
2001-12-05 23:46 ` Nathan Bryant
2001-12-05 23:51 ` Doug Ledford
2001-12-05 23:57 ` Nathan Bryant
2001-12-06 0:25 ` Doug Ledford
2001-12-06 0:50 ` Nathan Bryant
[not found] ` <3C0EC0ED.3000603@optonl! ine.net>
2001-12-06 0:55 ` Doug Ledford
[not found] ` <3C0EC219.8010107@redhat! .com>
2001-12-06 2:53 ` Nathan Bryant
[not found] ` <3C0EDDC2.608@optonl! ine.net>
2001-12-06 3:39 ` Doug Ledford
[not found] ` <3C0EC219.8010107@redhat!.com>
[not found] ` <3C0EE865.1090607@red! hat.com>
2001-12-06 4:02 ` Nathan Bryant
2001-12-06 4:09 ` Doug Ledford
2001-12-06 15:45 ` i810 audio patch (it _works_ for me :) Mario Mikocevic
2001-12-06 17:00 ` i810 audio patch Pascal Junod
2001-12-05 4:41 ` Nathan Bryant
2001-12-05 5:10 ` Doug Ledford
2001-12-05 5:35 ` Nathan Bryant
2001-12-05 7:24 ` Nathan Bryant
2001-12-04 23:05 ` Doug Ledford
2001-12-04 9:03 ` Alan Cox
-- strict thread matches above, loose matches on Subject: below --
2001-12-06 19:49 Nathan Bryant
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3C0C16E7.70206@optonline.net \
--to=nbryant@optonline.net \
--cc=dledford@redhat.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.