blob: 2774a0cf3dd72c5e7685c3242d1b3ba8bf3b457a [file] [log] [blame]
# Copyright 2015 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 _store_in_cache(self,
descriptors,
mbim_communication_interface,
ncm_communication_interface,
no_data_data_interface,
mbim_data_interface,
ncm_data_interface):
"""
Store the MBIM/NCM interface descriptors into the |device_context| and
also fetch the MBIM funnction descriptor, interrrupt endpoint
descriptor and bulk endpoint descriptors.
@param descriptors: Raw descriptor set obtained from the device.
Type: Array of |usb_descriptors.Descriptor| objects.
@param mbim_communication_interface: MBIM communication interface
descriptor object.
@param ncm_communication_interface: NCM communication interface
descriptor object if the device supports NCM/MBIM.
@param no_data_data_interface: MBIM/NCM data interface object. To be set
when not being used for any active data transfer.
@param mbim_data_interface: MBIM data interface object. To be set
when being used for any active MBIM NTB data transfer.
@param ncm_data_interface: NCM data interface object. To be set
when being used for any active NCM NTB data transfer.
"""
# Fetch the MBIM function descriptor
mbim_communication_interface_bundle = (
usb_descriptors.get_descriptor_bundle(
descriptors, mbim_communication_interface))
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')
# Fetch the MBIM bulk-in/out endpoints
mbim_data_interface_bundle = (
usb_descriptors.get_descriptor_bundle(
descriptors, mbim_data_interface))
bulk_endpoint_descriptors = usb_descriptors.filter_descriptors(
usb_descriptors.EndpointDescriptor,
mbim_data_interface_bundle)
if len(bulk_endpoint_descriptors) != 2:
mbim_errors.log_and_raise(
mbim_errors.MBIMComplianceTestError,
'MBIM Bulk-In/Bulk-Out Endpoint descriptors not found')
# Update with MBIM function settings.
self.ncm_communication_interface = ncm_communication_interface
self.mbim_communication_interface = mbim_communication_interface
self.no_data_data_interface = no_data_data_interface
self.ncm_data_interface = ncm_data_interface
self.mbim_data_interface = mbim_data_interface
self.mbim_functional = mbim_descriptors[0]
self.interrupt_endpoint = interrupt_endpoint_descriptors[0]
for endpoint in bulk_endpoint_descriptors:
# Check for MSB bit to determine if it is a
# BULK-OUT vs BULK-IN endpoint
if endpoint.bEndpointAddress < 0x80:
self.bulk_out_endpoint = endpoint
else:
self.bulk_in_endpoint = endpoint
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')
# Store the info in our |device_context| cache
self._store_in_cache(descriptors,
mbim_communication_interfaces[0],
None,
no_data_data_interfaces[0],
mbim_data_interfaces[0],
None)
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')
# Store the info in our |device_context| cache
self._store_in_cache(descriptors,
mbim_communication_interfaces[0],
ncm_communication_interfaces[0],
no_data_data_interfaces[0],
mbim_data_interfaces[0],
ncm_data_interfaces[0])
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)