From owner-freebsd-bugs Mon Feb 10 21:59:07 1997 Return-Path: Received: (from root@localhost) by freefall.freebsd.org (8.8.5/8.8.5) id VAA00575 for bugs-outgoing; Mon, 10 Feb 1997 21:59:07 -0800 (PST) Received: from meter.eng.uci.edu (root@meter.eng.uci.edu [128.200.85.3]) by freefall.freebsd.org (8.8.5/8.8.5) with ESMTP id VAA00553; Mon, 10 Feb 1997 21:59:02 -0800 (PST) Received: from newport.ece.uci.edu by meter.eng.uci.edu (8.8.5) id VAA14360; Mon, 10 Feb 1997 21:58:59 -0800 (PST) Received: from localhost by newport.ece.uci.edu (8.8.5) id VAA23924; Mon, 10 Feb 1997 21:58:57 -0800 (PST) Message-Id: <199702110558.VAA23924@newport.ece.uci.edu> To: current@freebsd.org cc: bugs@freebsd.org Subject: Important bug fix for sound driver Date: Mon, 10 Feb 1997 21:58:54 -0800 From: Steven Wallace Sender: owner-bugs@freebsd.org X-Loop: FreeBSD.org Precedence: bulk In compiling a Linux program for FreeBSD, I have discovered a bug in FreeBSD's version of the sound driver. The problem has to do with the SNDCTL_DSP_GETOSPACE ioctl. It is suppose to return the available buffer space to the structure audio_buf_info. When you first open the /dev/dsp device and check the buffer, it reports there is 0 bytes available when there is nothing in it. If you write a partial fragment, and then quickly check the buffer, now there appears to be some space left. The ioctl is only reporting partially used fragments and not whole fragments. I therefore used the code from Linux 1.3.20's dmabuf.c to correct the problem (It has the same BSD-style copyright). Here is the diff output. If there is no objections, this should be commited for 2.2R. Steven *** i386/isa/sound/dmabuf.c.orig Tue Sep 10 03:04:50 1996 --- i386/isa/sound/dmabuf.c Mon Feb 10 21:37:21 1997 *************** *** 44,49 **** --- 44,53 ---- * Needs dynamic run-time alloction. */ + static int space_in_queue (int); + static void reorganize_buffers (int); + static void dma_init_buffers (int); + static void reorganize_buffers (int dev) { *************** *** 510,523 **** 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: --- 514,561 ---- case SNDCTL_DSP_GETOSPACE: if (!local) return RET_ERROR (EINVAL); + else + { + audio_buf_info *info = (audio_buf_info *) arg; ! if (!(dmap->flags & DMA_ALLOC_DONE)) ! reorganize_buffers (dev); ! info->fragstotal = dmap->nbufs; ! ! if (cmd == SNDCTL_DSP_GETISPACE) ! info->fragments = dmap->qlen; ! else ! { ! if (!space_in_queue (dev)) ! info->fragments = 0; ! else ! { ! info->fragments = dmap->nbufs - dmap->qlen; ! if (audio_devs[dev]->local_qlen) ! { ! int tmp = audio_devs[dev]->local_qlen (dev); ! ! if (tmp & info->fragments) ! tmp--; /* ! * This buffer has been counted twice ! */ ! info->fragments -= tmp; ! } ! } ! } ! ! if (info->fragments < 0) ! info->fragments = 0; ! else if (info->fragments > dmap->nbufs) ! info->fragments = dmap->nbufs; ! ! info->fragsize = dmap->fragment_size; ! info->bytes = info->fragments * dmap->fragment_size; ! ! if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen) ! info->bytes -= dmap->counts[dmap->qhead]; ! } return 0; default: *** i386/include/soundcard.h.orig Thu Nov 21 16:23:40 1996 --- i386/include/soundcard.h Mon Feb 10 21:37:07 1997 *************** *** 577,582 **** --- 577,583 ---- */ typedef struct audio_buf_info { int fragments; /* # of available fragments (partially usend ones not counted) */ + int fragstotal; /* Total # of fragments allocated */ int fragsize; /* Size of a fragment in bytes */ int bytes; /* Available space in bytes (includes partially used fragments) */