blob: cb5f7837bf0bd5ef41949ce0265bea51640bb93a [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_CONNECTIVITY_ETHERNET_DRIVERS_ASIX_88179_ASIX_88179_H_
#define SRC_CONNECTIVITY_ETHERNET_DRIVERS_ASIX_88179_ASIX_88179_H_
#include <fuchsia/hardware/ethernet/cpp/banjo.h>
#include <lib/ddk/device.h>
#include <lib/operation/ethernet.h>
#include <lib/sync/completion.h>
#include <lib/zircon-internal/thread_annotations.h>
#include <optional>
#include <queue>
#include <thread>
#include <ddktl/device.h>
#include <fbl/auto_lock.h>
#include <usb/request-cpp.h>
#include <usb/usb-request.h>
#include <usb/usb.h>
namespace eth {
class Asix88179Ethernet;
using DeviceType = ddk::Device<Asix88179Ethernet, ddk::Initializable, ddk::Unbindable>;
class Asix88179Ethernet : public DeviceType,
public ddk::EthernetImplProtocol<Asix88179Ethernet, ddk::base_protocol> {
public:
Asix88179Ethernet(const Asix88179Ethernet&) = delete;
Asix88179Ethernet(Asix88179Ethernet&&) = delete;
Asix88179Ethernet& operator=(const Asix88179Ethernet&) = delete;
Asix88179Ethernet& operator=(Asix88179Ethernet&&) = delete;
explicit Asix88179Ethernet(zx_device_t* parent) : DeviceType(parent) {}
// DDK Hooks.
void DdkInit(ddk::InitTxn txn);
void DdkRelease();
void DdkUnbind(ddk::UnbindTxn txn);
zx_status_t EthernetImplQuery(uint32_t options, ethernet_info_t* info);
void EthernetImplStop();
zx_status_t EthernetImplStart(const ethernet_ifc_protocol_t* ifc);
void EthernetImplQueueTx(uint32_t options, ethernet_netbuf_t* netbuf,
ethernet_impl_queue_tx_callback completion_cb, void* cookie);
zx_status_t EthernetImplSetParam(uint32_t param, int32_t value, const uint8_t* data,
size_t data_size);
void EthernetImplGetBti(zx::bti* bti) { bti->reset(); }
static zx_status_t Bind(void* ctx, zx_device_t* device);
static void Release(void* ctx);
private:
zx_status_t Initialize();
zx_status_t InitializeRegisters();
template <typename T>
zx_status_t ReadMac(uint8_t register_address, T* data) TA_REQ(lock_);
template <typename T>
zx_status_t WriteMac(uint8_t register_address, const T& data) TA_REQ(lock_);
zx_status_t ReadPhy(uint8_t register_address, uint16_t* data) TA_REQ(lock_);
zx_status_t WritePhy(uint8_t register_address, uint16_t data) TA_REQ(lock_);
zx_status_t ConfigureBulkIn(uint8_t plsr) TA_REQ(lock_);
zx_status_t ConfigureMediumMode() TA_REQ(lock_);
zx_status_t Receive(usb::Request<>& request) TA_REQ(lock_);
zx_status_t RequestAppend(usb::Request<>& request, const eth::BorrowedOperation<>& netbuf);
void ReadComplete(usb_request_t* request);
void WriteComplete(usb_request_t* request);
void InterruptComplete(usb_request_t* usb_request);
void Shutdown();
zx_status_t TwiddleRcrBit(uint16_t bit, bool on) TA_REQ(lock_);
zx_status_t SetPromisc(bool on) TA_REQ(lock_);
zx_status_t SetMulticastPromisc(bool on) TA_REQ(lock_);
void SetFilterBit(const uint8_t* mac, uint8_t* filter) TA_REQ(lock_);
zx_status_t SetMulticastFilter(int32_t n_addresses, const uint8_t* address_bytes,
size_t address_size) TA_REQ(lock_);
template <uint8_t N>
void DumpRegister(const char* name, uint8_t register_address) TA_REQ(lock_);
void DumpRegs() TA_REQ(lock_);
int InterruptThread();
uint8_t mac_addr_[ETH_MAC_SIZE] TA_GUARDED(lock_) = {};
bool online_ TA_GUARDED(lock_) = false;
bool multicast_filter_overflow_ TA_GUARDED(lock_) = false;
// pool of free USB requests
usb::RequestPool<> free_read_pool_ TA_GUARDED(lock_);
std::optional<usb::Request<>> interrupt_request_ TA_GUARDED(lock_);
// callback interface to attached ethernet layer
ddk::EthernetIfcProtocolClient ifc_ TA_GUARDED(lock_);
bool running_ TA_GUARDED(lock_) = false;
fbl::Mutex lock_;
// List of requests that have pending data. Used to buffer data if a USB transaction is in
// flight. Additional data must be appended to the tail of the list, or if that's full, a
// request from free_write_reqs must be added to the list.
usb::RequestQueue<> pending_usb_transmit_queue_ TA_GUARDED(tx_lock_);
eth::BorrowedOperationQueue<> pending_netbuf_queue_ TA_GUARDED(tx_lock_);
fbl::Mutex tx_lock_;
usb::RequestPool<> free_write_pool_;
usb::UsbDevice usb_;
zx::duration rx_endpoint_delay_ = {}; // wait time between 2 recv requests
zx::duration tx_endpoint_delay_ = {}; // wait time between 2 transmit requests
uint8_t bulk_in_address_ = 0;
uint8_t bulk_out_address_ = 0;
uint8_t interrupt_address_ = 0;
uint8_t interface_number_ = 0;
size_t parent_req_size_ = 0;
std::optional<ddk::InitTxn> init_txn_;
thrd_t interrupt_thread_ = {};
sync_completion_t interrupt_completion_;
std::thread cancel_thread_;
usb_request_complete_callback_t read_request_complete_ = {
.callback =
[](void* ctx, usb_request_t* request) {
reinterpret_cast<Asix88179Ethernet*>(ctx)->ReadComplete(request);
},
.ctx = this,
};
usb_request_complete_callback_t write_request_complete_ = {
.callback =
[](void* ctx, usb_request_t* request) {
reinterpret_cast<Asix88179Ethernet*>(ctx)->WriteComplete(request);
},
.ctx = this,
};
usb_request_complete_callback_t interrupt_request_complete_ = {
.callback =
[](void* ctx, usb_request_t* request) {
reinterpret_cast<Asix88179Ethernet*>(ctx)->InterruptComplete(request);
},
.ctx = this,
};
};
} // namespace eth
#endif // SRC_CONNECTIVITY_ETHERNET_DRIVERS_ASIX_88179_ASIX_88179_H_