⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bsd_audio.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
	register int error;	while (!AUCB_EMPTY(&sc->sc_au.au_wb))		if ((error = audio_sleep(&sc->sc_au.au_wb, 0)) != 0)			return (error);	return (0);}/* * Close an audio chip. *//* ARGSUSED */intAUDIOCLOSE(dev, flags, ifmt, p){	register struct audio_softc *sc = SOFTC(dev);	register volatile struct amd7930 *amd;	register struct aucb *cb;	register int s;	/*	 * Block until output drains, but allow ^C interrupt.	 */	sc->sc_au.au_lowat = 0;	/* avoid excessive wakeups */	s = splaudio();	/*	 * If there is pending output, let it drain (unless	 * the output is paused).	 */	cb = &sc->sc_au.au_wb;	if (!AUCB_EMPTY(cb) && !cb->cb_pause)		(void)audio_drain(sc);	/*	 * Disable interrupts, clear open flag, and done.	 */	amd = sc->sc_au.au_amd;	amd->cr = AMDR_INIT;	amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE;	splx(s);	sc->sc_open = 0;	return (0);}intaudio_sleep(cb, thresh)	register struct aucb *cb;	register int thresh;{	register int error;	register int s = splaudio();	cb->cb_thresh = thresh;	error = tsleep((caddr_t)cb, (PZERO + 1) | PCATCH, "audio", 0);	splx(s);	return (error);}/* ARGSUSED */intAUDIOREAD(dev, uio, ioflag){	register struct audio_softc *sc = SOFTC(dev);	register struct aucb *cb;	register int n, head, taildata, error;	register int blocksize = sc->sc_au.au_blksize;	if (uio->uio_resid == 0)		return (0);	cb = &sc->sc_au.au_rb;	error = 0;	cb->cb_drops = 0;	sc->sc_rseek = sc->sc_au.au_stamp - AUCB_LEN(cb);	do {		while (AUCB_LEN(cb) < blocksize) {#ifndef SUNOS			if (ioflag & IO_NDELAY) {				error = EWOULDBLOCK;				return (error);			}#endif			if ((error = audio_sleep(cb, blocksize)) != 0)				return (error);		}		/*		 * The space calculation can only err on the short		 * side if an interrupt occurs during processing:		 * only cb_tail is altered in the interrupt code.		 */		head = cb->cb_head;		if ((n = AUCB_LEN(cb)) > uio->uio_resid)			n = uio->uio_resid;		taildata = AUCB_SIZE - head;		if (n > taildata) {			error = UIOMOVE((caddr_t)cb->cb_data + head,					taildata, UIO_READ, uio);			if (error == 0)				error = UIOMOVE((caddr_t)cb->cb_data,						n - taildata, UIO_READ, uio);		} else			error = UIOMOVE((caddr_t)cb->cb_data + head, n, 					UIO_READ, uio);		if (error)			break;		head = AUCB_MOD(head + n);		cb->cb_head = head;	} while (uio->uio_resid >= blocksize);	return (error);}/* ARGSUSED */intAUDIOWRITE(dev, uio, ioflag){	register struct audio_softc *sc = SOFTC(dev);	register struct aucb *cb = &sc->sc_au.au_wb;	register int n, tail, tailspace, error, first, watermark;	error = 0;	first = 1;	while (uio->uio_resid > 0) {		watermark = sc->sc_au.au_hiwat;		while (AUCB_LEN(cb) > watermark) {#ifndef SUNOS			if (ioflag & IO_NDELAY) {				error = EWOULDBLOCK;				return (error);			}#endif			if ((error = audio_sleep(cb, watermark)) != 0)				return (error);			watermark = sc->sc_au.au_lowat;		}		/*		 * The only value that can change on an interrupt is		 * cb->cb_head.  We only pull that out once to decide		 * how much to write into cb_data; if we lose a race		 * and cb_head changes, we will merely be overly		 * conservative.  For a legitimate time stamp,		 * however, we need to synchronize the accesses to		 * au_stamp and cb_head at a high ipl below.		 */		tail = cb->cb_tail;		if ((n = (AUCB_SIZE - 1) - AUCB_LEN(cb)) > uio->uio_resid) {			n = uio->uio_resid;			if (cb->cb_head == tail &&			    n <= sc->sc_au.au_blksize &&			    sc->sc_au.au_stamp - sc->sc_wseek > 400) {				/*				 * the write is 'small', the buffer is empty				 * and we have been silent for at least 50ms				 * so we might be dealing with an application				 * that writes frames synchronously with				 * reading them.  If so, we need an output				 * backlog to cover scheduling delays or				 * there will be gaps in the sound output.				 * Also take this opportunity to reset the				 * buffer pointers in case we ended up on				 * a bad boundary (odd byte, blksize bytes				 * from end, etc.).				 */				register u_int* ip;				register int muzero = 0x7f7f7f7f;				register int i = splaudio();				cb->cb_head = cb->cb_tail = 0;				splx(i);				tail = sc->sc_au.au_backlog;				ip = (u_int*)cb->cb_data;				for (i = tail >> 2; --i >= 0; )					*ip++ = muzero;			}		}		tailspace = AUCB_SIZE - tail;		if (n > tailspace) {			/* write first part at tail and rest at head */			error = UIOMOVE((caddr_t)cb->cb_data + tail,					tailspace, UIO_WRITE, uio);			if (error == 0)				error = UIOMOVE((caddr_t)cb->cb_data,						n - tailspace, UIO_WRITE, uio);		} else			error = UIOMOVE((caddr_t)cb->cb_data + tail, n, 					UIO_WRITE, uio);		if (error)			break;		tail = AUCB_MOD(tail + n);		if (first) {			register int s = splaudio();			sc->sc_wseek = AUCB_LEN(cb) + sc->sc_au.au_stamp + 1;			/* 			 * To guarantee that a write is contiguous in the			 * sample space, we clear the drop count the first			 * time through.  If we later get drops, we will			 * break out of the loop below, before writing			 * a new frame.			 */			cb->cb_drops = 0;			cb->cb_tail = tail;			splx(s);			first = 0;		} else {			if (cb->cb_drops != 0)				break;			cb->cb_tail = tail;		}	}	return (error);}/* Sun audio compatibility */struct sun_audio_prinfo {	u_int	sample_rate;	u_int	channels;	u_int	precision;	u_int	encoding;	u_int	gain;	u_int	port;	u_int	reserved0[4];	u_int	samples;	u_int	eof;	u_char	pause;	u_char	error;	u_char	waiting;	u_char	reserved1[3];	u_char	open;	u_char	active;};struct sun_audio_info {	struct sun_audio_prinfo play;	struct sun_audio_prinfo record;	u_int monitor_gain;	u_int reserved[4];};#ifndef SUNOS#define SUNAUDIO_GETINFO	_IOR('A', 1, struct sun_audio_info)#define SUNAUDIO_SETINFO	_IOWR('A', 2, struct sun_audio_info)#else#define SUNAUDIO_GETINFO	_IOR(A, 1, struct sun_audio_info)#define SUNAUDIO_SETINFO	_IOWR(A, 2, struct sun_audio_info)#endif/* ARGSUSED */intAUDIOIOCTL(dev, cmd, addr, flag, p){	register struct audio_softc *sc = SOFTC(dev);	int error = 0, s;	switch (cmd) {	case AUDIO_GETMAP:		bcopy((caddr_t)&sc->sc_map, addr, sizeof(sc->sc_map));		break;	case AUDIO_SETMAP:		bcopy(addr, (caddr_t)&sc->sc_map, sizeof(sc->sc_map));		sc->sc_map.mr_mmr2 &= 0x7f;		audio_setmap(sc->sc_au.au_amd, &sc->sc_map);		break;	case AUDIO_FLUSH:		s = splaudio();		AUCB_INIT(&sc->sc_au.au_rb);		AUCB_INIT(&sc->sc_au.au_wb);		sc->sc_au.au_stamp = 0;		splx(s);		sc->sc_wseek = 0;		sc->sc_rseek = 0;		break;	/*	 * Number of read samples dropped.  We don't know where or	 * when they were dropped.	 */	case AUDIO_RERROR:		*(int *)addr = sc->sc_au.au_rb.cb_drops != 0;		break;	/*	 * How many samples will elapse until mike hears the first	 * sample of what we last wrote?	 */	case AUDIO_WSEEK:		s = splaudio();		*(u_long *)addr = sc->sc_wseek - sc->sc_au.au_stamp				  + AUCB_LEN(&sc->sc_au.au_rb);		splx(s);		break;	case AUDIO_SETINFO:		error = audiosetinfo(sc, (struct audio_info *)addr);		break;	case AUDIO_GETINFO:		error = audiogetinfo(sc, (struct audio_info *)addr);		break;	case SUNAUDIO_GETINFO:		error = sunaudiogetinfo(sc, (struct sun_audio_info *)addr);		break;	case SUNAUDIO_SETINFO:		error = sunaudiosetinfo(sc, (struct sun_audio_info *)addr);		break;	case AUDIO_DRAIN:		error = audio_drain(sc);		break;	default:		error = EINVAL;		break;	}	return (error);}/* ARGSUSED */intAUDIOSELECT(dev, rw, p){	register struct audio_softc *sc = SOFTC(dev);	register struct aucb *cb;	register int s = splaudio();	switch (rw) {	case FREAD:		cb = &sc->sc_au.au_rb;		if (AUCB_LEN(cb) >= sc->sc_au.au_blksize) {			splx(s);			return (1);		}		selrecord(p, &sc->sc_rsel);		cb->cb_thresh = sc->sc_au.au_blksize;		break;	case FWRITE:		cb = &sc->sc_au.au_wb;		if (AUCB_LEN(cb) <= sc->sc_au.au_lowat) {			splx(s);			return (1);		}		selrecord(p, &sc->sc_wsel);		cb->cb_thresh = sc->sc_au.au_lowat;		break;	}	splx(s);	return (0);}#ifdef AUDIO_C_HANDLERintaudiohwintr(au0)	void *au0;{#ifdef SUNOS	register struct auio *au = audio_au;#else	register struct auio *au = au0;#endif	register volatile struct amd7930 *amd = au->au_amd;	register struct aucb *cb;	register int h, t, k;	k = amd->ir;		/* clear interrupt */	++au->au_stamp;	/* receive incoming data */	cb = &au->au_rb;	h = cb->cb_head;	t = cb->cb_tail;	k = AUCB_MOD(t + 1);	if (h == k)		cb->cb_drops++;	else if  (cb->cb_pause != 0)		cb->cb_pdrops++;	else {		cb->cb_data[t] = amd->bbrb;		cb->cb_tail = t = k;	}	if (AUCB_MOD(t - h) >= cb->cb_thresh) {		cb->cb_thresh = AUCB_SIZE;		cb->cb_waking = 1;		AUDIO_SET_SWINTR;	}	/* send outgoing data */	cb = &au->au_wb;	h = cb->cb_head;	t = cb->cb_tail;	if (h == t)		cb->cb_drops++;	else if (cb->cb_pause != 0)		cb->cb_pdrops++;	else {		cb->cb_head = h = AUCB_MOD(h + 1);		amd->bbtb = cb->cb_data[h];	}	if (AUCB_MOD(t - h) <= cb->cb_thresh) {		cb->cb_thresh = -1;		cb->cb_waking = 1;		AUDIO_SET_SWINTR;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -