[BACK]Return to siofile.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / aucat

File: [local] / src / usr.bin / aucat / Attic / siofile.c (download)

Revision 1.12, Wed Jun 27 06:46:44 2012 UTC (11 years, 10 months ago) by ratchov
Branch: MAIN
CVS Tags: OPENBSD_5_4_BASE, OPENBSD_5_4, OPENBSD_5_3_BASE, OPENBSD_5_3, OPENBSD_5_2_BASE, OPENBSD_5_2
Changes since 1.11: +2 -2 lines

Don't return void expressions in functions returning void. Removes
warnings in clang. From dhill. Thanks!

/*	$OpenBSD: siofile.c,v 1.12 2012/06/27 06:46:44 ratchov Exp $	*/
/*
 * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/time.h>
#include <sys/types.h>

#include <poll.h>
#include <sndio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "aparams.h"
#include "aproc.h"
#include "abuf.h"
#include "conf.h"
#include "dev.h"
#include "file.h"
#include "siofile.h"
#ifdef DEBUG
#include "dbg.h"
#endif

struct siofile {
	struct file file;
	struct sio_hdl *hdl;
	unsigned int wtickets, wbpf;
	unsigned int rtickets, rbpf;
	unsigned int bufsz;
	int started;
	void (*onmove)(void *, int);
	void *arg;
#ifdef DEBUG
	long long wtime, utime;
#endif
};

void siofile_close(struct file *);
unsigned int siofile_read(struct file *, unsigned char *, unsigned int);
unsigned int siofile_write(struct file *, unsigned char *, unsigned int);
void siofile_start(struct file *, void (*)(void *, int), void *);
void siofile_stop(struct file *);
int siofile_nfds(struct file *);
int siofile_pollfd(struct file *, struct pollfd *, int);
int siofile_revents(struct file *, struct pollfd *);

struct fileops siofile_ops = {
	"sio",
	sizeof(struct siofile),
	siofile_close,
	siofile_read,
	siofile_write,
	siofile_start,
	siofile_stop,
	siofile_nfds,
	siofile_pollfd,
	siofile_revents
};

int wsio_out(struct aproc *, struct abuf *);
int rsio_in(struct aproc *, struct abuf *);

struct aproc_ops rsio_ops = {
	"rsio",
	rsio_in,
	rfile_out,
	rfile_eof,
	rfile_hup,
	NULL, /* newin */
	NULL, /* newout */
	aproc_ipos,
	aproc_opos,
	rfile_done
};

struct aproc_ops wsio_ops = {
	"wsio",
	wfile_in,
	wsio_out,
	wfile_eof,
	wfile_hup,
	NULL, /* newin */
	NULL, /* newout */
	aproc_ipos,
	aproc_opos,
	wfile_done
};

struct aproc *
rsio_new(struct file *f)
{
	struct aproc *p;

	p = aproc_new(&rsio_ops, f->name);
	p->u.io.file = f;
	p->u.io.partial = 0;
	f->rproc = p;
	return p;
}

struct aproc *
wsio_new(struct file *f)
{
	struct aproc *p;

	p = aproc_new(&wsio_ops, f->name);
	p->u.io.file = f;
	p->u.io.partial = 0;
	f->wproc = p;
	return p;
}

int
wsio_out(struct aproc *p, struct abuf *obuf)
{
	struct siofile *f = (struct siofile *)p->u.io.file;

	if (f->wtickets == 0) {
#ifdef DEBUG
		if (debug_level >= 4) {
			file_dbg(&f->file);
			dbg_puts(": no more write tickets\n");
		}
#endif
		f->file.state &= ~FILE_WOK;
		return 0;
	}
	return wfile_out(p, obuf);
}

int
rsio_in(struct aproc *p, struct abuf *ibuf)
{
	struct siofile *f = (struct siofile *)p->u.io.file;

	if (f->rtickets == 0) {
#ifdef DEBUG
		if (debug_level >= 4) {
			file_dbg(&f->file);
			dbg_puts(": no more read tickets\n");
		}
#endif
		f->file.state &= ~FILE_ROK;
		return 0;
	}
	return rfile_in(p, ibuf);
}

void
siofile_cb(void *addr, int delta)
{
	struct siofile *f = (struct siofile *)addr;
	struct aproc *p;

#ifdef DEBUG
	if (delta < 0 || delta > (60 * RATE_MAX)) {
		file_dbg(&f->file);
		dbg_puts(": ");
		dbg_puti(delta);
		dbg_puts(": bogus sndio delta");
		dbg_panic();
	}
	if (debug_level >= 4) {
		file_dbg(&f->file);
		dbg_puts(": tick, delta = ");
		dbg_puti(delta);
		dbg_puts(", load = ");
		dbg_puti((file_utime - f->utime) / 1000);
		dbg_puts(" + ");
		dbg_puti((file_wtime - f->wtime) / 1000);
		dbg_puts("\n");
	}
	f->wtime = file_wtime;
	f->utime = file_utime;
#endif
	if (delta != 0) {
		p = f->file.wproc;
		if (p && p->ops->opos)
			p->ops->opos(p, NULL, delta);
		p = f->file.rproc;
		if (p && p->ops->ipos)
			p->ops->ipos(p, NULL, delta);
	}
	if (f->onmove)
		f->onmove(f->arg, delta);
	f->wtickets += delta * f->wbpf;
	f->rtickets += delta * f->rbpf;
}

/*
 * Open the device.
 */
struct siofile *
siofile_new(struct fileops *ops, char *path, unsigned int *rmode,
    struct aparams *ipar, struct aparams *opar,
    unsigned int *bufsz, unsigned int *round)
{
	struct sio_par par;
	struct sio_hdl *hdl;
	struct siofile *f;
	unsigned int mode = *rmode;

	hdl = sio_open(path, mode, 1);
	if (hdl == NULL) {
		if (mode != (SIO_PLAY | SIO_REC))
			return NULL;
		hdl = sio_open(path, SIO_PLAY, 1);
		if (hdl != NULL)
			mode = SIO_PLAY;
		else {
			hdl = sio_open(path, SIO_REC, 1);
			if (hdl != NULL)
				mode = SIO_REC;
			else
				return NULL;
		}
#ifdef DEBUG
		if (debug_level >= 1) {
			dbg_puts("warning, device opened in ");
			dbg_puts(mode == SIO_PLAY ? "play-only" : "rec-only");
			dbg_puts(" mode\n");
		}
#endif
	}

	sio_initpar(&par);
	if (mode & SIO_REC) {
		par.bits = ipar->bits;
		par.bps = ipar->bps;
		par.sig = ipar->sig;
		par.le = ipar->le;
		par.msb = ipar->msb;
		par.rate = ipar->rate;
		par.rchan = ipar->cmax + 1;
	} else {
		par.bits = opar->bits;
		par.bps = opar->bps;
		par.sig = opar->sig;
		par.le = opar->le;
		par.msb = opar->msb;
		par.rate = opar->rate;
	}
	if (mode & SIO_PLAY)
		par.pchan = opar->cmax + 1;
	if (*bufsz)
		par.appbufsz = *bufsz;
	if (*round)
		par.round = *round;
	if (!sio_setpar(hdl, &par))
		goto bad_close;
	if (!sio_getpar(hdl, &par))
		goto bad_close;
	if (mode & SIO_REC) {
		ipar->bits = par.bits;
		ipar->bps = par.bps;
		ipar->sig = par.sig;
		ipar->le = par.le;
		ipar->msb = par.msb;
		ipar->rate = par.rate;
		ipar->cmin = 0;
		ipar->cmax = par.rchan - 1;
	}
	if (mode & SIO_PLAY) {
		opar->bits = par.bits;
		opar->bps = par.bps;
		opar->sig = par.sig;
		opar->le = par.le;
		opar->msb = par.msb;
		opar->rate = par.rate;
		opar->cmin = 0;
		opar->cmax = par.pchan - 1;
	}
	*rmode = mode;
	*bufsz = par.bufsz;
	*round = par.round;
	f = (struct siofile *)file_new(ops, path, sio_nfds(hdl));
	if (f == NULL)
		goto bad_close;
	f->hdl = hdl;
	f->started = 0;
	f->wtickets = 0;
	f->rtickets = 0;
	f->wbpf = par.pchan * par.bps;
	f->rbpf = par.rchan * par.bps;
	f->bufsz = par.bufsz;
	sio_onmove(f->hdl, siofile_cb, f);
	return f;
 bad_close:
	sio_close(hdl);
	return NULL;
}

void
siofile_start(struct file *file, void (*cb)(void *, int), void *arg)
{
	struct siofile *f = (struct siofile *)file;

	if (!sio_start(f->hdl)) {
#ifdef DEBUG
		dbg_puts(f->file.name);
		dbg_puts(": failed to start device\n");
#endif
		file_close(file);
		return;
	}
	f->started = 1;
	f->wtickets = f->bufsz * f->wbpf;
	f->rtickets = 0;
#ifdef DEBUG
	f->wtime = file_wtime;
	f->utime = file_utime;
	if (debug_level >= 3) {
		file_dbg(&f->file);
		dbg_puts(": started\n");
	}
#endif
	f->onmove = cb;
	f->arg = arg;
}

void
siofile_stop(struct file *file)
{
	struct siofile *f = (struct siofile *)file;

	f->started = 0;
	f->onmove = NULL;
	if (!sio_eof(f->hdl) && !sio_stop(f->hdl)) {
#ifdef DEBUG
		dbg_puts(f->file.name);
		dbg_puts(": failed to stop device\n");
#endif
		file_close(file);
		return;
	}
#ifdef DEBUG
	if (debug_level >= 3) {
		file_dbg(&f->file);
		dbg_puts(": stopped\n");
	}
#endif
}

unsigned int
siofile_read(struct file *file, unsigned char *data, unsigned int count)
{
	struct siofile *f = (struct siofile *)file;
	unsigned int n;

#ifdef DEBUG
	if (f->rtickets == 0) {
		file_dbg(&f->file);
		dbg_puts(": called with no read tickets\n");
	}
#endif
	if (count > f->rtickets)
		count = f->rtickets;
	n = f->started ? sio_read(f->hdl, data, count) : 0;
	if (n == 0) {
		f->file.state &= ~FILE_ROK;
		if (sio_eof(f->hdl)) {
#ifdef DEBUG
			dbg_puts(f->file.name);
			dbg_puts(": failed to read from device\n");
#endif
			file_eof(&f->file);
		} else {
#ifdef DEBUG
			if (debug_level >= 4) {
				file_dbg(&f->file);
				dbg_puts(": reading blocked\n");
			}
#endif
		}
		return 0;
	} else {
		f->rtickets -= n;
		if (f->rtickets == 0) {
			f->file.state &= ~FILE_ROK;
#ifdef DEBUG
			if (debug_level >= 4) {
				file_dbg(&f->file);
				dbg_puts(": read tickets exhausted\n");
			}
#endif
		}
	}
	return n;

}

unsigned int
siofile_write(struct file *file, unsigned char *data, unsigned int count)
{
	struct siofile *f = (struct siofile *)file;
	unsigned int n;

#ifdef DEBUG
	if (f->wtickets == 0) {
		file_dbg(&f->file);
		dbg_puts(": called with no write tickets\n");
	}
#endif
	if (count > f->wtickets)
		count = f->wtickets;
	n = f->started ? sio_write(f->hdl, data, count) : 0;
	if (n == 0) {
		f->file.state &= ~FILE_WOK;
		if (sio_eof(f->hdl)) {
#ifdef DEBUG
			dbg_puts(f->file.name);
			dbg_puts(": failed to write on device\n");
#endif
			file_hup(&f->file);
		} else {
#ifdef DEBUG
			if (debug_level >= 4) {
				file_dbg(&f->file);
				dbg_puts(": writing blocked\n");
			}
#endif
		}
		return 0;
	} else {
		f->wtickets -= n;
		if (f->wtickets == 0) {
			f->file.state &= ~FILE_WOK;
#ifdef DEBUG
			if (debug_level >= 4) {
				file_dbg(&f->file);
				dbg_puts(": write tickets exhausted\n");
			}
#endif
		}
	}
	return n;
}

int
siofile_nfds(struct file *file)
{
	return sio_nfds(((struct siofile *)file)->hdl);
}

int
siofile_pollfd(struct file *file, struct pollfd *pfd, int events)
{
	struct siofile *f = (struct siofile *)file;

	if (!f->started)
		events &= ~(POLLIN | POLLOUT);
	return sio_pollfd(((struct siofile *)file)->hdl, pfd, events);
}

int
siofile_revents(struct file *file, struct pollfd *pfd)
{
	return sio_revents(((struct siofile *)file)->hdl, pfd);
}

void
siofile_close(struct file *file)
{
	struct siofile *f = (struct siofile *)file;

	if (f->started)
		siofile_stop(&f->file);
	sio_close(((struct siofile *)file)->hdl);
}