This commit is contained in:
2026-03-13 19:58:28 +03:00
commit c938609393
87 changed files with 230200 additions and 0 deletions

148
gateware/requesthandlers.py Normal file
View File

@@ -0,0 +1,148 @@
from enum import IntEnum
from amaranth import *
from luna.gateware.usb.usb2.request import USBRequestHandler
from luna.gateware.stream.generator import StreamSerializer
from usb_protocol.types import USBRequestType, USBRequestRecipient, USBStandardRequests
from usb_protocol.types.descriptors.uac2 import AudioClassSpecificRequestCodes, ClockSourceControlSelectors
from luna.gateware.usb.stream import USBInStreamInterface
from usb_descriptors import USBDescriptors
class VendorRequests(IntEnum):
ILA_STOP_CAPTURE = 0
TOGGLE_CONVOLUTION = 1
class UAC2RequestHandlers(USBRequestHandler):
""" request handlers to implement UAC2 functionality. """
def __init__(self):
super().__init__()
self.output_interface_altsetting_nr = Signal(3)
self.input_interface_altsetting_nr = Signal(3)
self.interface_settings_changed = Signal()
self.enable_convolution = Signal()
def elaborate(self, platform):
m = Module()
interface = self.interface
setup = self.interface.setup
m.submodules.transmitter = transmitter = \
StreamSerializer(data_length=14, domain="usb", stream_type=USBInStreamInterface, max_length_width=14)
m.d.usb += self.interface_settings_changed.eq(0)
m.d.comb += self.enable_convolution.eq(0)
#
# Class request handlers.
#
with m.If(setup.type == USBRequestType.STANDARD):
with m.If((setup.recipient == USBRequestRecipient.INTERFACE) &
(setup.request == USBStandardRequests.SET_INTERFACE)):
interface_nr = setup.index
alt_setting_nr = setup.value
m.d.usb += [
self.output_interface_altsetting_nr.eq(0),
self.input_interface_altsetting_nr.eq(0),
self.interface_settings_changed.eq(1),
]
with m.Switch(interface_nr):
with m.Case(1):
m.d.usb += self.output_interface_altsetting_nr.eq(alt_setting_nr)
with m.Case(2):
m.d.usb += self.input_interface_altsetting_nr.eq(alt_setting_nr)
# Always ACK the data out...
with m.If(interface.rx_ready_for_response):
m.d.comb += interface.handshakes_out.ack.eq(1)
# ... and accept whatever the request was.
with m.If(interface.status_requested):
m.d.comb += self.send_zlp()
clock_freq = (setup.value == Const(ClockSourceControlSelectors.CS_SAM_FREQ_CONTROL << 8, 16)) \
& (setup.index == Const(USBDescriptors.CLOCK_ID << 8, 16))
request_clock_freq = clock_freq & setup.is_in_request
set_clock_freq = clock_freq & ~setup.is_in_request
SRATE_44_1k = Const(44100, 32)
SRATE_48k = Const(48000, 32)
ZERO = Const(0, 32)
with m.Elif(setup.type == USBRequestType.CLASS):
with m.Switch(setup.request):
with m.Case(AudioClassSpecificRequestCodes.RANGE):
m.d.comb += transmitter.stream.attach(self.interface.tx)
with m.If(request_clock_freq):
m.d.comb += [
Cat(transmitter.data).eq(
Cat(Const(0x1, 16), # no triples
SRATE_48k, # MIN
SRATE_48k, # MAX
ZERO)), # RES
transmitter.max_length.eq(setup.length)
]
with m.Else():
m.d.comb += interface.handshakes_out.stall.eq(1)
# ... trigger it to respond when data's requested...
with m.If(interface.data_requested):
m.d.comb += transmitter.start.eq(1)
# ... and ACK our status stage.
with m.If(interface.status_requested):
m.d.comb += interface.handshakes_out.ack.eq(1)
with m.Case(AudioClassSpecificRequestCodes.CUR):
m.d.comb += transmitter.stream.attach(self.interface.tx)
with m.If(request_clock_freq & (setup.length == 4)):
m.d.comb += [
Cat(transmitter.data[0:4]).eq(Const(48000, 32)),
transmitter.max_length.eq(4)
]
with m.Else():
m.d.comb += interface.handshakes_out.stall.eq(1)
# ... trigger it to respond when data's requested...
with m.If(interface.data_requested):
m.d.comb += transmitter.start.eq(1)
# ... and ACK our status stage.
with m.If(interface.status_requested):
m.d.comb += interface.handshakes_out.ack.eq(1)
with m.Default():
#
# Stall unhandled requests.
#
with m.If(interface.status_requested | interface.data_requested):
m.d.comb += interface.handshakes_out.stall.eq(1)
with m.Elif(setup.type == USBRequestType.VENDOR):
with m.Switch(setup.request):
with m.Case(VendorRequests.TOGGLE_CONVOLUTION):
m.d.comb += self.enable_convolution.eq(1)
# m.d.usb += self.enable_convolution.eq(~self.enable_convolution)
# ... and ACK our status stage.
with m.If(interface.status_requested | interface.data_requested):
m.d.comb += interface.handshakes_out.ack.eq(1)
# m.d.comb += self.interface.handshakes_out.stall.eq(1)
# pass
with m.Case(VendorRequests.ILA_STOP_CAPTURE):
# TODO - will be implemented when needed
pass
with m.Default():
m.d.comb += self.interface.handshakes_out.stall.eq(1)
with m.Else():
m.d.comb += self.interface.handshakes_out.stall.eq(1)
return m