Skip to content

Commit 9d4d843

Browse files
committed
usbd: Add support for configuration open and reset callbacks.
Implement by overriding USBInterface.handle_open or handle_reset.
1 parent 581a662 commit 9d4d843

File tree

1 file changed

+63
-9
lines changed

1 file changed

+63
-9
lines changed

micropython/usbd/device.py

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ def __init__(self):
7878
descriptor_device_cb=self._descriptor_device_cb,
7979
descriptor_config_cb=self._descriptor_config_cb,
8080
descriptor_string_cb=self._descriptor_string_cb,
81-
open_driver_cb=self._open_driver_cb,
81+
open_cb=self._open_cb,
82+
reset_cb=self._reset_cb,
8283
control_xfer_cb=self._control_xfer_cb,
8384
xfer_cb=self._xfer_cb,
8485
)
@@ -286,9 +287,37 @@ def _descriptor_string_cb(self, index):
286287
except IndexError:
287288
return None
288289

289-
def _open_driver_cb(self, interface_desc_view):
290-
# Singleton callback from TinyUSB custom class driver
291-
pass
290+
def _open_cb(self, interface_desc_view):
291+
# Singleton callback from TinyUSB custom class driver, when USB host does
292+
# Set Configuration. The "runtime class device" accepts all interfaces that
293+
# it has sent in descriptors, and calls this callback.
294+
295+
# Walk the view of the "claimed" descriptor data provided in the
296+
# callback and call handle_open() on each claimed interface
297+
#
298+
# ... this may be unnecessary at the moment, as only one configuration is supported so we
299+
# can probably assume all the interfaces will be included.
300+
i = 0
301+
while i < len(interface_desc_view):
302+
# descriptor length, type, and index (if it's an interface descriptor)
303+
dl, dt, di = interface_desc_view[i:i+3]
304+
if dt == _STD_DESC_INTERFACE_TYPE:
305+
if di >= self._usbd.static.itf_max:
306+
di -= self._usbd.static.itf_max
307+
self._itfs[di].handle_open()
308+
i += dl
309+
assert dl
310+
311+
def _reset_cb(self):
312+
# Callback when the USB device is reset by the host
313+
314+
# Cancel outstanding transfer callbacks
315+
for k in self._ep_cbs.keys():
316+
self._ep_cbs[k] = None
317+
318+
# Allow interfaces to respond to the reset
319+
for itf in self._itfs:
320+
itf.handle_reset()
292321

293322
def _submit_xfer(self, ep_addr, data, done_cb=None):
294323
# Singleton function to submit a USB transfer (of any type except control).
@@ -387,6 +416,7 @@ def __init__(
387416
self.bInterfaceSubClass = bInterfaceSubClass
388417
self.bInterfaceProtocol = bInterfaceProtocol
389418
self.interface_str = interface_str
419+
self._open = False
390420

391421
def get_itf_descriptor(self, num_eps, itf_idx, str_idx):
392422
# Return the interface descriptor binary data and associated other
@@ -466,6 +496,27 @@ def get_endpoint_descriptors(self, ep_addr, str_idx):
466496
# start from ep_addr, optionally with the utils.EP_IN_FLAG bit set.)
467497
return (b"", [], [])
468498

499+
def handle_open(self):
500+
# Callback called when the USB host accepts the device configuration.
501+
#
502+
# Override this function to initiate any operations that the USB interface
503+
# should do when the USB device is configured to the host.
504+
self._open = True
505+
506+
def handle_reset(self):
507+
# Callback called on every registered interface when the USB device is
508+
# reset by the host. This can happen when the USB device is unplugged,
509+
# or if the host triggers a reset for some other reason.
510+
#
511+
# At this point, no USB functionality is available - handle_open() will
512+
# be called later if/when the USB host re-enumerates and configures the
513+
# interface.
514+
self._open = False
515+
516+
def is_open(self):
517+
# Returns True if the interface is in use
518+
return self._open
519+
469520
def handle_device_control_xfer(self, stage, request):
470521
# Control transfer callback. Override to handle a non-standard device
471522
# control transfer where bmRequestType Recipient is Device, Type is
@@ -486,11 +537,11 @@ def handle_device_control_xfer(self, stage, request):
486537
# The function can call split_bmRequestType() to split bmRequestType into
487538
# (Recipient, Type, Direction).
488539
#
489-
# Result:
540+
# Result, any of:
490541
#
491-
# - True to continue the request False to STALL the endpoint A buffer
492-
# - interface object to provide a buffer to the host as part of the
493-
# - transfer, if possible.
542+
# - True to continue the request, False to STALL the endpoint.
543+
# - Buffer interface object to provide a buffer to the host as part of the
544+
# transfer, if possible.
494545
return False
495546

496547
def handle_interface_control_xfer(self, stage, request):
@@ -512,7 +563,8 @@ def handle_interface_control_xfer(self, stage, request):
512563
def handle_endpoint_control_xfer(self, stage, request):
513564
# Control transfer callback. Override to handle a device
514565
# control transfer where bmRequestType Recipient is Endpoint and
515-
# the lower byte of wIndex indicates an endpoint address associated with this interface.
566+
# the lower byte of wIndex indicates an endpoint address associated
567+
# with this interface.
516568
#
517569
# bmRequestType Type will generally have any value except
518570
# utils.REQ_TYPE_STANDARD, as Standard endpoint requests are handled by
@@ -546,4 +598,6 @@ def submit_xfer(self, ep_addr, data, done_cb=None):
546598
#
547599
# Note that done_cb may be called immediately, possibly before this
548600
# function has returned to the caller.
601+
if not self._open:
602+
raise RuntimeError()
549603
return get_usbdevice()._submit_xfer(ep_addr, data, done_cb)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy