version 1.1, 2010/01/13 10:02:52 |
version 1.2, 2010/04/03 17:40:33 |
|
|
|
|
#include "aparams.h" |
#include "aparams.h" |
#include "aproc.h" |
#include "aproc.h" |
|
#include "abuf.h" |
#include "conf.h" |
#include "conf.h" |
#include "dev.h" |
#include "dev.h" |
#include "file.h" |
#include "file.h" |
|
|
struct siofile { |
struct siofile { |
struct file file; |
struct file file; |
struct sio_hdl *hdl; |
struct sio_hdl *hdl; |
|
unsigned wtickets, wbpf; |
|
unsigned rtickets, rbpf; |
|
unsigned bufsz; |
int started; |
int started; |
}; |
}; |
|
|
|
|
siofile_revents |
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 |
void |
siofile_cb(void *addr, int delta) |
siofile_cb(void *addr, int delta) |
{ |
{ |
|
|
|
|
#ifdef DEBUG |
#ifdef DEBUG |
if (delta < 0 || delta > (60 * RATE_MAX)) { |
if (delta < 0 || delta > (60 * RATE_MAX)) { |
dbg_puts(f->file.name); |
file_dbg(&f->file); |
dbg_puts(": "); |
dbg_puts(": "); |
dbg_puti(delta); |
dbg_puti(delta); |
dbg_puts(": bogus sndio delta"); |
dbg_puts(": bogus sndio delta"); |
dbg_panic(); |
dbg_panic(); |
} |
} |
|
if (debug_level >= 4) { |
|
file_dbg(&f->file); |
|
dbg_puts(": tick, delta = "); |
|
dbg_puti(delta); |
|
dbg_puts("\n"); |
|
} |
#endif |
#endif |
if (delta != 0) { |
if (delta != 0) { |
p = f->file.wproc; |
p = f->file.wproc; |
|
|
if (p && p->ops->ipos) |
if (p && p->ops->ipos) |
p->ops->ipos(p, NULL, delta); |
p->ops->ipos(p, NULL, delta); |
} |
} |
|
f->wtickets += delta * f->wbpf; |
|
f->rtickets += delta * f->rbpf; |
} |
} |
|
|
/* |
/* |
* Open the device. |
* Open the device. |
*/ |
*/ |
struct siofile * |
struct siofile * |
siofile_new(struct fileops *ops, char *path, |
siofile_new(struct fileops *ops, char *path, unsigned mode, |
struct aparams *ipar, struct aparams *opar, |
struct aparams *ipar, struct aparams *opar, |
unsigned *bufsz, unsigned *round) |
unsigned *bufsz, unsigned *round) |
{ |
{ |
struct sio_par par; |
struct sio_par par; |
struct sio_hdl *hdl; |
struct sio_hdl *hdl; |
struct siofile *f; |
struct siofile *f; |
int mode; |
|
|
|
mode = 0; |
|
if (ipar) |
|
mode |= SIO_REC; |
|
if (opar) |
|
mode |= SIO_PLAY; |
|
hdl = sio_open(path, mode, 1); |
hdl = sio_open(path, mode, 1); |
if (hdl == NULL) |
if (hdl == NULL) |
return NULL; |
return NULL; |
sio_initpar(&par); |
sio_initpar(&par); |
if (ipar) { |
if (mode & SIO_REC) { |
par.bits = ipar->bits; |
par.bits = ipar->bits; |
par.bps = ipar->bps; |
par.bps = ipar->bps; |
par.sig = ipar->sig; |
par.sig = ipar->sig; |
|
|
par.msb = opar->msb; |
par.msb = opar->msb; |
par.rate = opar->rate; |
par.rate = opar->rate; |
} |
} |
if (opar) |
if (mode & SIO_PLAY) |
par.pchan = opar->cmax - opar->cmin + 1; |
par.pchan = opar->cmax - opar->cmin + 1; |
par.appbufsz = *bufsz; |
par.appbufsz = *bufsz; |
par.round = *round; |
par.round = *round; |
|
|
goto bad_close; |
goto bad_close; |
if (!sio_getpar(hdl, &par)) |
if (!sio_getpar(hdl, &par)) |
goto bad_close; |
goto bad_close; |
if (ipar) { |
if (mode & SIO_REC) { |
ipar->bits = par.bits; |
ipar->bits = par.bits; |
ipar->bps = par.bps; |
ipar->bps = par.bps; |
ipar->sig = par.sig; |
ipar->sig = par.sig; |
|
|
ipar->rate = par.rate; |
ipar->rate = par.rate; |
ipar->cmax = ipar->cmin + par.rchan - 1; |
ipar->cmax = ipar->cmin + par.rchan - 1; |
} |
} |
if (opar) { |
if (mode & SIO_PLAY) { |
opar->bits = par.bits; |
opar->bits = par.bits; |
opar->bps = par.bps; |
opar->bps = par.bps; |
opar->sig = par.sig; |
opar->sig = par.sig; |
|
|
goto bad_close; |
goto bad_close; |
f->hdl = hdl; |
f->hdl = hdl; |
f->started = 0; |
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); |
sio_onmove(f->hdl, siofile_cb, f); |
return f; |
return f; |
bad_close: |
bad_close: |
|
|
return; |
return; |
} |
} |
f->started = 1; |
f->started = 1; |
|
f->wtickets = f->bufsz * f->wbpf; |
|
f->rtickets = 0; |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 3) { |
if (debug_level >= 3) { |
file_dbg(&f->file); |
file_dbg(&f->file); |
|
|
struct siofile *f = (struct siofile *)file; |
struct siofile *f = (struct siofile *)file; |
unsigned n; |
unsigned 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; |
n = f->started ? sio_read(f->hdl, data, count) : 0; |
if (n == 0) { |
if (n == 0) { |
f->file.state &= ~FILE_ROK; |
f->file.state &= ~FILE_ROK; |
|
|
#endif |
#endif |
} |
} |
return 0; |
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; |
return n; |
|
|
|
|
struct siofile *f = (struct siofile *)file; |
struct siofile *f = (struct siofile *)file; |
unsigned n; |
unsigned 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; |
n = f->started ? sio_write(f->hdl, data, count) : 0; |
if (n == 0) { |
if (n == 0) { |
f->file.state &= ~FILE_WOK; |
f->file.state &= ~FILE_WOK; |
|
|
#endif |
#endif |
} |
} |
return 0; |
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; |
return n; |
} |
} |