@@ -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