Home | History | Annotate | Download | only in mbim_compliance
      1 # Copyright 2015 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 from autotest_lib.client.cros.cellular.mbim_compliance import mbim_errors
      6 from autotest_lib.client.cros.cellular.mbim_compliance import usb_descriptors
      7 
      8 
      9 class MbimDescriptorCache(object):
     10     """
     11     Class used to store a cache of the most frequently used MBIM descriptors.
     12     This caching of descriptors avoids frequent access to the device for
     13     any control information.
     14 
     15     """
     16 
     17     def __init__(self, descriptors):
     18         """
     19         Store the the relevant descriptors from the list of descriptors.
     20 
     21         @param descriptors: Raw descriptor set obtained from the device.
     22                             Type: Array of |usb_descriptors.Descriptor| objects.
     23 
     24         """
     25         if self._check_ncm_mbim_device(descriptors):
     26             self._update_ncm_mbim_cache(descriptors)
     27         else:
     28             self._update_mbim_cache(descriptors)
     29 
     30 
     31     def _store_in_cache(self,
     32                         descriptors,
     33                         mbim_communication_interface,
     34                         ncm_communication_interface,
     35                         no_data_data_interface,
     36                         mbim_data_interface,
     37                         ncm_data_interface):
     38         """
     39         Store the MBIM/NCM interface descriptors into the |device_context| and
     40         also fetch the MBIM funnction descriptor, interrrupt endpoint
     41         descriptor and bulk endpoint descriptors.
     42 
     43         @param descriptors: Raw descriptor set obtained from the device.
     44                 Type: Array of |usb_descriptors.Descriptor| objects.
     45         @param mbim_communication_interface: MBIM communication interface
     46                 descriptor object.
     47         @param ncm_communication_interface: NCM communication interface
     48                 descriptor object if the device supports NCM/MBIM.
     49         @param no_data_data_interface: MBIM/NCM data interface object. To be set
     50                 when not being used for any active data transfer.
     51         @param mbim_data_interface: MBIM data interface object. To be set
     52                 when being used for any active MBIM NTB data transfer.
     53         @param ncm_data_interface: NCM data interface object. To be set
     54                 when being used for any active NCM NTB data transfer.
     55 
     56         """
     57         # Fetch the MBIM function descriptor
     58         mbim_communication_interface_bundle = (
     59                 usb_descriptors.get_descriptor_bundle(
     60                         descriptors, mbim_communication_interface))
     61         mbim_descriptors = usb_descriptors.filter_descriptors(
     62                 usb_descriptors.MBIMFunctionalDescriptor,
     63                 mbim_communication_interface_bundle)
     64         if not mbim_descriptors:
     65             mbim_errors.log_and_raise(
     66                     mbim_errors.MBIMComplianceTestError,
     67                     'No MBIM functional descriptor found')
     68 
     69         # Fetch the MBIM interrupt enpoint
     70         interrupt_endpoint_descriptors = usb_descriptors.filter_descriptors(
     71                 usb_descriptors.EndpointDescriptor,
     72                 mbim_communication_interface_bundle)
     73         if not interrupt_endpoint_descriptors:
     74             mbim_errors.log_and_raise(
     75                     mbim_errors.MBIMComplianceTestError,
     76                     'No MBIM Interrupt Endpoint descriptor found')
     77 
     78         # Fetch the MBIM bulk-in/out endpoints
     79         mbim_data_interface_bundle = (
     80                 usb_descriptors.get_descriptor_bundle(
     81                         descriptors, mbim_data_interface))
     82         bulk_endpoint_descriptors = usb_descriptors.filter_descriptors(
     83                 usb_descriptors.EndpointDescriptor,
     84                 mbim_data_interface_bundle)
     85         if len(bulk_endpoint_descriptors) != 2:
     86             mbim_errors.log_and_raise(
     87                     mbim_errors.MBIMComplianceTestError,
     88                     'MBIM Bulk-In/Bulk-Out Endpoint descriptors not found')
     89 
     90         # Update with MBIM function settings.
     91         self.ncm_communication_interface = ncm_communication_interface
     92         self.mbim_communication_interface = mbim_communication_interface
     93         self.no_data_data_interface = no_data_data_interface
     94         self.ncm_data_interface = ncm_data_interface
     95         self.mbim_data_interface = mbim_data_interface
     96         self.mbim_functional = mbim_descriptors[0]
     97         self.interrupt_endpoint = interrupt_endpoint_descriptors[0]
     98         for endpoint in bulk_endpoint_descriptors:
     99             # Check for MSB bit to determine if it is a
    100             # BULK-OUT vs BULK-IN endpoint
    101             if endpoint.bEndpointAddress < 0x80:
    102                 self.bulk_out_endpoint = endpoint
    103             else:
    104                 self.bulk_in_endpoint = endpoint
    105 
    106 
    107     def _update_mbim_cache(self, descriptors):
    108         """
    109         Parse and cache given raw |descriptors| as MBIM descriptors.
    110 
    111         """
    112         self.is_mbim_only = True
    113 
    114         # Fetch the MBIM communication interface
    115         interfaces = usb_descriptors.filter_descriptors(
    116                 usb_descriptors.InterfaceDescriptor, descriptors)
    117         mbim_communication_interfaces = (
    118                 usb_descriptors.filter_interface_descriptors(
    119                         interfaces,
    120                         usb_descriptors.MBIM_ONLY_COMMUNICATION_INTERFACE))
    121         if not mbim_communication_interfaces:
    122             mbim_errors.log_and_raise(
    123                     mbim_errors.MBIMComplianceTestError,
    124                     'No MBIM communication interface descriptor found')
    125 
    126         # Fetch the MBIM no_data data interface
    127         no_data_data_interfaces = (
    128                 usb_descriptors.filter_interface_descriptors(
    129                         interfaces,
    130                         usb_descriptors.MBIM_ONLY_DATA_INTERFACE_NO_DATA))
    131         if not no_data_data_interfaces:
    132             mbim_errors.log_and_raise(
    133                     mbim_errors.MBIMComplianceTestError,
    134                     'No No_Data data interface descriptor found')
    135         # Fetch the MBIM data interface
    136         mbim_data_interfaces = (
    137                 usb_descriptors.filter_interface_descriptors(
    138                         interfaces,
    139                         usb_descriptors.MBIM_ONLY_DATA_INTERFACE_MBIM))
    140         if not mbim_data_interfaces:
    141             mbim_errors.log_and_raise(
    142                     mbim_errors.MBIMComplianceTestError,
    143                     'No MBIM data interface descriptor found')
    144 
    145         # Store the info in our |device_context| cache
    146         self._store_in_cache(descriptors,
    147                              mbim_communication_interfaces[0],
    148                              None,
    149                              no_data_data_interfaces[0],
    150                              mbim_data_interfaces[0],
    151                              None)
    152 
    153 
    154     def _update_ncm_mbim_cache(self, descriptors):
    155         """
    156         Parse and cache given raw |descriptors| as NCM + MBIM descriptors.
    157 
    158         """
    159         self.is_mbim_only = False
    160 
    161         # Fetch the NCM communication interface
    162         interfaces = usb_descriptors.filter_descriptors(
    163                 usb_descriptors.InterfaceDescriptor, descriptors)
    164         ncm_communication_interfaces = (
    165                 usb_descriptors.filter_interface_descriptors(
    166                         interfaces,
    167                         usb_descriptors.NCM_MBIM_COMMUNICATION_INTERFACE_NCM))
    168 
    169         # Fetch the MBIM communication interface
    170         mbim_communication_interfaces = (
    171                 usb_descriptors.filter_interface_descriptors(
    172                         interfaces,
    173                         usb_descriptors.NCM_MBIM_COMMUNICATION_INTERFACE_MBIM))
    174         if not mbim_communication_interfaces:
    175             mbim_errors.log_and_raise(
    176                     mbim_errors.MBIMComplianceTestError,
    177                     'No MBIM communication interface descriptor found')
    178 
    179         # Fetch the NCM + MBIM no_data data interface
    180         no_data_data_interfaces = (
    181                 usb_descriptors.filter_interface_descriptors(
    182                         interfaces,
    183                         usb_descriptors.NCM_MBIM_DATA_INTERFACE_NO_DATA))
    184         if not no_data_data_interfaces:
    185             mbim_errors.log_and_raise(
    186                     mbim_errors.MBIMComplianceTestError,
    187                     'No No_Data data interface descriptor found')
    188         # Fetch the NCM data interface
    189         ncm_data_interfaces = (
    190                 usb_descriptors.filter_interface_descriptors(
    191                         interfaces,
    192                         usb_descriptors.NCM_MBIM_DATA_INTERFACE_NCM))
    193         if not ncm_data_interfaces:
    194             mbim_errors.log_and_raise(
    195                     mbim_errors.MBIMComplianceTestError,
    196                     'No NCM data interface descriptor found')
    197         # Fetch the MBIM data interface
    198         mbim_data_interfaces = (
    199                 usb_descriptors.filter_interface_descriptors(
    200                         interfaces,
    201                         usb_descriptors.NCM_MBIM_DATA_INTERFACE_MBIM))
    202         if not mbim_data_interfaces:
    203             mbim_errors.log_and_raise(
    204                     mbim_errors.MBIMComplianceTestError,
    205                     'No MBIM data interface descriptor found')
    206 
    207         # Store the info in our |device_context| cache
    208         self._store_in_cache(descriptors,
    209                              mbim_communication_interfaces[0],
    210                              ncm_communication_interfaces[0],
    211                              no_data_data_interfaces[0],
    212                              mbim_data_interfaces[0],
    213                              ncm_data_interfaces[0])
    214 
    215 
    216     def _check_ncm_mbim_device(self, descriptors):
    217         """
    218         Checks whether the connected device supports NCM + MBIM or MBIM only.
    219 
    220         @returns True if the device supports NCM + MBIM, else False
    221 
    222         """
    223         # Only a dual NCM/MBIM device has an NCM communication interface
    224         # in its descriptors
    225         interfaces = usb_descriptors.filter_descriptors(
    226                 usb_descriptors.InterfaceDescriptor, descriptors)
    227         ncm_communication_interfaces = (
    228                 usb_descriptors.filter_interface_descriptors(
    229                         interfaces,
    230                         usb_descriptors.NCM_MBIM_COMMUNICATION_INTERFACE_NCM))
    231         return bool(ncm_communication_interfaces)
    232