OK, turing.

<- leave blank

Wed Nov 23 22:42:36 EST 2022

Return-Path: <9front-bounces@9front.inri.net>
Delivered-To: ori@eigenstate.org
Received: from 9front.inri.net (9front.inri.net [168.235.81.73])
	by mimir.eigenstate.org (OpenSMTPD) with ESMTP id a539c1df
	for <ori@eigenstate.org>;
	Fri, 18 Nov 2022 19:44:41 -0800 (PST)
MIME-Version: 1.0
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: 8bit
Received: from mail-pj1-f41.google.com ([209.85.216.41]) by 9front; Fri Nov 18
22:39:07 -0500 2022
Received: by mail-pj1-f41.google.com with SMTP id
u6-20020a17090a5e4600b0021881a8d264so4430968pji.4
	for <9front@9front.org>; Fri, 18 Nov 2022 19:39:04 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
	d=mforney.org; s=google;
	h=to:subject:date:from:references:in-reply-to:message-id:from:to:cc
	 :subject:date:message-id:reply-to;
	bh=s+LE3VzoGAnzl+i14htIosiCfZtwjaN3PWbbipw0BHc=;
	b=HiVR7A1fmzfZngP9Ej7oE1lDcaAVbHd1jZiMaI+0aLv0RWbAA+Zfjr/p4UEsHBq2eY
	 2w4mhcA6KEdiVuwNq6v6LObinBtqpVjOMZCh4ebI5sMWUIRyN3WKgMdtBvlf+qUHq0Np
	 eLRSuIX1q88QH/6nJU6s3FMskzlis3Q4tbtR8vt4OKVy+c++Q0+FD0i4bmYkOUgQFXbx
	 2BtOcUm+m0PrqEP35Ig2dSw0pGPDgBEiAZnVLBsNln6Pp3xRXwpvyeQxsAackilqcTxU
	 qHDw+3NVX5XJ7QufUVocVd9m53NK4jae1NV2DlsXqhr2WTvRnBj1lGUOo8fSJlV/6jsO
	 fYFw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
	d=1e100.net; s=20210112;
	h=to:subject:date:from:references:in-reply-to:message-id
	 :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to;
	bh=s+LE3VzoGAnzl+i14htIosiCfZtwjaN3PWbbipw0BHc=;
	b=3bV4eIgt13Jw1xArsi9haT1fNC1xuQmvrmZ7d0QCwPSMcivHxwHLkHo9o+pTXyycb7
	 G7CW8Lz5BnccO8R+lXh3C+r1ZlVuczXcp+ARCR2AHQuELpqDY19XvdUHeEaj8QKxEqjr
	 DnZoNqsyvXO3ytwIUbdeL6B6ld4JkVsExandz+2DAf1D67EmJ+/IFcoVBsyf3ARDcsNA
	 xMQ52BRyrIHDa4qvH87q9rfg3hdqteewEZ8adciwslMbTfzNJk73feMpmTNKbuZcWnVA
	 RIOGe3k9NWGjirLkUnkZv2rs6z38/bbx7zXad4lCq4yxomvwEiq9VLW/qM+Vf0M4srEO
	 EN9A==
X-Gm-Message-State: ANoB5pm/qMtavsb1Rmw6a4fVvHiJwIJ1hjw8ptBoBbokfJbUvpA3kQh0
	V9d2gZg92ig5lhwOmj7DqlhuRYnD07bFieB5OxI=
X-Google-Smtp-Source:
AA0mqf7oUdalKIQCJY89GtlPVfJFGKHVzyJ10VIcaXiYaq6hzaB22MNHZxyFfwqLei5P+z0pt8MjUg==
X-Received: by 2002:a17:902:aa0c:b0:180:4030:1c7d with SMTP id
be12-20020a170902aa0c00b0018040301c7dmr2365034plb.99.1668829143650;
	Fri, 18 Nov 2022 19:39:03 -0800 (PST)
Return-Path: <mforney@mforney.org>
Received: from localhost ([2601:647:6400:20b0:cab2:9bff:fe88:d09c])
	by smtp.gmail.com with ESMTPSA id
	c19-20020a631c53000000b00476e77b0f07sm3503215pgm.38.2022.11.18.19.39.02
	for <9front@9front.org>
	(version=TLS1_2 cipher=ECDHE-ECDSA-CHACHA20-POLY1305 bits=256/256);
	Fri, 18 Nov 2022 19:39:02 -0800 (PST)
Message-Id:
<d4cba708842774bcb918ca2bc697298d4f475ac7.1668828454.git.mforney@mforney.org>
In-Reply-To: <cover.1668828454.git.mforney@mforney.org>
References: <cover.1668828454.git.mforney@mforney.org>
From: Michael Forney <mforney@mforney.org>
Date: Fri, 18 Nov 2022 09:21:12 +0000
To: 9front@9front.org
List-ID: <9front.9front.org>
List-Help: <http://lists.9front.org>
X-Glyph: ➈
X-Bullshit: scripting-scale blockchain CSS-oriented factory interface
Subject: [9front] [PATCH 4/5] nusb/audio: enumerate streams through control
interface
Reply-To: 9front@9front.org
Precedence: bulk

USB audio 2.0 splits the sample rate control from the AudioStreaming
alternate settings to a clock entity connected to input/output
terminals associated with the AudioStreaming interfaces.  So, in order
to pair endpoints with their corresponding clock, we must have a
better picture of the audio function topology.

The AudioControl interface tells us which streams are available, so we
can go through each one, determining the possible stream parameters
and locating the associated endpoint.  This will give us the necessary
context to locate the corresponding terminal (and soon, clock).  When
we go to setup input/output endpoints, we now only have to consider
those that we have selected earlier.
---
 sys/src/cmd/nusb/audio/audio.c | 193 ++++++++++++++++++++++++---------
 1 file changed, 139 insertions(+), 54 deletions(-)

diff --git a/sys/src/cmd/nusb/audio/audio.c b/sys/src/cmd/nusb/audio/audio.c
index 09b84b8c48..2cd75f6361 100644
--- a/sys/src/cmd/nusb/audio/audio.c
+++ b/sys/src/cmd/nusb/audio/audio.c
@@ -19,16 +19,21 @@ enum {
 typedef struct Range Range;
 struct Range
 {
- Range *next;
- int min;
- int max;
+ uint min;
+ uint max;
 };

 typedef struct Aconf Aconf;
 struct Aconf
 {
+ Ep *ep;
+ int bits;
+ int bps; /* subslot size (bytes per sample) */
+ int format;
+ int channels;
+ int controls;
	Range *freq;
- int caps;
+ int nfreq;
 };

 int audiodelay = 1764; /* 40 ms */
@@ -39,62 +44,131 @@ int audiores = 16;
 char user[] = "audio";

 Dev *audiodev = nil;
-
+Iface *audiocontrol = nil;
 Ep *audioepin = nil;
 Ep *audioepout = nil;

-void
-parsedescr(Desc *dd)
+Iface*
+findiface(Conf *conf, int class, int subclass, int id)
 {
- Aconf *c;
- Range *f;
- uchar *b;
	int i;
+ Iface *iface;

- if(dd == nil || dd->iface == nil)
- return;
- if(Subclass(dd->iface->csp) != 2)
- return;
+ for(i = 0; i < nelem(conf->iface); i++){
+ iface = conf->iface[i];
+ if(iface == nil || Class(iface->csp) != class || Subclass(iface->csp) !=
subclass)
+ continue;
+ if(id == -1 || iface->id == id)
+ return iface;
+ }
+ return nil;
+}
+
+Desc*
+findacheader(Usbdev *u, Iface *ac)
+{
+ Desc *dd;
+ uchar *b;
+ int i;

- c = dd->iface->aux;
- if(c == nil){
- c = mallocz(sizeof(*c), 1);
- dd->iface->aux = c;
+ for(i = 0; i < nelem(u->ddesc); i++){
+ dd = u->ddesc[i];
+ if(dd == nil || dd->iface != ac || dd->data.bDescriptorType != 0x24)
+ continue;
+ if(dd->data.bLength < 8 || dd->data.bbytes[0] != 1)
+ continue;
+ b = dd->data.bbytes;
+ if(dd->data.bLength == 8+b[5])
+ return dd;
	}
+ return nil;
+}
+
+void
+parseasdesc(Desc *dd, Aconf *c)
+{
+ uchar *b;
+ Range *f;

- b = (uchar*)&dd->data;
- switch(b[1]<<8 | b[2]){
+ b = dd->data.bbytes;
+ switch(dd->data.bDescriptorType<<8 | b[0]){
	case 0x2501: /* CS_ENDPOINT, EP_GENERAL */
- c->caps |= b[3];
+ if(dd->data.bLength != 7)
+ return;
+ c->controls = b[1];
		break;

- case 0x2402: /* CS_INTERFACE, FORMAT_TYPE */
- if(b[4] != audiochan)
- break;
- if(b[6] != audiores)
- break;
+ case 0x2401: /* CS_INTERFACE, AS_GENERAL */
+ if(dd->data.bLength != 7)
+ return;
+ c->format = GET2(&b[3]);
+ break;

- if(b[7] == 0){
- f = mallocz(sizeof(*f), 1);
- f->min = b[8] | b[9]<<8 | b[10]<<16;
- f->max = b[11] | b[12]<<8 | b[13]<<16;
-
- f->next = c->freq;
- c->freq = f;
- } else {
- for(i=0; i<b[7]; i++){
- f = mallocz(sizeof(*f), 1);
- f->min = b[8+3*i] | b[9+3*i]<<8 | b[10+3*i]<<16;
+ case 0x2402: /* CS_INTERFACE, FORMAT_TYPE */
+ if(dd->data.bLength < 8 || b[1] != 1)
+ return;
+ c->channels = b[2];
+ c->bps = b[3];
+ c->bits = b[4];
+ if(b[5] == 0){ /* continuous frequency range */
+ c->nfreq = 1;
+ c->freq = emallocz(sizeof(*f), 1);
+ c->freq->min = b[6] | b[7]<<8 | b[8]<<16;
+ c->freq->max = b[9] | b[10]<<8 | b[11]<<16;
+ }else{ /* discrete sampling frequencies */
+ c->nfreq = b[5];
+ c->freq = emallocz(c->nfreq * sizeof(*f), 1);
+ b += 6;
+ for(f = c->freq; f < c->freq+c->nfreq; f++, b += 3){
+ f->min = b[0] | b[1]<<8 | b[2]<<16;
				f->max = f->min;
-
- f->next = c->freq;
- c->freq = f;
			}
		}
		break;
	}
 }

+void
+parsestream(Dev *d, int id)
+{
+ Iface *as;
+ Desc *dd;
+ Ep *e;
+ Aconf *c;
+ int i;
+
+ /* find AS interface */
+ as = findiface(d->usb->conf[0], Claudio, 2, id);
+
+ /* enumerate through alt.  settings */
+ for(; as != nil; as = as->next){
+ c = emallocz(sizeof(*c), 1);
+ as->aux = c;
+
+ /* find AS endpoint */
+ for(i = 0; i < nelem(as->ep); i++){
+ e = as->ep[i];
+ if(e != nil && e->type == Eiso && (e->attrib>>4 & 3) == Edata){
+ c->ep = e;
+ break;
+ }
+ }
+ if(c->ep == nil){
+ free(c);
+ as->aux = nil;
+ continue;
+ }
+
+ /* parse AS descriptors */
+ for(i = 0; i < nelem(d->usb->ddesc); i++){
+ dd = d->usb->ddesc[i];
+ if(dd == nil || dd->iface != as)
+ continue;
+ parseasdesc(dd, c);
+ }
+ }
+}
+
 Dev*
 setupep(Dev *d, Ep *e, int speed)
 {
@@ -103,12 +177,12 @@ setupep(Dev *d, Ep *e, int speed)
	Range *f;

	for(;e != nil; e = e->next){
- if(e->dir!=dir)
- continue;
		c = e->iface->aux;
- if(c == nil)
+ if(c == nil || e != c->ep || e->dir != dir)
			continue;
- for(f = c->freq; f != nil; f = f->next)
+ if(c->format != 1 || c->bits != audiores || 8*c->bps != audiores ||
c->channels != audiochan)
+ continue;
+ for(f = c->freq; f != c->freq+c->nfreq; f++)
			if(speed >= f->min && speed <= f->max)
				goto Foundaltc;
	}
@@ -119,7 +193,7 @@ Foundaltc:
	if(setalt(d, e->iface) < 0)
		return nil;

- if(c->caps & 1){
+ if(c->controls & 1){
		uchar b[4];

		b[0] = speed;
@@ -207,6 +281,10 @@ main(int argc, char *argv[])
 {
	char buf[32];
	Dev *d, *ed;
+ Desc *dd;
+ Conf *conf;
+ Iface *ac;
+ Aconf *c;
	Ep *e;
	int i;

@@ -226,15 +304,22 @@ main(int argc, char *argv[])
		sysfatal("getdev: %r");
	audiodev = d;

- /* parse descriptors, mark valid altc */
- for(i = 0; i < nelem(d->usb->ddesc); i++)
- parsedescr(d->usb->ddesc[i]);
+ conf = d->usb->conf[0];
+ ac = findiface(conf, Claudio, 1, -1);
+ if(ac == nil)
+ sysfatal("no audio control interface");
+ audiocontrol = ac;
+
+ dd = findacheader(d->usb, ac);
+ if(dd == nil)
+ sysfatal("no audio control header");
+ for(i = 6; i < dd->data.bLength-2; i++)
+ parsestream(d, dd->data.bbytes[i]);
+
	for(i = 0; i < nelem(d->usb->ep); i++){
- e = d->usb->ep[i];
- if(e == nil || e->type != Eiso || e->iface->csp != CSP(Claudio, 2, 0))
- continue;
- for(; e != nil; e = e->next){
- if((e->attrib>>4 & 3) == Edata)
+ for(e = d->usb->ep[i]; e != nil; e = e->next){
+ c = e->iface->aux;
+ if(c != nil && c->ep == e)
				break;
		}
		if(e == nil)
@@ -263,7 +348,7 @@ main(int argc, char *argv[])
		closedev(ed);
	}
	if(audioepout == nil)
- sysfatal("no endpoints found");
+ sysfatal("no output stream found");

	fs.tree = alloctree(user, "usb", DMDIR|0555, nil);
	createfile(fs.tree->root, "volume", user, 0666, nil);
--
2.37.3