/*	
 *	clipaudi.c
 *
 *	USB Audio Device
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2014 Naoyuki Sawa
 *
 *	* Sun Sep 21 23:12:43 JST 2014 Naoyuki Sawa
 *	- 1st リリース。
 *	* Tue Sep 23 03:01:15 JST 2014 Naoyuki Sawa
 *	- Audio_Write_sub()をアセンブラ化しました。
 *	- Audio_ep2_txdone()をアセンブラ化しました。
 */
#include "clip.h"

/****************************************************************************
 *	開発メモ
 ****************************************************************************/
//■既知の問題点
//△Audio_Start()を実行して、Windows7がデバイスを認識した後、音量アイコンを右クリック⇒録音デバイス⇒P/ECE USB device⇒プロパティ⇒聴く⇒「このデバイスを聴く」をOnにしないと鳴りません。これは、Windows7の仕様です。
//△「このデバイスを聴く」をOnにしした後、「Operational Alternate Setting 1」に切替わるまでに数秒間かかり、それまでは音が鳴りません。これは、Windows7の仕様だと思います。
//×「このデバイスを聴く」をOnにしたまま、デバイスを停止〜再開すると、Onのまま維持されているにもかかわらず、音が鳴らないことがある。「このデバイスを聴く」をOn⇒Off⇒Onするか、プロパティを再設定すると鳴るようです。
//×「このデバイスを聴く」をOnにしたまま、デバイスを停止〜再開して、Operational Alternate Setting 1」に切替わった後、数秒間音が鳴らず、そのまま待っていると鳴り始めることが、よくあります。
//×InputTerminalDescriptor.wTerminalTypeを「マイク」にすると、「レベル」を下げても音量が大きいままになることがありました。
/****************************************************************************
 *	グローバル変数
 ****************************************************************************/
ST_Audio* pAudio;
/****************************************************************************
 *	ローカル関数宣言
 ****************************************************************************/
/*static*/ void Audio_Write_sub(const int16_t buf[/*len*/], int len);
static void get_descriptor(const DEVICE_REQUEST* req, const unsigned char* dat, int len);
static void set_configuration(const DEVICE_REQUEST* req, const unsigned char* dat, int len);
static void set_interface(const DEVICE_REQUEST* req, const unsigned char* dat, int len);
/*static*/ void Audio_ep2_txdone();
/****************************************************************************
 *	USBフック情報
 ****************************************************************************/
static const USBINF usb_inf = {
	/* USBC mode */
	mode:			D12_ENDP_ISOIN,
	/* USBC raw event */
	ep2_txdone:		Audio_ep2_txdone,
	/* Device request */
	get_descriptor:		get_descriptor,
	set_configuration:	set_configuration,
	set_interface:		set_interface,
};
/****************************************************************************
 *	ディスクリプタ
 ****************************************************************************/
//■参照資料
//│「Universal Serial Bus Device Class Definition for Audio Devices Release 1.0 March 18, 1998」(audio10.pdf)
//│Appendix B. Example 1: USB Microphone (Informative)
/*--------------------------------------------------------------------------*/
//□B.3.1 Device Descriptor
static const DEVICE_DESCRIPTOR DeviceDescriptor = {
	bLength:		sizeof(DEVICE_DESCRIPTOR),		//Size of this descriptor, in bytes.
	bDescriptorType:	DEVICE_DESCRIPTOR_TYPE,			//DEVICE descriptor.
	bcdUSB:			0x0110,					//1.00 - current revision of USB specification.						⇒参照資料の例は1.00となっているが、P/ECEは1.10準拠なので1.10とした。
//不要	bDeviceClass:		0x00,					//Device defined at Interface level.
//不要	bDeviceSubClass:	0x00,					//Unused.
//不要	bDeviceProtocol:	0x00,					//Unused.
	bMaxPacketSize0:	EP0_PACKET_SIZE,			//8 bytes.										⇒参照資料の例は8 bytesとなってるが、P/ECEのハードウェアは16 bytes。
	idVendor:		PCE_VENDOR_ID,				//Vendor ID.
	idProduct:		AUDIO_PRODUCT_ID,			//Product ID.
	bcdDevice:		0x0001,					//Device Release Code.
	iManufacture:		0x01,					//Index to string descriptor that contains the string <Your Name> in Unicode.
	iProduct:		0x02,					//Index to string descriptor that contains the string <Your Product Name> in Unicode.
//不要	iSerialNumber:		0x00,					//Unused.
	bNumConfigurations:	0x01,					//One configuration.
};
/*--------------------------------------------------------------------------*/
//□B.3.2 Configuration Descriptor
static const CONFIGURATION_DESCRIPTOR ConfigurationDescriptor = {
	bLength:		sizeof(CONFIGURATION_DESCRIPTOR),	//Size of this descriptor, in bytes.
	bDescriptorType:	CONFIGURATION_DESCRIPTOR_TYPE,		//CONFIGURATION descriptor.
//	wTotalLength:		?,					//Length of the total configuration block, including this descriptor, in bytes.		⇒get_descriptor()で送出時に設定する。
	bNumInterfaces:		0x02,					//Two interfaces.
	bConfigurationValue:	0x01,					//ID of this configuration.
//不要	iConfiguration:		0x00,					//Unused.
	bmAttributes:		0x80,	/* Bus-powered */		//Bus Powered device, not Self Powered, no Remote wakeup capability.
	MaxPower:		100/2,	/* 100[mA](仮) */		//20 mA Max. power consumption.								⇒参照資料の例は20 mA Maxとなってるが、P/ECEの消費電流はもっと多いので、USB規格上限の100 mA Maxとする。
};
//□B.3.3 AudioControl Interface Descriptor
//□B.3.3.1 Standard AC Interface Descriptor
static const INTERFACE_DESCRIPTOR StandardACInterfaceDescriptor = {
	bLength:		sizeof(INTERFACE_DESCRIPTOR),		//Size of this descriptor, in bytes.
	bDescriptorType:	INTERFACE_DESCRIPTOR_TYPE,		//INTERFACE descriptor.
//不要	bInterfaceNumber:	0x00,					//Index of this interface.
//不要	bAlternateSetting:	0x00,					//Index of this setting.
//不要	bNumEndpoints:		0x00,					//0 endpoints.
	bInterfaceClass:	0x01,					//AUDIO.
	bInterfaceSubClass:	0x01,					//AUDIO_CONTROL.
//不要	bInterfaceProtocol:	0x00,					//Unused.
//不要	iInterface:		0x00,					//Unused.
};
//□B.3.3.2 Class-specific AC Interface Descriptor
static const uint8_t ClassSpecificACInterfaceDescriptor[] = {
	0x09,								//bLength		Size of this descriptor, in bytes.
	INTERFACE_DESCRIPTOR_TYPE|(1/*Class*/<<5),			//bDescriptorType	CS_INTERFACE.
	0x01,								//bDescriptorSubtype	HEADER subtype.
	USB_UINT16(0x0100),						//bcdADC		Revision of class specification - 1.0
	USB_UINT16(0x001E),						//wTotalLength		Total size of class specific descriptors.			=(ClassSpecificACInterfaceDescriptor+InputTerminalDescriptor+OutputTerminalDescriptor)
	0x01,								//bInCollection		Number of streaming interfaces.
	0x01,								//baInterfaceNr(1)	AudioStreaming interface 1 belongs to this AudioControl interface.
};
//□B.3.3.3 Input Terminal Descriptor
static const uint8_t InputTerminalDescriptor[] = {
	0x0C,								//bLength		Size of this descriptor, in bytes.
	INTERFACE_DESCRIPTOR_TYPE|(1/*Class*/<<5),			//bDescriptorType	CS_INTERFACE.
	0x02,								//bDescriptorSubtype	INPUT_TERMINAL subtype.
	0x01,								//bTerminalID		ID of this Input Terminal.
//{{どれか一つを選択する事
	USB_UINT16(0x0200),						//wTerminalType		Terminal is Input Undefined.					⇒Windows7のサウンド設定で「内蔵AUXジャック」と認識される。
//	USB_UINT16(0x0201),						//wTerminalType		Terminal is Microphone.						⇒Windows7のサウンド設定で「マイク」と認識される。
//	USB_UINT16(0x0713),						//wTerminalType		Terminal is Synthesizer.					⇒Windows7のサウンド設定で「シンセサイザー」と認識される。
//}}どれか一つを選択する事
	0x00,								//bAssocTerminal	No association.
	0x01,								//bNrChannels		One channel.
	USB_UINT16(0x0000),						//wChannelConfig	Mono sets no position bits.
	0x00,								//iChannelNames		Unused.
	0x00,								//iTerminal		Unused.
};
//□B.3.3.4 Output Terminal Descriptor
static const uint8_t OutputTerminalDescriptor[] = {
	0x09,								//bLength		Size of this descriptor, in bytes.
	INTERFACE_DESCRIPTOR_TYPE|(1/*Class*/<<5),			//bDescriptorType	CS_INTERFACE.
	0x03,								//bDescriptorSubtype	OUTPUT_TERMINAL subtype.
	0x02,								//bTerminalID		ID of this Output Terminal.
	USB_UINT16(0x0101),						//wTerminalType		USB Streaming.
	0x00,								//bAssocTerminal	Unused.
	0x01,								//bSourceID		From Input Terminal.
	0x00,								//iTerminal		Unused.
};
//□B.3.4 AudioStreaming Interface Descriptor
//□B.3.4.1 Zero-bandwidth Alternate Setting 0
//□B.3.4.1.1.1 Standard AS Interface Descriptor
static const INTERFACE_DESCRIPTOR StandardASInterfaceDescriptor0 = {
	bLength:		sizeof(INTERFACE_DESCRIPTOR),		//Size of this descriptor, in bytes.
	bDescriptorType:	INTERFACE_DESCRIPTOR_TYPE,		//INTERFACE descriptor.
	bInterfaceNumber:	0x01,					//Index of this interface.
//不要	bAlternateSetting:	0x00,					//Index of this alternate setting.
//不要	bNumEndpoints:		0x00,					//0 endpoints.
	bInterfaceClass:	0x01,					//AUDIO.
	bInterfaceSubClass:	0x02,					//AUDIO_STREAMING.
//不要	bInterfaceProtocol:	0x00,					//Unused.
//不要	iInterface:		0x00,					//Unused.
};
//□B.3.4.2 Operational Alternate Setting 1
//□B.3.4.2.1.1 Standard AS Interface Descriptor
static const INTERFACE_DESCRIPTOR StandardASInterfaceDescriptor1 = {
	bLength:		sizeof(INTERFACE_DESCRIPTOR),		//Size of this descriptor, in bytes.
	bDescriptorType:	INTERFACE_DESCRIPTOR_TYPE,		//INTERFACE descriptor.
	bInterfaceNumber:	0x01,					//Index of this interface.
	bAlternateSetting:	0x01,					//Index of this alternate setting.
	bNumEndpoints:		0x01,					//One endpoint.
	bInterfaceClass:	0x01,					//AUDIO.
	bInterfaceSubClass:	0x02,					//AUDIO_STREAMING.
//不要	bInterfaceProtocol:	0x00,					//Unused.
//不要	iInterface:		0x00,					//Unused.
};
//□B.3.4.2.1.2 Class-specific AS General Interface Descriptor
static const uint8_t ClassSpecificASGeneralInterfaceDescriptor[] = {
	0x07,								//bLength		Size of this descriptor, in bytes.
	INTERFACE_DESCRIPTOR_TYPE|(1/*Class*/<<5),			//bDescriptorType	CS_INTERFACE descriptor.
	0x01,								//bDescriptorSubtype	GENERAL subtype.
	0x02,								//bTerminalLink		Unit ID of the Output Terminal.
	0x01,								//bDelay		Interface delay.
	USB_UINT16(0x0001),						//wFormatTag		PCM Format.
};
//□B.3.4.2.1.3 Type I Format Type Descriptor
static const uint8_t TypeIFormatTypeDescriptor[] = {
	0x0B,								//bLength		Size of this descriptor, in bytes.
	INTERFACE_DESCRIPTOR_TYPE|(1/*Class*/<<5),			//bDescriptorType	CS_INTERFACE descriptor.
	0x02,								//bDescriptorSubtype	FORMAT_TYPE subtype.
	0x01,								//bFormatType		FORMAT_TYPE_I.
	0x01,								//bNrChannels		One channel.
	0x02,								//bSubFrameSize		Two bytes per audio subframe.
	0x10,								//bBitResolution	16 bits per sample.
	0x01,								//bSamFreqType		One frequency supported.
	USB_UINT24(SPEAKER_FREQUENCY),					//tSamFreq		8000Hz.								⇒参照資料の例は8000Hzとなってるが、P/ECEのハードウェアは16000Hz。
};
//□B.3.4.2.1.4 Standard Endpoint Descriptor
//{{2014/09/21変更:bRefresh,bSynchAddressは無くても動作するようなので、バイト列ではなくENDPOINT_DESCRIPTORとして定義することにした。
//static const uint8_t StandardEndpointDescriptor[] = {
//	0x09,								//bLength		Size of this descriptor, in bytes.
//	ENDPOINT_DESCRIPTOR_TYPE,					//bDescriptorType	ENDPOINT descriptor.
//	0x82,								//bEndpointAddress	IN Endpoint 1.							⇒参照資料の例はIN Endpoint 1となってるが、P/ECEのハードウェアはIN Endpoint 2。
//	0x01,								//bmAttributes		Isochronous, not shared.
//	USB_UINT16(EP2_ISOIN_PACKET_SIZE),				//wMaxPacketSize	16 bytes per packet.						⇒参照資料の例は16 bytesとなってるが、P/ECEのハードウェアは128 bytes。
//	0x01,								//bInterval		One packet per frame.
//	0x00,								//bRefresh		Unused.								┬Audio Class特有(?)
//	0x00,								//bSynchAddress		Unused.								┘ENDPOINT_DESCRIPTORにはこれらのフィールドが無いので、ENDPOINT_DESCRIPTORではなくバイト配列として定義する。
//};
//↓2014/09/21変更:bRefresh,bSynchAddressは無くても動作するようなので、バイト列ではなくENDPOINT_DESCRIPTORとして定義することにした。
static const ENDPOINT_DESCRIPTOR StandardEndpointDescriptor = {
	bLength:		sizeof(ENDPOINT_DESCRIPTOR),		//bLength		Size of this descriptor, in bytes.
	bDescriptorType:	ENDPOINT_DESCRIPTOR_TYPE,		//bDescriptorType	ENDPOINT descriptor.
	bEndpointAddress:	0x82,					//bEndpointAddress	IN Endpoint 1.							⇒参照資料の例はIN Endpoint 1となってるが、P/ECEのハードウェアはIN Endpoint 2。
	bmAttributes:		0x01,					//bmAttributes		Isochronous, not shared.
	wMaxPacketSize:		EP2_ISOIN_PACKET_SIZE,			//wMaxPacketSize	16 bytes per packet.						⇒参照資料の例は16 bytesとなってるが、P/ECEのハードウェアは128 bytes。
	bInterval:		0x01,					//bInterval		One packet per frame.
//無い	bRefresh:		0x00,					//bRefresh		Unused.								┬Audio Class特有(?)
//無い	bSynchAddress:		0x00,					//bSynchAddress		Unused.								┘ENDPOINT_DESCRIPTORにはこれらのフィールドが無いので、ENDPOINT_DESCRIPTORではなくバイト配列として定義する。
};
//}}2014/09/21変更:bRefresh,bSynchAddressは無くても動作するようなので、バイト列ではなくENDPOINT_DESCRIPTORとして定義することにした。
//□B.3.4.2.1.5 Class-specific Isochronous Audio Data Endpoint Descriptor
static const uint8_t ClassSpecificIsochronousAudioDataEndpointDescriptor[] = {
	0x07,								//bLength		Size of this descriptor, in bytes.
	ENDPOINT_DESCRIPTOR_TYPE|(1/*Class*/<<5),			//bDescriptorType	CS_ENDPOINT descriptor
	0x01,								//bDescriptorSubtype	GENERAL subtype.
	0x00,								//bmAttributes		No sampling frequency control, no pitch control, no packet padding.
	0x00,								//bLockDelayUnits	Unused.
	USB_UINT16(0x0000),						//wLockDelay		Unused.
};
/*--------------------------------------------------------------------------*/
//□B.3.5 String Descriptors
static const char* const StringDescriptors[] = {
//	   ++-- 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30
//	   ||
//	"\x??\3_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0"
	"\x04\3\x09\x04",						// 0: wLANGID = 0x0409 English (United States)
	"\x16\3P\0i\0e\0c\0e\0 \0L\0a\0b\0.\0",				// 1: iManufacture   = "Piece Lab."
	"\x22\3P\0/\0E\0C\0E\0 \0U\0S\0B\0 \0d\0e\0v\0i\0c\0e\0",	// 2: iProduct       = "P/ECE USB device"
};
/****************************************************************************
 *	
 ****************************************************************************/
void Audio_Start(int Cap) {
	/* 確実に終了しておく。 */
	Audio_Stop();
	/* バッファ容量が指定されていなければ、既定のバッファ容量を用いる。
	 * 既定のバッファ容量は、サウンド処理の一般的なBLKSの二個分とした。 */
	if(!Cap) { Cap = 320 * 2; }
	/* 構造体メモリを確保する。 */
	pAudio = calloc(sizeof(ST_Audio) + sizeof(int16_t) * Cap, 1);
	if(!pAudio) { DIE(); }	//メモリ不足
	/* バッファ容量を格納する。 */
	pAudio->Cap = Cap;
	/* USBのフックを開始する。 */
	usb_start(&usb_inf);
}
/*--------------------------------------------------------------------------*/
void Audio_Stop() {
	/* USBのフックを確実に終了する。 */
	usb_stop();
	/* 構造体メモリを確実に開放する。 */
	free(pAudio);
	pAudio = NULL;
}
/*--------------------------------------------------------------------------*/
void Audio_Write(const int16_t buf[/*len*/], int len) {
	if(!pAudio) { DIE(); }	//未初期化
ENTER_CS;
	Audio_Write_sub(buf, len);
LEAVE_CS;
}
/*--------------------------------------------------------------------------*/
#ifndef PIECE
/*static*/ void Audio_Write_sub(const int16_t buf[/*len*/], int len) {
	int rd_pos = pAudio->Pos;	//読み出し位置(高速化のためにローカル変数へ取り出す)
	int rd_len = pAudio->Len;	//有効データ長(高速化のためにローカル変数へ取り出す)
	int wr_pos = rd_pos + rd_len;	//書き込み位置
	if(wr_pos >= pAudio->Cap) { wr_pos -= pAudio->Cap; }		//書き込み位置の折り返しを考慮
	while(len--) {							//書き込みデータが残っていれば…
		pAudio->Buf[wr_pos++] = *buf++;				//書き込む
		if(wr_pos == pAudio->Cap) { wr_pos = 0; }		//書き込み位置が終端に達したら、折り返す
		if(rd_len <  pAudio->Cap) {				//バッファが既にフルでなければ…
			rd_len++;					//有効データ長を増やす
		} else {						//バッファが既にフルだったらば…
			rd_pos++;					//上書した有効データを破棄する
			if(rd_pos == pAudio->Cap) { rd_pos = 0; }	//読み出し位置が終端に達したら、折り返す
		}
	}
	pAudio->Pos = rd_pos;		//読み出し位置(構造体へ書き戻す)
	pAudio->Len = rd_len;		//有効データ長(構造体へ書き戻す)
	Audio_ep2_txdone();		//送信処理を行う。書き込みデータが無かった場合に呼び出しても安全である。
}
#else /*PIECE*/
/*static*/ void Audio_Write_sub(const int16_t buf[/*len*/], int len);
asm("
		.code
		.align		1
Audio_Write_sub:
		;//%r12 := buf
		;//%r13 := len
		xld.w		%r14, [pAudio]		;//%r14 :=          pAudio
		add		%r14, 2			;//%r14 :=         &pAudio->Pos				!INTERLOCK!
		ld.w		%r15, %r14		;//%r15 :=         &pAudio->Pos
		ld.uh		%r4, [%r14]+		;//%r4  := rd_pos = pAudio->Pos
		ld.uh		%r5, [%r14]+		;//%r5  := rd_len = pAudio->Len
		ld.uh		%r6, [%r14]+		;//%r6  := Cap    = pAudio->Cap, %r14 := pAudio->Buf
		ld.w		%r7, %r4		;//%r7  :=          rd_pos
		add		%r7, %r5		;//%r7  := wr_pos = rd_pos + rd_len
		sub		%r7, %r6		;//%r7  := wr_pos -= Cap						┐
		jruge		2			;//if(wr_pos < 0) {							├「if(wr_pos >= Cap) { wr_pos -= Cap }」に相当。
		 add		%r7, %r6		;//  %r7  := wr_pos += Cap }						┘
		add		%r14, %r7		;//%r14 := dst = pAudio->Buf + wr_pos * sizeof(int16_t)
		add		%r14, %r7		;//
		sub		%r4, %r6		;//%r4  := (rd_pos-Cap)							高速化の工夫。rd_posを0→Capに変化するよりも、(rd_pos-Cap)を(-Cap)→0に変化する方が、比較命令が少なくて済む。
		jp.d		Audio_Write_sub_L20	;//goto L20
		sub		%r7, %r6		;//%r7  := (wr_pos-Cap)					*delay*		高速化の工夫。wr_posを0→Capに変化するよりも、(wr_pos-Cap)を(-Cap)→0に変化する方が、比較命令が少なくて済む。
		;//-------------------------------------;//
		;//%r4  := (rd_pos-Cap)
		;//%r5  := rd_len
		;//%r6  := Cap
		;//%r7  := (wr_pos-Cap)
		;//%r12 := buf
		;//%r13 := len
		;//%r14 := dst
		;//%r15 := &pAudio->Pos
Audio_Write_sub_L10:
		ld.h		%r9, [%r12]+		;//*dst++ = *buf++
		ld.h		[%r14]+, %r9		;//
;//		add		%r7, 1			;//%r7  := (wr_pos-Cap)++	────────┐
		jrne		4			;//if((wr_pos-Cap) == 0) {			│
		 sub		%r7, %r6		;//  %r7  := (wr_pos-Cap) -= Cap		│
		 sub		%r14, %r6		;//  %r14 := dst -= Cap * sizeof(int16_t)	│
		 sub		%r14, %r6		;//						│
		cmp		%r5, %r6		;//%psr(C) :=        ((rd_len < Cap) ? 1 : 0)	│
		jrult.d		5			;//if(rd_len >= Cap) {				│
		 adc		%r5, %r8		;//%r5  := rd_len += ((rd_len < Cap) ? 1 : 0)	│	*delay*		高速化の工夫。「jrult.d;add %r5,1;sub %r5,1」で相殺するよりも、一命令少なくて済む。
		 add		%r4, 1			;//  %r4  := (rd_pos-Cap)++			│
		 jrne		2			;//  if((rd_pos-Cap) == 0) {			│
		  sub		%r4, %r6		;//    %r4  := (rd_pos-Cap) -= Cap }		│
Audio_Write_sub_L20:					;//						│
		sub		%r13, 1			;//%r13 := len--				│
		jruge.d		Audio_Write_sub_L10	;//if(len >= 0) { goto L10 }			│
		add		%r7, 1			;//%r7  := (wr_pos-Cap)++	←───────┘	*delay*		最後のループを抜ける時に%r7が1回多く増えてしまうが、この下で%r7を参照していないので問題無い。
		;//-------------------------------------;//
		;//%r4  := (rd_pos-Cap)
		;//%r5  := rd_len
		;//%r15 := &pAudio->Pos
		add		%r4, %r6		;//%r4  := rd_pos
		ld.h		[%r15]+, %r4		;//pAudio->Pos = rd_pos
		ld.h		[%r15]+, %r5		;//pAudio->Len = rd_len
		xjp		Audio_ep2_txdone	;//Audio_ep2_txdone()
");
#endif /*PIECE*/
/****************************************************************************
 *	
 ****************************************************************************/
static void get_descriptor(const DEVICE_REQUEST* req, const unsigned char* dat, int len) {
	static uint8_t* buf;
	       uint8_t* ptr;
	       int type, index;
	buf   = realloc(buf, 0);	//必須ではないがメモリ節約のために、デバイスリクエスト開始時に前回のバッファを開放することにした。本当はデバイスリクエスト完了時にバッファを開放するのが良いのだが、現在のclipusb.cの実装ではデバイスリクエスト完了時のコールバックが無い。代替手段ではあるが、実際のところCONFIGURATION_DESCRIPTOR_TYPE⇒STRING_DESCRIPTOR_TYPEの順になり、バッファが開放された状態で動作しメモリ節約できるだろう。もしそうならなかったとしても、メモリリークではないので問題無い。
	type  = HIBYTE(req->wValue);
	index = LOBYTE(req->wValue);
	switch(type) {
	case DEVICE_DESCRIPTOR_TYPE:
		usb_ep0_tx(&DeviceDescriptor, sizeof DeviceDescriptor);
		return;
	case CONFIGURATION_DESCRIPTOR_TYPE:
		if(index == 0) {
			len  = sizeof ConfigurationDescriptor;
			len += sizeof StandardACInterfaceDescriptor;
			len += sizeof ClassSpecificACInterfaceDescriptor;
			len += sizeof InputTerminalDescriptor;
			len += sizeof OutputTerminalDescriptor;
			len += sizeof StandardASInterfaceDescriptor0;
			len += sizeof StandardASInterfaceDescriptor1;
			len += sizeof ClassSpecificASGeneralInterfaceDescriptor;
			len += sizeof TypeIFormatTypeDescriptor;
			len += sizeof StandardEndpointDescriptor;
			len += sizeof ClassSpecificIsochronousAudioDataEndpointDescriptor;
			buf = realloc(buf, len);
			if(!buf) { DIE(); }
			ptr = memcpy(buf, &ConfigurationDescriptor                             ,sizeof ConfigurationDescriptor                            ) + sizeof ConfigurationDescriptor;
			ptr = memcpy(ptr, &StandardACInterfaceDescriptor                       ,sizeof StandardACInterfaceDescriptor                      ) + sizeof StandardACInterfaceDescriptor;
			ptr = memcpy(ptr, &ClassSpecificACInterfaceDescriptor                  ,sizeof ClassSpecificACInterfaceDescriptor                 ) + sizeof ClassSpecificACInterfaceDescriptor;
			ptr = memcpy(ptr, &InputTerminalDescriptor                             ,sizeof InputTerminalDescriptor                            ) + sizeof InputTerminalDescriptor;
			ptr = memcpy(ptr, &OutputTerminalDescriptor                            ,sizeof OutputTerminalDescriptor                           ) + sizeof OutputTerminalDescriptor;
			ptr = memcpy(ptr, &StandardASInterfaceDescriptor0                      ,sizeof StandardASInterfaceDescriptor0                     ) + sizeof StandardASInterfaceDescriptor0;
			ptr = memcpy(ptr, &StandardASInterfaceDescriptor1                      ,sizeof StandardASInterfaceDescriptor1                     ) + sizeof StandardASInterfaceDescriptor1;
			ptr = memcpy(ptr, &ClassSpecificASGeneralInterfaceDescriptor           ,sizeof ClassSpecificASGeneralInterfaceDescriptor          ) + sizeof ClassSpecificASGeneralInterfaceDescriptor;
			ptr = memcpy(ptr, &TypeIFormatTypeDescriptor                           ,sizeof TypeIFormatTypeDescriptor                          ) + sizeof TypeIFormatTypeDescriptor;
			ptr = memcpy(ptr, &StandardEndpointDescriptor                          ,sizeof StandardEndpointDescriptor                         ) + sizeof StandardEndpointDescriptor;
			      memcpy(ptr, &ClassSpecificIsochronousAudioDataEndpointDescriptor ,sizeof ClassSpecificIsochronousAudioDataEndpointDescriptor);
			((CONFIGURATION_DESCRIPTOR*)buf)->wTotalLength = len;
			usb_ep0_tx(buf, len);
			return;
		}
		break;
	case STRING_DESCRIPTOR_TYPE:
		if(index < ARRAY_SIZE(StringDescriptors)) {
			usb_ep0_tx(StringDescriptors[index], StringDescriptors[index][0]);
			return;
		}
		break;
	}
	usb_ep0_stall(); /* 未対応 */
}
/*--------------------------------------------------------------------------*/
static void set_configuration(const DEVICE_REQUEST* req, const unsigned char* dat, int len) {
	D12_SetEndpointEnable(req->wValue == 1);		/* bConfigurationValue */
	usb_ep0_tx(NULL, 0); /* ACK */
}
/*--------------------------------------------------------------------------*/
static void set_interface(const DEVICE_REQUEST* req, const unsigned char* dat, int len) {
	if(req->wIndex == 1) {					/* bInterfaceNumber */
		pAudio->bAlternateSetting = req->wValue;	/* bAlternateSetting */
		pAudio->Len = 0;	//必須ではないが、「Zero-bandwidth Alternate Setting 0」⇔「Operational Alternate Setting 1」の切り替え時に、バッファをフラッシュすることにした。
	}
	usb_ep0_tx(NULL, 0); /* ACK */
}
/*--------------------------------------------------------------------------*/
#ifndef PIECE
/*static*/ void Audio_ep2_txdone() {
	if(pAudio->bAlternateSetting) {		//「Operational Alternate Setting 1」ならば…
		int rd_pos = pAudio->Pos;	//読み出し位置(高速化のためにローカル変数へ取り出す)
		int rd_len = pAudio->Len;	//有効データ長(高速化のためにローカル変数へ取り出す)
		while(rd_len) {										//有効データ長が残っていれば…
			int16_t buf[EP2_ISOIN_PACKET_SIZE / sizeof(int16_t)], *dst = buf;
			int pos =     rd_pos;
			int len = min(rd_len, ARRAY_SIZE(buf)), cnt = len;				//有効データ長,又は,パケットサイズの小さい方を単位として処理する
			do {
				*dst++ = pAudio->Buf[pos++];						//有効データを取得する
				if(pos == pAudio->Cap) { pos = 0; }					//読み出し位置が終端に達したら、折り返す
			} while(--cnt);
			if(D12_WriteBuffer(EP2IN, buf, len * sizeof(int16_t)) == -1) { break; }		//パケットを書き込む。USBコントローラのバッファに空きが無く書き込めなければ、ここまで
			D12_ValidateBuffer(EP2IN);							//パケットを送出する
			rd_pos  = pos;									//パケットを書き込めた分、読み出し位置を進める
			rd_len -= len;									//パケットを書き込めた分、有効データ長を減らす
		}
		pAudio->Pos = rd_pos;		//読み出し位置(構造体へ書き戻す)
		pAudio->Len = rd_len;		//有効データ長(構造体へ書き戻す)
	}
}

#else /*PIECE*/
/*static*/ void Audio_ep2_txdone();
asm("
		.code
		.align		1
Audio_ep2_txdone:
		xld.w		%r4, [pAudio]		;//%r4  := pAudio
		ld.uh		%r9, [%r4]+		;//%r9  := pAudio->bAlternateSetting					!INTERLOCK!
		cmp		%r9, 0			;//if(!pAudio->bAlternateSetting) {
		jreq		Audio_ep2_txdone_L60	;//  goto L60 }
		;//-------------------------------------;//
		pushn		%r3
		xsub		%sp, %sp, 128
		ld.uh		%r0, [%r4]+		;//%r0  := rd_pos = pAudio->Pos
		ld.uh		%r1, [%r4]+		;//%r1  := rd_len = pAudio->Len
		jp.d		Audio_ep2_txdone_L40	;//goto L40
		cmp		%r1, 0			;//                       %psr(Z) := (rd_len ? 0 : 1)			*delay*
		;//-------------------------------------;//
		;//[%sp] := buf[64].h
		;//%r0   := rd_pos
		;//%r1   := rd_len
Audio_ep2_txdone_L10:
		ld.w		%r2, %r0		;//%r2  := pos = rd_pos
		ld.w		%r3, %r1		;//%r3  := len = rd_len
		xcmp		%r3, 64			;//if(len > 64) {
		jrule		Audio_ep2_txdone_L20	;//
		xld.w		%r3, 64			;//  %r3  := len = 64 }
Audio_ep2_txdone_L20:					;//
		ld.w		%r4, %sp		;//%r4  := dst = buf
		ld.w		%r5, %r3		;//%r5  := cnt = len
		xld.w		%r6, [pAudio]		;//%r6  :=       pAudio
		add		%r6, 6			;//%r6  :=      &pAudio->Cap						!INTERLOCK!
		ld.uh		%r7, [%r6]+		;//%r7  := Cap = pAudio->Cap, %r6 := pAudio->Buf
		add		%r6, %r2		;//%r6  := src = pAudio->Buf + pos * sizeof(int16_t)
		add		%r6, %r2		;//
		sub		%r2, %r7		;//%r2  := (pos-Cap)									高速化の工夫。posを0→Capに変化するよりも、(pos-Cap)を(-Cap)→0に変化する方が、比較命令が少なくて済む。
		;//[%sp] := buf[64].h
		;//%r0   := rd_pos
		;//%r1   := rd_len
		;//%r2   := pos
		;//%r3   := len
		;//%r4   := dst
		;//%r5   := cnt
		;//%r6   := src
		;//%r7   := Cap
Audio_ep2_txdone_L30:					;//do {
		ld.h		%r9, [%r6]+		;//  *dst++ = *src++
		ld.h		[%r4]+, %r9		;//  
		add		%r2, 1			;//  %r2  := (pos-Cap)++
		jrne		4			;//  if((pos-Cap) == 0) {
		 sub		%r2, %r7		;//    %r2  := (pos-Cap) -= Cap
		 sub		%r6, %r7		;//    %r6  := src -= Cap * sizeof(int16_t) }
		 sub		%r6, %r7		;//  
		sub		%r5, 1			;//  %r5  := cnt--
		jrne		Audio_ep2_txdone_L30	;//} while(cnt)
		add		%r2, %r7		;//%r2  := pos
		ld.w		%r12, 5			;//%r12 :=                          EP2IN
		ld.w		%r13, %sp		;//%r13 :=                                 buf
		ld.w		%r14, %r3		;//%r14 :=                                      len
		xcall.d		D12_WriteBuffer		;//%r10 := retval = D12_WriteBuffer(EP2IN, buf, len * sizeof(int16_t))
		sll		%r14, 1			;//%r14 :=                                      len * sizeof(int16_t)	*delay*
		cmp		%r10, -1		;//if(retval == -1) {
		jreq		Audio_ep2_txdone_L50	;//  goto L50 }
		xcall.d		D12_ValidateBuffer	;//D12_ValidateBuffer(EP2IN)
		ld.w		%r12, 5			;//%r12 :=            EP2IN						*delay*
		ld.w		%r0, %r2		;//%r0  := rd_pos  = pos
		sub		%r1, %r3		;//%r1  := rd_len -= len, %psr(Z) := (rd_len ? 0 : 1)
Audio_ep2_txdone_L40:					;//
		jrne		Audio_ep2_txdone_L10	;//                    if(%psr(Z) == 0) { goto L10 }
		;//-------------------------------------;//
		;//[%sp] := buf[64].h
		;//%r0   := rd_pos
		;//%r1   := rd_len
Audio_ep2_txdone_L50:
		xld.w		%r4, [pAudio]		;//%r4  :=  pAudio
		add		%r4, 2			;//%r4  := &pAudio->Pos
		ld.h		[%r4]+, %r0		;//pAudio->Pos = rd_pos
		ld.h		[%r4]+, %r1		;//pAudio->Len = rd_len
		xadd		%sp, %sp, 128
		popn		%r3
		;//-------------------------------------;//
Audio_ep2_txdone_L60:
		ret
");
#endif /*PIECE*/
