202 lines · 3.4 KB · C
RawDownload
#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"io.h"#include	"../port/error.h"#include	"audio.h" typedef struct Audioprobe Audioprobe;struct Audioprobe {	char *name;	int (*probe)(Audio*);}; enum {	Qdir = 0,	Qaudio,	Qaudioctl,	Qaudiostatus,	Qvolume,	Maxaudioprobes = 8,}; static int naudioprobes;static Audioprobe audioprobes[Maxaudioprobes];static Audio *audiodevs; static Dirtab audiodir[] = {	".",	{Qdir, 0, QTDIR},	0,	DMDIR|0555,	"audio",	{Qaudio},			0,	0666,	"audioctl",	{Qaudioctl},			0,	0666,	"audiostat",	{Qaudiostatus},			0,	0666,	"volume",	{Qvolume},			0,	0666,}; voidaddaudiocard(char *name, int (*probefn)(Audio *)){	Audioprobe *probe;	probe = &audioprobes[naudioprobes++];	probe->name = name;	probe->probe = probefn;} static voidaudioreset(void){	int i, ctlrno = 0;	Audio **pp;	Audioprobe *probe;	pp = &audiodevs;	*pp = malloc(sizeof(Audio));	(*pp)->ctlrno = ctlrno++;	for(i = 0; i < naudioprobes; i++){		probe = &audioprobes[i];		(*pp)->name = probe->name;		while(!probe->probe(*pp)){			pp = &(*pp)->next;			*pp = malloc(sizeof(Audio));			(*pp)->ctlrno = ctlrno++;		}	}	free(*pp);	*pp = nil;} static Chan*audioattach(char *spec){	Chan *c;	Audio *p;	int i;	if(spec != nil && *spec != '\0')		i = strtol(spec, 0, 10);	else		i = 0;	for(p = audiodevs; p; p = p->next)		if(i-- == 0)			break;	if(p == nil)		error(Enodev);	c = devattach('A', spec);	c->qid.path = Qdir;	c->aux = p;	if(p->attach)		p->attach(p);	return c;} static longaudioread(Chan *c, void *a, long n, vlong off){	Audio *adev;	long (*fn)(Audio *, void *, long, vlong);	adev = c->aux;	switch((ulong)c->qid.path){	default:		error("audio bugger (rd)");	case Qaudioctl:		fn = adev->ctl;		break;	case Qdir:		if(adev->buffered)			audiodir[Qaudio].length = adev->buffered(adev);		return devdirread(c, a, n, audiodir, nelem(audiodir), devgen);	case Qaudio:		fn = adev->read;		break;	case Qaudiostatus:		fn = adev->status;		break;	case Qvolume:		fn = adev->volread;		break;	}	if(fn == nil)		error("not implemented");	return fn(adev, a, n, off);} static longaudiowrite(Chan *c, void *a, long n, vlong off){	Audio *adev;	long (*fn)(Audio *, void *, long, vlong);	adev = c->aux;	switch((ulong)c->qid.path){	default:		error("audio bugger (wr)");	case Qaudio:		fn = adev->write;		break;	case Qaudioctl:		fn = adev->ctl;		break;	case Qvolume:		fn = adev->volwrite;		break;	}	if(fn == nil)		error("not implemented");	return fn(adev, a, n, off);} static voidaudioclose(Chan *c){	Audio *adev;	adev = c->aux;	switch((ulong)c->qid.path){	default:		return;	case Qaudio:		if(adev->close == nil)			return;		adev->close(adev);		return;	}} static Walkqid*audiowalk(Chan *c, Chan *nc, char **name, int nname){	return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen);} static intaudiostat(Chan *c, uchar *dp, int n){	Audio *adev;	adev = c->aux;	if(adev->buffered && (ulong)c->qid.path == Qaudio)		audiodir[Qaudio].length = adev->buffered(adev);	return devstat(c, dp, n, audiodir, nelem(audiodir), devgen);} static Chan*audioopen(Chan *c, int omode){	return devopen(c, omode, audiodir, nelem(audiodir), devgen);} Dev audiodevtab = {	'A',	"audio",	audioreset,	devinit,	devshutdown,	audioattach,	audiowalk,	audiostat,	audioopen,	devcreate,	audioclose,	audioread,	devbread,	audiowrite,	devbwrite,	devremove,	devwstat,};