Index: forte.c =================================================================== RCS file: /home/mkp/Repository/forte/forte.c,v retrieving revision 1.55 retrieving revision 1.63 diff -u -u -r1.55 -r1.63 --- forte.c 2 Oct 2002 00:01:42 -0000 1.55 +++ forte.c 1 Mar 2003 05:32:42 -0000 1.63 @@ -3,6 +3,9 @@ * * Written by Martin K. Petersen * Copyright (C) 2002 Hewlett-Packard Company + * Portions Copyright (C) 2003 Martin K. Petersen + * + * Latest version: http://mkp.net/forte/ * * Based upon the ALSA FM801 driver by Jaroslav Kysela and OSS drivers * by Thomas Sailer, Alan Cox, Zach Brown, and Jeff Garzik. Thanks @@ -24,15 +27,6 @@ * */ -/* - * TODO: - * MMIO - * Multichannelize - * Multichipify - * MPU401 - * M^Gameport - */ - #include #include #include @@ -55,7 +49,7 @@ #include #define DRIVER_NAME "forte" -#define DRIVER_VERSION "$Id: forte.c,v 1.55 2002/10/02 00:01:42 mkp Exp $" +#define DRIVER_VERSION "$Id: forte.c,v 1.63 2003/03/01 05:32:42 mkp Exp $" #define PFX DRIVER_NAME ": " #undef M_DEBUG @@ -76,10 +70,11 @@ #define FORTE_MIN_FRAG_SIZE 256 #define FORTE_MAX_FRAG_SIZE PAGE_SIZE #define FORTE_DEF_FRAG_SIZE 256 -#define FORTE_MIN_FRAGMENTS 16 +#define FORTE_MIN_FRAGMENTS 2 #define FORTE_MAX_FRAGMENTS 256 -#define FORTE_DEF_FRAGMENTS 16 -#define FORTE_MIN_BUF 16386 +#define FORTE_DEF_FRAGMENTS 2 +#define FORTE_MIN_BUF_MSECS 500 +#define FORTE_MAX_BUF_MSECS 1000 /* PCI BARs */ #define FORTE_PCM_VOL 0x00 /* PCM Output Volume */ @@ -168,6 +163,7 @@ unsigned int frag_sz; /* Current fragment size */ unsigned int frag_num; /* Current # of fragments */ + unsigned int frag_msecs; /* Milliseconds per frag */ unsigned int buf_sz; /* Current buffer size */ unsigned int hwptr; /* Tail */ @@ -175,14 +171,13 @@ unsigned int filled_frags; /* Fragments currently full */ unsigned int next_buf; /* Index of next buffer */ - unsigned int blocked; /* Blocked on I/O */ - unsigned int drain; /* Drain queued buffers */ unsigned int active; /* Channel currently in use */ unsigned int mapped; /* mmap */ unsigned int buf_pages; /* Real size of buffer */ unsigned int nr_irqs; /* Number of interrupts */ unsigned int bytes; /* Total bytes */ + unsigned int residue; /* Partial fragment */ }; @@ -404,12 +399,11 @@ channel->next_buf = 1; channel->swptr = 0; channel->filled_frags = 0; - channel->blocked = 0; - channel->drain = 0; channel->active = 0; channel->bytes = 0; channel->nr_irqs = 0; channel->mapped = 0; + channel->residue = 0; } @@ -423,12 +417,11 @@ static void inline forte_channel_start (struct forte_channel *channel) { - if (!channel || !channel->iobase) + if (!channel || !channel->iobase || channel->active) return; - DPRINTK ("%s: channel = %s\n", __FUNCTION__, channel->name); - - channel->ctrl &= ~(FORTE_PAUSE | FORTE_BUF1_LAST | FORTE_BUF2_LAST); + channel->ctrl &= ~(FORTE_PAUSE | FORTE_BUF1_LAST | FORTE_BUF2_LAST + | FORTE_IMMED_STOP); channel->ctrl |= FORTE_START; channel->active = 1; outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL); @@ -448,9 +441,29 @@ if (!channel || !channel->iobase) return; - DPRINTK ("%s: channel = %s\n", __FUNCTION__, channel->name); + channel->ctrl &= ~(FORTE_START | FORTE_PAUSE); + channel->ctrl |= FORTE_IMMED_STOP; + + channel->active = 0; + outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL); +} + + +/** + * forte_channel_pause: + * @channel: Channel to pause + * + * Locking: Must be called with lock held. + */ + +static void inline +forte_channel_pause (struct forte_channel *channel) +{ + if (!channel || !channel->iobase) + return; + + channel->ctrl |= FORTE_PAUSE; - channel->ctrl &= ~FORTE_START; channel->active = 0; outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL); } @@ -584,38 +597,61 @@ * @channel: Channel whose buffer to set up * * Locking: Must be called with lock held. - * - * FIXME: Buffer scaling dependent on rate/channels/bits */ static void forte_channel_buffer (struct forte_channel *channel, int sz, int num) { + unsigned int msecs, shift; + /* Go away, I'm busy */ if (channel->filled_frags || channel->bytes) return; - channel->frag_sz = sz; - channel->frag_num = num; + /* Fragment size must be a power of 2 */ + shift = 0; sz++; + while (sz >>= 1) + shift++; + channel->frag_sz = 1 << shift; + /* Round fragment size to something reasonable */ if (channel->frag_sz < FORTE_MIN_FRAG_SIZE) channel->frag_sz = FORTE_MIN_FRAG_SIZE; if (channel->frag_sz > FORTE_MAX_FRAG_SIZE) channel->frag_sz = FORTE_MAX_FRAG_SIZE; + /* Find fragment length in milliseconds */ + msecs = channel->frag_sz / + (channel->format == AFMT_S16_LE ? 2 : 1) / + (channel->stereo ? 2 : 1) / + (channel->rate / 1000); + + channel->frag_msecs = msecs; + + /* Pick a suitable number of fragments */ + if (msecs * num < FORTE_MIN_BUF_MSECS) + num = FORTE_MIN_BUF_MSECS / msecs; + + if (msecs * num > FORTE_MAX_BUF_MSECS) + num = FORTE_MAX_BUF_MSECS / msecs; + + /* Fragment number must be a power of 2 */ + shift = 0; + while (num >>= 1) + shift++; + channel->frag_num = 1 << (shift + 1); + + /* Round fragment number to something reasonable */ if (channel->frag_num < FORTE_MIN_FRAGMENTS) channel->frag_num = FORTE_MIN_FRAGMENTS; if (channel->frag_num > FORTE_MAX_FRAGMENTS) channel->frag_num = FORTE_MAX_FRAGMENTS; - if (channel->frag_sz * channel->frag_num < FORTE_MIN_BUF) - channel->frag_num = FORTE_MIN_BUF / channel->frag_sz; - channel->buf_sz = channel->frag_sz * channel->frag_num; - DPRINTK ("%s: %s frag_sz = %d, frag_num = %d, buf_sz = %d\n", + DPRINTK ("%s: %s frag_sz = %d, frag_num = %d, buf_sz = %d\n", __FUNCTION__, channel->name, channel->frag_sz, channel->frag_num, channel->buf_sz); } @@ -637,6 +673,7 @@ if (channel->buf) return; + forte_channel_buffer (channel, channel->frag_sz, channel->frag_num); channel->buf_pages = channel->buf_sz >> PAGE_SHIFT; if (channel->buf_sz % PAGE_SIZE) @@ -688,8 +725,7 @@ DECLARE_WAITQUEUE (wait, current); unsigned long flags; - if (!channel->active) - return 0; + DPRINTK ("%s\n", __FUNCTION__); if (channel->mapped) { spin_lock_irqsave (&forte->lock, flags); @@ -698,24 +734,26 @@ return 0; } - channel->drain = 1; + spin_lock_irqsave (&forte->lock, flags); add_wait_queue (&channel->wait, &wait); for (;;) { - spin_lock_irqsave (&forte->lock, flags); - - if (channel->active == 0 || channel->filled_frags < 1) + if (channel->active == 0 || channel->filled_frags == 1) break; spin_unlock_irqrestore (&forte->lock, flags); + __set_current_state (TASK_INTERRUPTIBLE); schedule(); + + spin_lock_irqsave (&forte->lock, flags); } - channel->drain = 0; - spin_unlock_irqrestore (&forte->lock, flags); + forte_channel_stop (channel); + forte_channel_reset (channel); set_current_state (TASK_RUNNING); remove_wait_queue (&channel->wait, &wait); + spin_unlock_irqrestore (&forte->lock, flags); return 0; } @@ -765,8 +803,8 @@ forte_channel_stereo (channel, 1); forte_channel_format (channel, AFMT_S16_LE); forte_channel_rate (channel, 48000); - forte_channel_buffer (channel, FORTE_DEF_FRAG_SIZE, - FORTE_DEF_FRAGMENTS); + channel->frag_sz = FORTE_DEF_FRAG_SIZE; + channel->frag_num = FORTE_DEF_FRAGMENTS; chip->trigger = 0; spin_unlock_irq (&chip->lock); @@ -967,12 +1005,8 @@ case SNDCTL_DSP_SYNC: DPRINTK ("%s: SYNC\n", __FUNCTION__); - if (wr) { + if (wr) ret = forte_channel_drain (&chip->play); - spin_lock_irq (&chip->lock); - forte_channel_reset (&chip->play); - spin_unlock_irq (&chip->lock); - } return 0; @@ -981,7 +1015,10 @@ if (wr) { spin_lock_irq (&chip->lock); - forte_channel_reset (&chip->play); + + if (chip->play.filled_frags) + forte_channel_start (&chip->play); + spin_unlock_irq (&chip->lock); } @@ -1059,7 +1096,7 @@ case SNDCTL_DSP_GETOSPACE: if (!wr) return -EINVAL; - + spin_lock_irq (&chip->lock); abi.fragstotal = chip->play.frag_num; @@ -1072,7 +1109,12 @@ else { abi.fragments = chip->play.frag_num - chip->play.filled_frags; - abi.bytes = abi.fragments * abi.fragsize; + + if (chip->play.residue) + abi.fragments--; + + abi.bytes = abi.fragments * abi.fragsize + + chip->play.residue; } spin_unlock_irq (&chip->lock); @@ -1099,20 +1141,23 @@ return copy_to_user ((void *) arg, &cinfo, sizeof (cinfo)); case SNDCTL_DSP_GETODELAY: - if (!chip->play.active) - return 0; - if (!wr) return -EINVAL; spin_lock_irq (&chip->lock); - if (chip->play.mapped) { + if (!chip->play.active) { + ival = 0; + } + else if (chip->play.mapped) { count = inw (chip->play.iobase + FORTE_PLY_COUNT) + 1; ival = chip->play.frag_sz - count; } else { ival = chip->play.filled_frags * chip->play.frag_sz; + + if (chip->play.residue) + ival += chip->play.frag_sz - chip->play.residue; } spin_unlock_irq (&chip->lock); @@ -1170,13 +1215,18 @@ return put_user (chip->play.rate, (int *) arg); case SOUND_PCM_READ_CHANNELS: - DPRINTK ("%s: PCM_READ_CHANNELS\n", __FUNCTION__); + DPRINTK ("%s: PCM_READ_CHANNELS\n", __FUNCTION__); return put_user (chip->play.stereo, (int *) arg); case SOUND_PCM_READ_BITS: DPRINTK ("%s: PCM_READ_BITS\n", __FUNCTION__); return put_user (chip->play.format, (int *) arg); + case SNDCTL_DSP_NONBLOCK: + DPRINTK ("%s: DSP_NONBLOCK\n", __FUNCTION__); + file->f_flags |= O_NONBLOCK; + return 0; + default: DPRINTK ("Unsupported ioctl: %x (%p)\n", cmd, (void *) arg); break; @@ -1195,14 +1245,22 @@ { struct forte_chip *chip = forte; /* FIXME: HACK FROM HELL! */ - if (down_interruptible (&chip->open_sem)) { - DPRINTK ("%s: returning -ERESTARTSYS\n", __FUNCTION__); - return -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (down_trylock (&chip->open_sem)) { + DPRINTK ("%s: returning -EAGAIN\n", __FUNCTION__); + return -EAGAIN; + } + } + else { + if (down_interruptible (&chip->open_sem)) { + DPRINTK ("%s: returning -ERESTARTSYS\n", __FUNCTION__); + return -ERESTARTSYS; + } } file->private_data = forte; - DPRINTK ("%s: chip @ %p\n", __FUNCTION__, file->private_data); + DPRINTK ("%s: dsp opened by %d\n", __FUNCTION__, current->pid); if (file->f_mode & FMODE_WRITE) forte_channel_init (forte, &forte->play); @@ -1231,9 +1289,7 @@ spin_lock_irq (&chip->lock); - chip->play.ctrl |= FORTE_IMMED_STOP; - forte_channel_stop (&chip->play); - forte_channel_free (chip, &chip->play); + forte_channel_free (chip, &chip->play); spin_unlock_irq (&chip->lock); } @@ -1244,7 +1300,6 @@ spin_lock_irq (&chip->lock); - chip->play.ctrl |= FORTE_IMMED_STOP; forte_channel_stop (&chip->rec); forte_channel_free (chip, &chip->rec); @@ -1260,7 +1315,6 @@ /** * forte_dsp_poll: * - * FIXME: Racy */ static unsigned int @@ -1278,8 +1332,12 @@ if (channel->active) poll_wait (file, &channel->wait, wait); - if (channel->filled_frags) + spin_lock_irq (&chip->lock); + + if (channel->frag_num - channel->filled_frags > 0) mask |= POLLOUT | POLLWRNORM; + + spin_unlock_irq (&chip->lock); } if (file->f_mode & FMODE_READ) { @@ -1288,8 +1346,12 @@ if (channel->active) poll_wait (file, &channel->wait, wait); + spin_lock_irq (&chip->lock); + if (channel->filled_frags > 0) mask |= POLLIN | POLLRDNORM; + + spin_unlock_irq (&chip->lock); } return mask; @@ -1405,62 +1467,64 @@ if (channel->frag_num - channel->filled_frags == 0) { DECLARE_WAITQUEUE (wait, current); - /* For trigger mode operation, get out */ - if (chip->trigger) { + /* For trigger or non-blocking operation, get out */ + if (chip->trigger || file->f_flags & O_NONBLOCK) { spin_unlock_irqrestore (&chip->lock, flags); return -EAGAIN; } /* Otherwise wait for buffers */ - channel->blocked = 1; add_wait_queue (&channel->wait, &wait); for (;;) { - if (channel->active == 0) - break; - - if (channel->frag_num - channel->filled_frags) - break; - spin_unlock_irqrestore (&chip->lock, flags); set_current_state (TASK_INTERRUPTIBLE); - schedule(); + schedule(); spin_lock_irqsave (&chip->lock, flags); + + if (channel->frag_num - channel->filled_frags) + break; } - set_current_state (TASK_RUNNING); remove_wait_queue (&channel->wait, &wait); - channel->blocked = 0; + set_current_state (TASK_RUNNING); + + if (signal_pending (current)) { + spin_unlock_irqrestore (&chip->lock, flags); + return -ERESTARTSYS; + } } - if (i > channel->frag_sz) + if (channel->residue) + sz = channel->residue; + else if (i > channel->frag_sz) sz = channel->frag_sz; else sz = i; spin_unlock_irqrestore (&chip->lock, flags); - /* Clear the fragment so we don't get noise when copying - * smaller buffers - */ - memset ((void *) channel->buf + channel->swptr, 0x0, sz); - - if (copy_from_user ((void *) channel->buf + channel->swptr, - buffer, sz)) { + if (copy_from_user ((void *) channel->buf + channel->swptr, buffer, sz)) return -EFAULT; - } spin_lock_irqsave (&chip->lock, flags); /* Advance software pointer */ buffer += sz; - channel->filled_frags++; - channel->swptr += channel->frag_sz; + channel->swptr += sz; channel->swptr %= channel->buf_sz; i -= sz; + /* Only bump filled_frags if a full fragment has been written */ + if (channel->swptr % channel->frag_sz == 0) { + channel->filled_frags++; + channel->residue = 0; + } + else + channel->residue = channel->frag_sz - sz; + /* If playback isn't active, start it */ if (channel->active == 0 && chip->trigger == 0) forte_channel_start (channel); @@ -1521,7 +1585,6 @@ return -EAGAIN; } - channel->blocked = 1; add_wait_queue (&channel->wait, &wait); for (;;) { @@ -1541,7 +1604,6 @@ set_current_state (TASK_RUNNING); remove_wait_queue (&channel->wait, &wait); - channel->blocked = 0; } if (i > channel->frag_sz) @@ -1560,7 +1622,8 @@ /* Advance software pointer */ buffer += sz; - channel->filled_frags--; + if (channel->filled_frags > 0) + channel->filled_frags--; channel->swptr += channel->frag_sz; channel->swptr %= channel->buf_sz; i -= sz; @@ -1607,23 +1670,16 @@ if (status & FORTE_IRQ_PLAYBACK) { channel = &chip->play; - spin_lock (&chip->lock); - - /* Declare a fragment done */ - channel->filled_frags--; - /* Get # of completed bytes */ - count = inw (channel->iobase + FORTE_PLY_COUNT) + 1; - channel->bytes += count; + spin_lock (&chip->lock); - if (count == 0) { - DPRINTK ("%s: last, filled_frags = %d\n", __FUNCTION__, - channel->filled_frags); - channel->filled_frags = 0; - forte_channel_stop (channel); + if (channel->frag_sz == 0) goto pack; - } + /* Declare a fragment done */ + if (channel->filled_frags > 0) + channel->filled_frags--; + channel->bytes += channel->frag_sz; channel->nr_irqs++; /* Flip-flop between buffer I and II */ @@ -1639,17 +1695,18 @@ channel->iobase + FORTE_PLY_BUF1 : channel->iobase + FORTE_PLY_BUF2); - /* If the currently playing fragment is last, schedule stop */ - if (channel->filled_frags == 1) - forte_channel_stop (channel); + /* If the currently playing fragment is last, schedule pause */ + if (channel->filled_frags == 1) + forte_channel_pause (channel); + pack: /* Acknowledge interrupt */ outw (FORTE_IRQ_PLAYBACK, chip->iobase + FORTE_IRQ_STATUS); - spin_unlock (&chip->lock); + if (waitqueue_active (&channel->wait)) + wake_up_all (&channel->wait); - if (channel->blocked || channel->drain) - wake_up_interruptible (&channel->wait); + spin_unlock (&chip->lock); } if (status & FORTE_IRQ_CAPTURE) { @@ -1668,7 +1725,7 @@ channel->filled_frags = 0; goto rack; } - + /* Buffer I or buffer II BAR */ outl (channel->buf_handle + channel->hwptr, channel->next_buf == 0 ? @@ -1691,7 +1748,7 @@ spin_unlock (&chip->lock); - if (channel->blocked) + if (waitqueue_active (&channel->wait)) wake_up_all (&channel->wait); } @@ -1710,7 +1767,7 @@ int i = 0, p_rate, p_chan, r_rate; unsigned short p_reg, r_reg; - i += sprintf (page, "ForteMedia FM801 OSS Lite driver\n%s\n\n", + i += sprintf (page, "ForteMedia FM801 OSS Lite driver\n%s\n \n", DRIVER_VERSION); if (!forte->iobase) @@ -1745,7 +1802,14 @@ "Rate : %-5d %-5d\n" "Channels : %-5d -\n" "16-bit : %-3s %-3s\n" - "Stereo : %-3s %-3s\n", + "Stereo : %-3s %-3s\n" + " \n" + "Buffer Sz : %-6d %-6d\n" + "Frag Sz : %-6d %-6d\n" + "Frag Num : %-6d %-6d\n" + "Frag msecs : %-6d %-6d\n" + "Used Frags : %-6d %-6d\n" + "Mapped : %-3s %-3s\n", p_reg & 1<<0 ? "yes" : "no", r_reg & 1<<0 ? "yes" : "no", p_reg & 1<<1 ? "yes" : "no", @@ -1763,7 +1827,15 @@ p_reg & 1<<14 ? "yes" : "no", r_reg & 1<<14 ? "yes" : "no", p_reg & 1<<15 ? "yes" : "no", - r_reg & 1<<15 ? "yes" : "no"); + r_reg & 1<<15 ? "yes" : "no", + forte->play.buf_sz, forte->rec.buf_sz, + forte->play.frag_sz, forte->rec.frag_sz, + forte->play.frag_num, forte->rec.frag_num, + forte->play.frag_msecs, forte->rec.frag_msecs, + forte->play.filled_frags, forte->rec.filled_frags, + forte->play.mapped ? "yes" : "no", + forte->rec.mapped ? "yes" : "no" + ); return i; }