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 5from autotest_lib.client.cros.cellular.mbim_compliance import mbim_errors 6from autotest_lib.client.cros.cellular.mbim_compliance import usb_descriptors 7 8 9class 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