| # Copyright 2014 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| from autotest_lib.client.cros.cellular.mbim_compliance import mbim_errors |
| from autotest_lib.client.cros.cellular.mbim_compliance import usb_descriptors |
| |
| |
| class MbimDescriptorCache(object): |
| """ |
| Class used to store a cache of the most frequently used MBIM descriptors. |
| This caching of descriptors avoids frequent access to the device for |
| any control information. |
| |
| """ |
| |
| def __init__(self, descriptors): |
| """ |
| Store the the relevant descriptors from the list of descriptors. |
| |
| @param descriptors: Raw descriptor set obtained from the device. |
| Type: Array of |usb_descriptors.Descriptor| objects. |
| |
| """ |
| if self._check_ncm_mbim_device(descriptors): |
| self._update_ncm_mbim_cache(descriptors) |
| else: |
| self._update_mbim_cache(descriptors) |
| |
| |
| def _update_mbim_cache(self, descriptors): |
| """ |
| Parse and cache given raw |descriptors| as MBIM descriptors. |
| |
| """ |
| self.is_mbim_only = True |
| |
| # Fetch the MBIM communication interface |
| interfaces = usb_descriptors.filter_descriptors( |
| usb_descriptors.InterfaceDescriptor, descriptors) |
| mbim_communication_interfaces = ( |
| usb_descriptors.filter_interface_descriptors( |
| interfaces, |
| usb_descriptors.MBIM_ONLY_COMMUNICATION_INTERFACE)) |
| if not mbim_communication_interfaces: |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceTestError, |
| 'No MBIM communication interface descriptor found') |
| |
| # Fetch the MBIM no_data data interface |
| no_data_data_interfaces = ( |
| usb_descriptors.filter_interface_descriptors( |
| interfaces, |
| usb_descriptors.MBIM_ONLY_DATA_INTERFACE_NO_DATA)) |
| if not no_data_data_interfaces: |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceTestError, |
| 'No No_Data data interface descriptor found') |
| # Fetch the MBIM data interface |
| mbim_data_interfaces = ( |
| usb_descriptors.filter_interface_descriptors( |
| interfaces, |
| usb_descriptors.MBIM_ONLY_DATA_INTERFACE_MBIM)) |
| if not mbim_data_interfaces: |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceTestError, |
| 'No MBIM data interface descriptor found') |
| |
| # Fetch the MBIM function |
| mbim_communication_interface_bundle = ( |
| usb_descriptors.get_descriptor_bundle( |
| descriptors, mbim_communication_interfaces[0])) |
| mbim_descriptors = usb_descriptors.filter_descriptors( |
| usb_descriptors.MBIMFunctionalDescriptor, |
| mbim_communication_interface_bundle) |
| if not mbim_descriptors: |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceTestError, |
| 'No MBIM functional descriptor found') |
| |
| # Fetch the MBIM interrupt enpoint |
| interrupt_endpoint_descriptors = usb_descriptors.filter_descriptors( |
| usb_descriptors.EndpointDescriptor, |
| mbim_communication_interface_bundle) |
| if not interrupt_endpoint_descriptors: |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceTestError, |
| 'No MBIM Interrupt Endpoint descriptor found') |
| |
| # Update with MBIM function settings. |
| self.ncm_communication_interface = None |
| self.mbim_communication_interface = mbim_communication_interfaces[0] |
| self.no_data_data_interface = no_data_data_interfaces[0] |
| self.ncm_data_interface = None |
| self.mbim_data_interface = mbim_data_interfaces[0] |
| self.mbim_functional = mbim_descriptors[0] |
| self.interrupt_endpoint = interrupt_endpoint_descriptors[0] |
| |
| |
| def _update_ncm_mbim_cache(self, descriptors): |
| """ |
| Parse and cache given raw |descriptors| as NCM + MBIM descriptors. |
| |
| """ |
| self.is_mbim_only = False |
| |
| # Fetch the NCM communication interface |
| interfaces = usb_descriptors.filter_descriptors( |
| usb_descriptors.InterfaceDescriptor, descriptors) |
| ncm_communication_interfaces = ( |
| usb_descriptors.filter_interface_descriptors( |
| interfaces, |
| usb_descriptors.NCM_MBIM_COMMUNICATION_INTERFACE_NCM)) |
| |
| # Fetch the MBIM communication interface |
| mbim_communication_interfaces = ( |
| usb_descriptors.filter_interface_descriptors( |
| interfaces, |
| usb_descriptors.NCM_MBIM_COMMUNICATION_INTERFACE_MBIM)) |
| if not mbim_communication_interfaces: |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceTestError, |
| 'No MBIM communication interface descriptor found') |
| |
| # Fetch the NCM + MBIM no_data data interface |
| no_data_data_interfaces = ( |
| usb_descriptors.filter_interface_descriptors( |
| interfaces, |
| usb_descriptors.NCM_MBIM_DATA_INTERFACE_NO_DATA)) |
| if not no_data_data_interfaces: |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceTestError, |
| 'No No_Data data interface descriptor found') |
| # Fetch the NCM data interface |
| ncm_data_interfaces = ( |
| usb_descriptors.filter_interface_descriptors( |
| interfaces, |
| usb_descriptors.NCM_MBIM_DATA_INTERFACE_NCM)) |
| if not ncm_data_interfaces: |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceTestError, |
| 'No NCM data interface descriptor found') |
| # Fetch the MBIM data interface |
| mbim_data_interfaces = ( |
| usb_descriptors.filter_interface_descriptors( |
| interfaces, |
| usb_descriptors.NCM_MBIM_DATA_INTERFACE_MBIM)) |
| if not mbim_data_interfaces: |
| mbim_errors.log_and_raise( |
| mbim_errors.MBIMComplianceTestError, |
| 'No MBIM data interface descriptor found') |
| |
| # Update with NCM + MBIM function settings. |
| self.ncm_communication_interface = ncm_communication_interfaces[0] |
| self.mbim_communication_interface = mbim_communication_interfaces[0] |
| self.no_data_data_interface = no_data_data_interfaces[0] |
| self.ncm_data_interface = ncm_data_interfaces[0] |
| self.mbim_data_interface = mbim_data_interfaces[0] |
| self.interrupt_endpoint = None |
| |
| |
| def _check_ncm_mbim_device(self, descriptors): |
| """ |
| Checks whether the connected device supports NCM + MBIM or MBIM only. |
| |
| @returns True if the device supports NCM + MBIM, else False |
| |
| """ |
| # Only a dual NCM/MBIM device has an NCM communication interface |
| # in its descriptors |
| interfaces = usb_descriptors.filter_descriptors( |
| usb_descriptors.InterfaceDescriptor, descriptors) |
| ncm_communication_interfaces = ( |
| usb_descriptors.filter_interface_descriptors( |
| interfaces, |
| usb_descriptors.NCM_MBIM_COMMUNICATION_INTERFACE_NCM)) |
| return bool(ncm_communication_interfaces) |