diff --git a/kernel-src/include/kernel/usb.h b/kernel-src/include/kernel/usb.h index 46ca338b..eb9d6cb9 100644 --- a/kernel-src/include/kernel/usb.h +++ b/kernel-src/include/kernel/usb.h @@ -284,6 +284,19 @@ struct usb_device { usb_interface_t *interfaces; }; +static inline usb_endpoint_t *usb_find_endpoint(usb_device_t *device, uint8_t endpoint_address) { + for (uint8_t i = 0; i < device->config_desc->bNumInterfaces; ++i) { + usb_interface_t *interface = &device->interfaces[i]; + for (uint8_t j = 0; j < interface->desc->bNumEndpoints; ++j) { + usb_endpoint_t *endpoint = &interface->endpoints[j]; + if (endpoint->desc->bEndpointAddress == endpoint_address) + return endpoint; + } + } + + return NULL; +} + typedef enum { USB_XFER_FLAG_TO_DEVICE = (1 << 0), USB_XFER_FLAG_TO_HOST = (1 << 1), diff --git a/kernel-src/io/net/u80211_drv/attach.c b/kernel-src/io/net/u80211_drv/attach.c new file mode 100644 index 00000000..ad5aee27 --- /dev/null +++ b/kernel-src/io/net/u80211_drv/attach.c @@ -0,0 +1,63 @@ +#include + +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + usb_device_t *device; + usb_interface_t *interface; + work_t work; +} u80211_drv_usb_device_t; + +static work_queue_t *u80211_drv_attach_queue; + +static void u80211_drv_usb_attach_worker(void *context, size_t pending) { + (void)pending; + u80211_drv_usb_device_t *device = context; + + int status = u80211_drv_attach(device->device, device->interface); + if (status != U80211_DRV_STATUS_SUCCESS) + printf("u80211_drv: attachment failed with status %d\n", status); +} + +static int u80211_drv_usb_probe(usb_device_t *device, usb_interface_t *interface) { + int status = u80211_drv_probe(device, interface); + if (status == U80211_DRV_STATUS_SUCCESS) + return USB_DRIVER_SCORE_EXACT_MATCH; + + if (status != U80211_DRV_STATUS_NO_MATCH) + printf("u80211_drv: probe failed with status %d\n", status); + + return USB_DRIVER_SCORE_NONE; +} + +static int u80211_drv_usb_attach(usb_device_t *device, usb_interface_t *interface) { + u80211_drv_usb_device_t *usb_device = alloc(sizeof(*usb_device)); + if (usb_device == NULL) + return ENOMEM; + + usb_device->device = device; + usb_device->interface = interface; + WORK_INIT(&usb_device->work, u80211_drv_usb_attach_worker, usb_device); + interface->driver_data = usb_device; + work_enqueue(u80211_drv_attach_queue, &usb_device->work); + return 0; +} + +DEFINE_USB_CLASS_DRIVER(u80211_drv, + .name = "u80211 USB NIC", + .probe = u80211_drv_usb_probe, + .attach = u80211_drv_usb_attach +) + +static void u80211_drv_usb_init(void) { + u80211_drv_attach_queue = work_queue_create("u80211_drv", 1, IPL_USB); + __assert(u80211_drv_attach_queue); +} + +INIT_ROUTINE_DEFINE(u80211_drv_usb, INIT_ROUTINE_FLAGS_NONE, u80211_drv_usb_init, work_queue); diff --git a/kernel-src/io/net/u80211_drv/include/u80211_drv/80211.h b/kernel-src/io/net/u80211_drv/include/u80211_drv/80211.h new file mode 100644 index 00000000..ce73de79 --- /dev/null +++ b/kernel-src/io/net/u80211_drv/include/u80211_drv/80211.h @@ -0,0 +1,37 @@ +#ifndef U80211_DRV_80211_H +#define U80211_DRV_80211_H + +#include + +#include + +#define U80211_DRV_80211_FRAME_TYPE_MANAGEMENT 0 +#define U80211_DRV_80211_FRAME_TYPE_DATA 2 + +#define U80211_DRV_80211_FRAME_DATA_QOS_BIT 0x8 +#define U80211_DRV_80211_HEADER_MINIMUM_SIZE 24 +#define U80211_DRV_80211_MAX_MPDU_SIZE 2352 + +static inline uint16_t u80211_drv_80211_frame_control(const void *frame) { + return u80211_drv_deserialize_le16(frame); +} + +static inline uint8_t u80211_drv_80211_frame_type(uint16_t frame_control) { + return (frame_control >> 2) & 0x3; +} + +static inline uint8_t u80211_drv_80211_frame_subtype(uint16_t frame_control) { + return (frame_control >> 4) & 0xf; +} + +static inline const uint8_t *u80211_drv_80211_receiver_address(const void *frame) { + const uint8_t *frame_bytes = frame; + return frame_bytes + 4; +} + +static inline uint16_t u80211_drv_80211_sequence_number(const void *frame) { + const uint8_t *frame_bytes = frame; + return u80211_drv_deserialize_le16(frame_bytes + 22) >> 4; +} + +#endif diff --git a/kernel-src/io/net/u80211_drv/include/u80211_drv/drv_init.h b/kernel-src/io/net/u80211_drv/include/u80211_drv/drv_init.h new file mode 100644 index 00000000..e0637fcd --- /dev/null +++ b/kernel-src/io/net/u80211_drv/include/u80211_drv/drv_init.h @@ -0,0 +1,8 @@ +#ifndef U80211_DRV_DRV_INIT_H +#define U80211_DRV_DRV_INIT_H + +#include + +int u80211_drv_rtl8188eu_init(u80211_drv_device_handle_t device, u80211_drv_interface_handle_t interface); + +#endif diff --git a/kernel-src/io/net/u80211_drv/include/u80211_drv/kernel_interface.h b/kernel-src/io/net/u80211_drv/include/u80211_drv/kernel_interface.h new file mode 100644 index 00000000..df5cc636 --- /dev/null +++ b/kernel-src/io/net/u80211_drv/include/u80211_drv/kernel_interface.h @@ -0,0 +1,171 @@ +#ifndef U80211_DRV_KERNEL_INTERFACE_H +#define U80211_DRV_KERNEL_INTERFACE_H + +#include +#include + +// opaque handles supplied by the kernel integration +// the driver only stores and passes these handles back to the integration +typedef void *u80211_drv_device_handle_t; +typedef void *u80211_drv_interface_handle_t; +typedef void *u80211_drv_transfer_handle_t; +typedef void *u80211_drv_network_device_handle_t; + +typedef void (*u80211_drv_kernel_transfer_callback_t)(void *context, int status, size_t transferred_size); + +// usb device descriptor fields used to match a driver +typedef struct { + uint16_t vendor_id; + uint16_t product_id; +} u80211_drv_device_descriptor_t; + +// usb interface descriptor fields used to match a driver and discover its endpoints +typedef struct { + uint8_t number; + uint8_t class_code; + uint8_t subclass; + uint8_t protocol; + uint8_t endpoint_count; +} u80211_drv_interface_descriptor_t; + +// usb endpoint descriptor fields required by a driver +typedef struct { + uint8_t address; + uint8_t attributes; + uint16_t maximum_packet_size; + uint8_t interval; +} u80211_drv_endpoint_descriptor_t; + +#define U80211_DRV_DEVICE_MAC_ADDRESS_LEN 6 +#define U80211_DRV_DEVICE_RATE_BITMAP_LEN 16 + +// radio properties published once initialization has completed +typedef struct { + uint8_t mac_address[U80211_DRV_DEVICE_MAC_ADDRESS_LEN]; + // bit N represents a supported rate of N * 500 kbit/s + uint8_t rate_bitmap[U80211_DRV_DEVICE_RATE_BITMAP_LEN]; +} u80211_drv_device_metadata_t; + +// cipher values used by key installation and transmission +#define U80211_DRV_CIPHER_NONE -1 +#define U80211_DRV_CIPHER_CCMP 0 +#define U80211_DRV_CIPHER_TKIP 1 +#define U80211_DRV_CIPHER_WEP40 2 +#define U80211_DRV_CIPHER_WEP104 3 + +#define U80211_DRV_KEY_PAIRWISE (1u << 0) +#define U80211_DRV_KEY_GROUP (1u << 1) +#define U80211_DRV_KEY_RX (1u << 2) +#define U80211_DRV_KEY_TX (1u << 3) + +// key data passed to set_key +typedef struct { + int cipher; + uint8_t index; + uint8_t peer[U80211_DRV_DEVICE_MAC_ADDRESS_LEN]; + const uint8_t *key; + size_t key_len; + uint32_t flags; +} u80211_drv_key_t; + +// per-packet encryption selection +// key is the installed key index or -1 when no key is selected +// cipher is one of U80211_DRV_CIPHER_* +typedef struct { + int key; + int cipher; +} u80211_drv_transmit_options_t; + +// operations implemented by a hardware driver and published through u80211_drv_device_ready() +// unless otherwise stated operations return a U80211_DRV_STATUS_* value +typedef struct { + // allocates a buffer of 'size' bytes + // on success '*buffer' points at the start of the writable 802.11 frame region + int (*allocate_tx_buffer)(size_t size, void **buffer); + void (*free_tx_buffer)(void *buffer); + // transmits the bytes and consumes buffer including on failure + int (*transmit)(void *device, void *buffer, size_t size, size_t current_offset, const u80211_drv_transmit_options_t *options); + // sets the rf channel number the device will rx/tx on + int (*set_channel)(void *device, uint8_t channel); + // adds an encryption key + int (*set_key)(void *device, const u80211_drv_key_t *key); + // deletes an encryption ke + int (*del_key)(void *device, uint8_t index); +} u80211_drv_device_ops_t; + +// values used to control usb transfers +#define U80211_DRV_KERNEL_XFER_OUT 0x00 +#define U80211_DRV_KERNEL_XFER_IN 0x80 +#define U80211_DRV_KERNEL_XFER_DIRECTION_MASK 0x80 + +#define U80211_DRV_KERNEL_ENDPOINT_TRANSFER_TYPE_MASK 0x03 +#define U80211_DRV_KERNEL_ENDPOINT_TRANSFER_TYPE_BULK 0x02 + +#define U80211_DRV_KERNEL_XFER_REQUEST_TYPE_STANDARD 0x00 +#define U80211_DRV_KERNEL_XFER_REQUEST_TYPE_CLASS 0x20 +#define U80211_DRV_KERNEL_XFER_REQUEST_TYPE_VENDOR 0x40 +#define U80211_DRV_KERNEL_XFER_REQUEST_TYPE_RESERVED 0x60 +#define U80211_DRV_KERNEL_XFER_REQUEST_TYPE_MASK 0x60 + +#define U80211_DRV_KERNEL_XFER_RECIPIENT_DEVICE 0x00 +#define U80211_DRV_KERNEL_XFER_RECIPIENT_INTERFACE 0x01 +#define U80211_DRV_KERNEL_XFER_RECIPIENT_ENDPOINT 0x02 +#define U80211_DRV_KERNEL_XFER_RECIPIENT_OTHER 0x03 +#define U80211_DRV_KERNEL_XFER_RECIPIENT_MASK 0x1f + +#define U80211_DRV_KERNEL_PRINT_LEVEL_INFO 0 +#define U80211_DRV_KERNEL_PRINT_LEVEL_WARN 1 +#define U80211_DRV_KERNEL_PRINT_LEVEL_ERROR 2 + +// allocates 'size' bytes of memory +// return NULL on allocation failure +void *u80211_drv_kernel_allocate(size_t size); + +// frees the kernel memory referenced by 'memory' +// 'memory' will never be NULL +void u80211_drv_kernel_free(void *memory); + +// requests for firmware to be loaded +// invokes callback once firmware is available +// the callback must not be invoked on failure +// 'firmware_data' only needs to be valid for the duration of the callback +typedef void (*u80211_drv_kernel_firmware_callback_t)(void *context, const void *firmware_data, size_t firmware_size); +int u80211_drv_kernel_get_firmware(const char *name, u80211_drv_kernel_firmware_callback_t callback, void *context); + +// these functions return usb descriptors into the specified buffers +int u80211_drv_kernel_get_device_descriptor(u80211_drv_device_handle_t device, u80211_drv_device_descriptor_t *descriptor); +int u80211_drv_kernel_get_interface_descriptor(u80211_drv_interface_handle_t interface, u80211_drv_interface_descriptor_t *descriptor); +int u80211_drv_kernel_get_endpoints(u80211_drv_interface_handle_t interface, u80211_drv_endpoint_descriptor_t *endpoints, size_t endpoint_count); + +// synchronous usb control transfers with a timeout in milliseconds +// 'flags' combines U80211_DRV_KERNEL_XFER_* values into the usb control request type +int u80211_drv_kernel_submit_control_xfer_and_wait(u80211_drv_device_handle_t device, uint8_t flags, uint8_t request, uint16_t value, uint16_t index, void *buf, uint16_t buffer_size, size_t *transferred_size, unsigned int timeout); + +// synchronous usb bulk transfers with a timeout in milliseconds +int u80211_drv_kernel_submit_bulk_xfer_and_wait(u80211_drv_device_handle_t device, uint8_t endpoint_address, void *buf, size_t buffer_size, size_t *transferred_size, unsigned int timeout); + +// allocates a reusable asynchronous bulk transfer +// 'buffer' and 'context' must stay valid across submissions and callbacks +// callback receives a U80211_DRV_STATUS_* value and zero transferred_size on failure +// a completed transfer may be submitted again from its callback +int u80211_drv_kernel_allocate_bulk_xfer(u80211_drv_device_handle_t device, uint8_t endpoint_address, void *buffer, size_t buffer_size, u80211_drv_kernel_transfer_callback_t callback, void *context, u80211_drv_transfer_handle_t *transfer); + +// starts an asynchronous transfer +// submitting one that is already active must return U80211_DRV_STATUS_INVALID_ARGUMENT +int u80211_drv_kernel_submit_xfer(u80211_drv_transfer_handle_t transfer); + +// busy-waits for at least 'microseconds' before returning +void u80211_drv_kernel_stall_us(unsigned int microseconds); + +// writes one complete message at the requested U80211_DRV_KERNEL_PRINT_LEVEL_* +void u80211_drv_kernel_print(int level, const char *msg); + +// publishes an initialized radio to the kernel integration +// 'network_device' receives the handle used for received packets +int u80211_drv_device_ready(void *device, const u80211_drv_device_metadata_t *metadata, const u80211_drv_device_ops_t *ops, u80211_drv_network_device_handle_t *network_device); + +// delivers one 802.11 packet +// might be called from an interrupt context +void u80211_drv_packet_received(u80211_drv_network_device_handle_t device, void *packet, size_t packet_size); + +#endif diff --git a/kernel-src/io/net/u80211_drv/include/u80211_drv/rtl8188eu.h b/kernel-src/io/net/u80211_drv/include/u80211_drv/rtl8188eu.h new file mode 100644 index 00000000..24f443eb --- /dev/null +++ b/kernel-src/io/net/u80211_drv/include/u80211_drv/rtl8188eu.h @@ -0,0 +1,389 @@ +#ifndef U80211_DRV_RTL8188EU_H +#define U80211_DRV_RTL8188EU_H + +#include +#include +#include + +#include + +#define U80211_DRV_RTL8188EU_REG_SYS_ISO_CTRL 0x0000 +#define U80211_DRV_RTL8188EU_REG_SYS_ISO_CTRL_PWC_EV12V (1u << 15) + +#define U80211_DRV_RTL8188EU_REG_SYS_FUNC 0x0002 +#define U80211_DRV_RTL8188EU_REG_SYS_FUNC_BBRSTB (1u << 0) +#define U80211_DRV_RTL8188EU_REG_SYS_FUNC_BB_GLB_RSTN (1u << 1) +#define U80211_DRV_RTL8188EU_REG_SYS_FUNC_USBA (1u << 2) +#define U80211_DRV_RTL8188EU_REG_SYS_FUNC_USBD (1u << 4) +#define U80211_DRV_RTL8188EU_REG_SYS_FUNC_CPUEN (1u << 10) +#define U80211_DRV_RTL8188EU_REG_SYS_FUNC_ELDR (1u << 12) +#define U80211_DRV_RTL8188EU_REG_SYS_FUNC_DIO_RF (1u << 13) + +#define U80211_DRV_RTL8188EU_REG_APS_FSMCO 0x0004 +#define U80211_DRV_RTL8188EU_REG_APS_FSMCO_MAC_ENABLE (1u << 8) +#define U80211_DRV_RTL8188EU_REG_APS_FSMCO_HW_SUSPEND (1u << 11) +#define U80211_DRV_RTL8188EU_REG_APS_FSMCO_PCIE (1u << 12) +#define U80211_DRV_RTL8188EU_REG_APS_FSMCO_HW_POWERDOWN (1u << 15) +#define U80211_DRV_RTL8188EU_REG_APS_FSMCO_POWER_READY (1u << 17) + +#define U80211_DRV_RTL8188EU_REG_SYS_CLKR 0x0008 +#define U80211_DRV_RTL8188EU_REG_SYS_CLKR_ANA8M (1u << 1) +#define U80211_DRV_RTL8188EU_REG_SYS_CLKR_LOADER_ENABLE (1u << 5) + +#define U80211_DRV_RTL8188EU_REG_9346CR 0x000a +#define U80211_DRV_RTL8188EU_REG_9346CR_EEPROM_BOOT (1u << 4) +#define U80211_DRV_RTL8188EU_REG_9346CR_EEPROM_ENABLE (1u << 5) + +#define U80211_DRV_RTL8188EU_REG_RSV_CTRL 0x001c +#define U80211_DRV_RTL8188EU_REG_RSV_CTRL_WLOCK_00 (1u << 1) +#define U80211_DRV_RTL8188EU_REG_RSV_CTRL_MCU_RST (1u << 11) + +#define U80211_DRV_RTL8188EU_REG_RF_CTRL 0x001f +#define U80211_DRV_RTL8188EU_REG_RF_CTRL_ENABLE (1u << 0) +#define U80211_DRV_RTL8188EU_REG_RF_CTRL_RSTB (1u << 1) +#define U80211_DRV_RTL8188EU_REG_RF_CTRL_SDMRSTB (1u << 2) + +#define U80211_DRV_RTL8188EU_REG_LPLDO_CTRL 0x0023 +#define U80211_DRV_RTL8188EU_REG_LPLDO_CTRL_SLEEP (1u << 4) + +#define U80211_DRV_RTL8188EU_REG_AFE_XTAL_CTRL 0x0024 +#define U80211_DRV_RTL8188EU_REG_AFE_XTAL_CTRL_SCHMITT_TRIGGER (1u << 23) +#define U80211_DRV_RTL8188EU_REG_AFE_XTAL_CTRL_ADDRESS_MASK 0x007ff800 +#define U80211_DRV_RTL8188EU_REG_AFE_XTAL_CTRL_ADDRESS_SHIFT 11 + +#define U80211_DRV_RTL8188EU_REG_EFUSE_CTRL 0x0030 +#define U80211_DRV_RTL8188EU_REG_EFUSE_CTRL_READ_READY (1u << 31) + +#define U80211_DRV_RTL8188EU_REG_LEDCFG2 0x004e +#define U80211_DRV_RTL8188EU_REG_LEDCFG2_HW_LED_CONTROL (1u << 1) +#define U80211_DRV_RTL8188EU_REG_LEDCFG2_SW_LED_DISABLE (1u << 3) +#define U80211_DRV_RTL8188EU_REG_LEDCFG2_HW_LED_ENABLE (1u << 5) + +#define U80211_DRV_RTL8188EU_REG_EFUSE_ACCESS 0x00cf +#define U80211_DRV_RTL8188EU_EFUSE_ACCESS_ENABLE 0x69 +#define U80211_DRV_RTL8188EU_EFUSE_ACCESS_DISABLE 0x00 + +#define U80211_DRV_RTL8188EU_REG_MCUFWDL 0x0080 +#define U80211_DRV_RTL8188EU_REG_MCUFWDL_ENABLE (1u << 0) +#define U80211_DRV_RTL8188EU_REG_MCUFWDL_READY (1u << 1) +#define U80211_DRV_RTL8188EU_REG_MCUFWDL_CHECKSUM_REPORT (1u << 2) +#define U80211_DRV_RTL8188EU_REG_MCUFWDL_WINTINI_READY (1u << 6) +#define U80211_DRV_RTL8188EU_REG_MCUFWDL_RAM_DOWNLOAD_SELECT (1u << 7) +#define U80211_DRV_RTL8188EU_REG_MCUFWDL_PAGE_MASK (7u << 16) +#define U80211_DRV_RTL8188EU_REG_MCUFWDL_ROM_DOWNLOAD_LENGTH (1u << 19) + +#define U80211_DRV_RTL8188EU_FIRMWARE_START_ADDRESS 0x1000 +#define U80211_DRV_RTL8188EU_FIRMWARE_PAGE_SIZE 4096 +#define U80211_DRV_RTL8188EU_FIRMWARE_HEADER_SIZE 32 + +#define U80211_DRV_RTL8188EU_EFUSE_PHYSICAL_LEN 512 +#define U80211_DRV_RTL8188EU_EFUSE_MAP_LEN 512 +#define U80211_DRV_RTL8188EU_EFUSE_WORDS_PER_SECTION 4 +#define U80211_DRV_RTL8188EU_EFUSE_RTL_ID 0x8129 +#define U80211_DRV_RTL8188EU_MAC_ADDRESS_LEN 6 +#define U80211_DRV_RTL8188EU_CCK_TX_POWER_BASE_INDEX_COUNT 6 +#define U80211_DRV_RTL8188EU_HT40_1S_TX_POWER_BASE_INDEX_COUNT 5 + +#define U80211_DRV_RTL8188EU_REG_SYS_CFG 0xf0 +#define U80211_DRV_RTL8188EU_REG_SYS_CFG_TRP_VAUX_EN (1u << 23) +#define U80211_DRV_RTL8188EU_REG_SYS_CFG_VER(value) (((value) >> 12) & 0xfu) + +#define U80211_DRV_RTL8188EU_REG_CR 0x0100 +#define U80211_DRV_RTL8188EU_REG_CR_HCI_TXDMA_ENABLE (1u << 0) +#define U80211_DRV_RTL8188EU_REG_CR_HCI_RXDMA_ENABLE (1u << 1) +#define U80211_DRV_RTL8188EU_REG_CR_TXDMA_ENABLE (1u << 2) +#define U80211_DRV_RTL8188EU_REG_CR_RXDMA_ENABLE (1u << 3) +#define U80211_DRV_RTL8188EU_REG_CR_PROTOCOL_ENABLE (1u << 4) +#define U80211_DRV_RTL8188EU_REG_CR_SCHEDULE_ENABLE (1u << 5) +#define U80211_DRV_RTL8188EU_REG_CR_MAC_TX_ENABLE (1u << 6) +#define U80211_DRV_RTL8188EU_REG_CR_MAC_RX_ENABLE (1u << 7) +#define U80211_DRV_RTL8188EU_REG_CR_SECURITY_ENABLE (1u << 9) +#define U80211_DRV_RTL8188EU_REG_CR_CALTIMER_ENABLE (1u << 10) + +#define U80211_DRV_RTL8188EU_REG_MSR 0x0102 +#define U80211_DRV_RTL8188EU_REG_MSR_NETWORK_TYPE_MASK 0x03 + +#define U80211_DRV_RTL8188EU_REG_PBP 0x0104 +#define U80211_DRV_RTL8188EU_REG_PBP_128_BYTES 0x11 + +#define U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL 0x010c +#define U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL_VO_SHIFT 4 +#define U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL_VI_SHIFT 6 +#define U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL_BE_SHIFT 8 +#define U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL_BK_SHIFT 10 +#define U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL_MG_SHIFT 12 +#define U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL_HI_SHIFT 14 +#define U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL_LOW_CONTROL_MASK 0x0007 +#define U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL_RXDMA_AGG_ENABLE (1u << 2) + +#define U80211_DRV_RTL8188EU_REG_TRXFF_BNDY 0x0114 +#define U80211_DRV_RTL8188EU_RX_FIFO_BOUNDARY 0x25ff + +#define U80211_DRV_RTL8188EU_REG_LLT_INIT 0x01e0 +#define U80211_DRV_RTL8188EU_REG_LLT_INIT_OP_WRITE (1u << 30) +#define U80211_DRV_RTL8188EU_REG_LLT_INIT_OP_MASK (3u << 30) +#define U80211_DRV_RTL8188EU_LLT_LAST_ENTRY 0xaf +#define U80211_DRV_RTL8188EU_LLT_END 0xff + +#define U80211_DRV_RTL8188EU_REG_RQPN 0x0200 +#define U80211_DRV_RTL8188EU_REG_RQPN_HI_SHIFT 0 +#define U80211_DRV_RTL8188EU_REG_RQPN_LO_SHIFT 8 +#define U80211_DRV_RTL8188EU_REG_RQPN_PUB_SHIFT 16 +#define U80211_DRV_RTL8188EU_REG_RQPN_LOAD (1u << 31) + +#define U80211_DRV_RTL8188EU_REG_RQPN_NPQ 0x0214 +#define U80211_DRV_RTL8188EU_REG_RQPN_NPQ_SHIFT 0 + +#define U80211_DRV_RTL8188EU_REG_TDECTRL 0x0208 + +#define U80211_DRV_RTL8188EU_REG_FWHW_TXQ_CTRL 0x0420 +#define U80211_DRV_RTL8188EU_REG_FWHW_TXQ_CTRL_AMPDU_RTY_NEW (1u << 7) +#define U80211_DRV_RTL8188EU_REG_HWSEQ_CTRL 0x0423 + +#define U80211_DRV_RTL8188EU_REG_SPEC_SIFS 0x0428 +#define U80211_DRV_RTL8188EU_REG_RL 0x042a + +#define U80211_DRV_RTL8188EU_REG_RRSR 0x0440 +#define U80211_DRV_RTL8188EU_REG_RRSR_RATE_MASK 0x000fffff +#define U80211_DRV_RTL8188EU_REG_RRSR_RATE_CCK_ONLY_1M 0x000ffff1 + +#define U80211_DRV_RTL8188EU_REG_TXPKTBUF_BCNQ_BDNY 0x0424 +#define U80211_DRV_RTL8188EU_REG_TXPKTBUF_MGQ_BDNY 0x0425 +#define U80211_DRV_RTL8188EU_REG_TXPKTBUF_WMAC_LBK_BF_HD 0x045d + +#define U80211_DRV_RTL8188EU_REG_MAX_AGGR_NUM 0x04ca +#define U80211_DRV_RTL8188EU_REG_MAX_AGGR_NUM_8188EU 0x07 + +#define U80211_DRV_RTL8188EU_REG_EDCA_VO 0x0500 +#define U80211_DRV_RTL8188EU_REG_EDCA_VI 0x0504 +#define U80211_DRV_RTL8188EU_REG_EDCA_BE 0x0508 +#define U80211_DRV_RTL8188EU_REG_EDCA_BK 0x050c + +#define U80211_DRV_RTL8188EU_REG_BCNTCFG 0x0510 +#define U80211_DRV_RTL8188EU_REG_SIFS_CCK 0x0514 +#define U80211_DRV_RTL8188EU_REG_SIFS_OFDM 0x0516 + +#define U80211_DRV_RTL8188EU_REG_TBTT_PROHIBIT 0x0540 +#define U80211_DRV_RTL8188EU_REG_BCN_CTRL 0x0550 +#define U80211_DRV_RTL8188EU_REG_DRVERLYINT 0x0558 +#define U80211_DRV_RTL8188EU_REG_BCNDMATIM 0x0559 + +#define U80211_DRV_RTL8188EU_REG_BWOPMODE 0x0603 +#define U80211_DRV_RTL8188EU_REG_BWOPMODE_20MHZ (1u << 2) + +#define U80211_DRV_RTL8188EU_REG_RCR 0x0608 +#define U80211_DRV_RTL8188EU_REG_RCR_AAP (1u << 0) +#define U80211_DRV_RTL8188EU_REG_RCR_APM (1u << 1) +#define U80211_DRV_RTL8188EU_REG_RCR_AM (1u << 2) +#define U80211_DRV_RTL8188EU_REG_RCR_AB (1u << 3) +#define U80211_DRV_RTL8188EU_REG_RCR_AMF (1u << 13) +#define U80211_DRV_RTL8188EU_REG_RCR_HTC_LOC_CTRL (1u << 14) +#define U80211_DRV_RTL8188EU_REG_RCR_APP_PHYSTS (1u << 28) +#define U80211_DRV_RTL8188EU_REG_RCR_APP_ICV (1u << 29) +#define U80211_DRV_RTL8188EU_REG_RCR_APP_MIC (1u << 30) + +#define U80211_DRV_RTL8188EU_REG_RX_DRVINFO_SZ 0x060f +#define U80211_DRV_RTL8188EU_RX_DRVINFO_SZ 4 + +#define U80211_DRV_RTL8188EU_REG_MACID 0x0610 +#define U80211_DRV_RTL8188EU_REG_MAR 0x0620 + +#define U80211_DRV_RTL8188EU_REG_MAC_SPEC_SIFS 0x063a +#define U80211_DRV_RTL8188EU_REG_RESP_SIFS_CCK 0x063c +#define U80211_DRV_RTL8188EU_REG_RESP_SIFS_OFDM 0x063e +#define U80211_DRV_RTL8188EU_REG_ACKTO 0x0640 + +#define U80211_DRV_RTL8188EU_REG_CAMCMD 0x0670 +#define U80211_DRV_RTL8188EU_REG_CAMWRITE 0x0674 +#define U80211_DRV_RTL8188EU_REG_CAMCMD_WRITE (1u << 16) +#define U80211_DRV_RTL8188EU_REG_CAMCMD_CLR (1u << 30) +#define U80211_DRV_RTL8188EU_REG_CAMCMD_POLLING (1u << 31) + +#define U80211_DRV_RTL8188EU_CAM_ENTRY_WORD_COUNT 8 +#define U80211_DRV_RTL8188EU_CAM_CTL0_KEY_ID_MASK 0x03 +#define U80211_DRV_RTL8188EU_CAM_CTL0_ALGORITHM_SHIFT 2 +#define U80211_DRV_RTL8188EU_CAM_CTL0_GROUP (1u << 6) +#define U80211_DRV_RTL8188EU_CAM_CTL0_VALID (1u << 15) +#define U80211_DRV_RTL8188EU_CAM_ALGORITHM_WEP40 1 +#define U80211_DRV_RTL8188EU_CAM_ALGORITHM_TKIP 2 +#define U80211_DRV_RTL8188EU_CAM_ALGORITHM_CCMP 4 +#define U80211_DRV_RTL8188EU_CAM_ALGORITHM_WEP104 5 + +#define U80211_DRV_RTL8188EU_REG_SECCFG 0x0680 +#define U80211_DRV_RTL8188EU_REG_SECCFG_TXUCKEY_DEF (1u << 0) +#define U80211_DRV_RTL8188EU_REG_SECCFG_RXUCKEY_DEF (1u << 1) +#define U80211_DRV_RTL8188EU_REG_SECCFG_TXENC_ENABLE (1u << 2) +#define U80211_DRV_RTL8188EU_REG_SECCFG_RXENC_ENABLE (1u << 3) +#define U80211_DRV_RTL8188EU_REG_SECCFG_TXBCKEY_DEF (1u << 6) +#define U80211_DRV_RTL8188EU_REG_SECCFG_RXBCKEY_DEF (1u << 7) + +#define U80211_DRV_RTL8188EU_REG_RXFLTMAP0 0x06a0 +#define U80211_DRV_RTL8188EU_REG_RXFLTMAP1 0x06a2 +#define U80211_DRV_RTL8188EU_REG_RXFLTMAP2 0x06a4 + +#define U80211_DRV_RTL8188EU_REG_FPGA0_RFMOD 0x0800 +#define U80211_DRV_RTL8188EU_REG_FPGA_RFMOD_40MHZ (1u << 0) +#define U80211_DRV_RTL8188EU_REG_FPGA0_RFMOD_CCK_ENABLE (1u << 24) +#define U80211_DRV_RTL8188EU_REG_FPGA0_RFMOD_OFDM_ENABLE (1u << 25) + +#define U80211_DRV_RTL8188EU_REG_HSSI_PARAM1_A 0x0820 +#define U80211_DRV_RTL8188EU_REG_HSSI_PARAM1_PI (1u << 8) + +#define U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_A 0x0824 +#define U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_CCK_HIGH_POWER (1u << 9) +#define U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_ADDRESS_LENGTH (1u << 10) +#define U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_DATA_LENGTH (1u << 11) +#define U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_READ_ADDRESS_MASK 0x7f800000 +#define U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_READ_ADDRESS_SHIFT 23 +#define U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_READ_EDGE (1u << 31) + +#define U80211_DRV_RTL8188EU_REG_LSSI_PARAM_A 0x0840 +#define U80211_DRV_RTL8188EU_REG_LSSI_PARAM_ADDRESS_SHIFT 20 +#define U80211_DRV_RTL8188EU_REG_LSSI_PARAM_DATA_MASK 0x000fffff + +#define U80211_DRV_RTL8188EU_REG_RF_IFACE_OE_A 0x0860 +#define U80211_DRV_RTL8188EU_REG_RF_IFACE_OE_RF_ENV (1u << 4) +#define U80211_DRV_RTL8188EU_REG_RF_IFACE_OE_RF_ENV_ENABLE (1u << 20) + +#define U80211_DRV_RTL8188EU_REG_TXAGC_B_CCK11_A_CCK2_11 0x086c + +#define U80211_DRV_RTL8188EU_REG_RF_IFACE_SW_A 0x0870 +#define U80211_DRV_RTL8188EU_REG_RF_IFACE_SW_RF_ENV (1u << 4) + +#define U80211_DRV_RTL8188EU_REG_LSSI_READBACK_A 0x08a0 +#define U80211_DRV_RTL8188EU_REG_HSPI_READBACK_A 0x08b8 +#define U80211_DRV_RTL8188EU_RF_READBACK_MASK 0x000fffff +#define U80211_DRV_RTL8188EU_RF_CHNLBW 0x18 +#define U80211_DRV_RTL8188EU_RF_CHNLBW_CHANNEL_BW_MASK 0x00000fff +#define U80211_DRV_RTL8188EU_RF_CHNLBW_BW20 0x00000c00 + +#define U80211_DRV_RTL8188EU_REG_FPGA1_RFMOD 0x0900 + +#define U80211_DRV_RTL8188EU_REG_OFDM0_AGCCORE1 0x0c50 +#define U80211_DRV_RTL8188EU_REG_OFDM0_AGCCORE1_LATCH 0x69553422 +#define U80211_DRV_RTL8188EU_REG_OFDM0_AGCCORE1_FINAL 0x69553420 + +#define U80211_DRV_RTL8188EU_REG_OFDM0_AGCRSSITABLE 0x0c78 + +#define U80211_DRV_RTL8188EU_REG_TXAGC_A_RATE18_06 0x0e00 +#define U80211_DRV_RTL8188EU_REG_TXAGC_A_RATE54_24 0x0e04 +#define U80211_DRV_RTL8188EU_REG_TXAGC_A_CCK1 0x0e08 +#define U80211_DRV_RTL8188EU_REG_TXAGC_A_MCS03 0x0e10 +#define U80211_DRV_RTL8188EU_REG_TXAGC_A_MCS07 0x0e14 +#define U80211_DRV_RTL8188EU_REG_TXAGC_A_CCK1_MASK 0x0000ff00 + +#define U80211_DRV_RTL8188EU_REG_USB_SPECIAL_OPTION 0xfe55 +#define U80211_DRV_RTL8188EU_REG_USB_SPECIAL_OPTION_AGG_ENABLE (1u << 3) + +#define U80211_DRV_RTL8188EU_TX_TOTAL_PAGE_NUM 0xa9 +#define U80211_DRV_RTL8188EU_TX_PAGE_NUM_HI_PQ 0x29 +#define U80211_DRV_RTL8188EU_TX_PAGE_NUM_LO_PQ 0x1c +#define U80211_DRV_RTL8188EU_TX_PAGE_NUM_NORM_PQ 0x1c + +#define U80211_DRV_RTL8188EU_TRXDMA_QUEUE_LOW 1 +#define U80211_DRV_RTL8188EU_TRXDMA_QUEUE_NORMAL 2 +#define U80211_DRV_RTL8188EU_TRXDMA_QUEUE_HIGH 3 + +#define U80211_DRV_RTL8188EU_RX_SLOT_COUNT 4 + +typedef enum { + U80211_DRV_RTL8188EU_ACCESS_CATEGORY_VO, + U80211_DRV_RTL8188EU_ACCESS_CATEGORY_VI, + U80211_DRV_RTL8188EU_ACCESS_CATEGORY_BE, + U80211_DRV_RTL8188EU_ACCESS_CATEGORY_BK, +} u80211_drv_rtl8188eu_access_category_t; + +typedef struct { + uint8_t aifsn; + uint8_t ecwmin; + uint8_t ecwmax; + uint16_t txop; + uint8_t slot_time; +} u80211_drv_rtl8188eu_edca_params_t; + +typedef struct { + uint16_t rtl_id; + uint8_t mac_address[U80211_DRV_RTL8188EU_MAC_ADDRESS_LEN]; + uint8_t cck_tx_power_base_indexes[U80211_DRV_RTL8188EU_CCK_TX_POWER_BASE_INDEX_COUNT]; + uint8_t ht40_1s_tx_power_base_indexes[U80211_DRV_RTL8188EU_HT40_1S_TX_POWER_BASE_INDEX_COUNT]; + uint8_t ht20_ofdm_tx_power_diff; + uint8_t xtal_k; +} u80211_drv_rtl8188eu_efuse_t; + +typedef struct u80211_drv_rtl8188eu u80211_drv_rtl8188eu_t; + +typedef struct { + u80211_drv_rtl8188eu_t *rtl8188eu; + void *buffer; + u80211_drv_transfer_handle_t transfer; +} u80211_drv_rtl8188eu_rx_slot_t; + +struct u80211_drv_rtl8188eu { + u80211_drv_device_handle_t device; + u80211_drv_interface_handle_t interface; + u80211_drv_network_device_handle_t network_device; + uint8_t rx_endpoint; + uint8_t bulk_out_endpoint_count; + uint8_t tx_endpoint_high; + uint8_t tx_endpoint_normal; + uint8_t tx_endpoint_low; + bool cck_high_power; + uint32_t rf_chnlbw; + u80211_drv_rtl8188eu_efuse_t efuse; + u80211_drv_rtl8188eu_rx_slot_t rx_slots[U80211_DRV_RTL8188EU_RX_SLOT_COUNT]; +}; + +int u80211_drv_rtl8188eu_efuse_prepare(u80211_drv_device_handle_t device); +int u80211_drv_rtl8188eu_efuse_finish(u80211_drv_device_handle_t device); +int u80211_drv_rtl8188eu_read_efuse(u80211_drv_device_handle_t device, uint8_t efuse_map[U80211_DRV_RTL8188EU_EFUSE_MAP_LEN]); +int u80211_drv_rtl8188eu_parse_efuse(const uint8_t efuse_map[U80211_DRV_RTL8188EU_EFUSE_MAP_LEN], u80211_drv_rtl8188eu_efuse_t *result); + +int u80211_drv_rtl8188eu_power_active(u80211_drv_device_handle_t device); + +int u80211_drv_rtl8188eu_mac_enable_infrastructure(u80211_drv_device_handle_t device); +int u80211_drv_rtl8188eu_mac_enable_tx_rx(u80211_drv_device_handle_t device); +int u80211_drv_rtl8188eu_mac_disable_rx_aggregation(u80211_drv_device_handle_t device); +int u80211_drv_rtl8188eu_mac_configure_tx_queues(u80211_drv_device_handle_t device, uint8_t bulk_out_endpoint_count); +int u80211_drv_rtl8188eu_mac_configure_rx_fifo_boundary(u80211_drv_device_handle_t device); +int u80211_drv_rtl8188eu_mac_configure_packet_buffer(u80211_drv_device_handle_t device); +int u80211_drv_rtl8188eu_mac_initialize_llt(u80211_drv_device_handle_t device); +int u80211_drv_rtl8188eu_mac_configure_wmac(u80211_drv_rtl8188eu_t *rtl8188eu); +int u80211_drv_rtl8188eu_mac_set_edca(u80211_drv_device_handle_t device, u80211_drv_rtl8188eu_access_category_t access_category, u80211_drv_rtl8188eu_edca_params_t params); +int u80211_drv_rtl8188eu_mac_configure_timing(u80211_drv_device_handle_t device); +int u80211_drv_rtl8188eu_mac_configure_hardware_offloads(u80211_drv_device_handle_t device); +int u80211_drv_rtl8188eu_mac_load_table(u80211_drv_device_handle_t device); + +int u80211_drv_rtl8188eu_bb_enable(u80211_drv_device_handle_t device); +int u80211_drv_rtl8188eu_bb_enable_datapaths(u80211_drv_device_handle_t device); +int u80211_drv_rtl8188eu_bb_load_table(u80211_drv_device_handle_t device); +int u80211_drv_rtl8188eu_bb_load_agc_table(u80211_drv_device_handle_t device); +int u80211_drv_rtl8188eu_bb_apply_efuse_calibration(u80211_drv_rtl8188eu_t *rtl8188eu); + +int u80211_drv_rtl8188eu_rf_write(u80211_drv_device_handle_t device, uint8_t rf_reg, uint32_t value); +int u80211_drv_rtl8188eu_rf_read(u80211_drv_device_handle_t device, uint8_t rf_reg, uint32_t *value); +int u80211_drv_rtl8188eu_rf_load_table(u80211_drv_device_handle_t device); + +int u80211_drv_rtl8188eu_set_tx_power(u80211_drv_rtl8188eu_t *rtl8188eu, uint8_t channel); +int u80211_drv_rtl8188eu_set_channel(u80211_drv_rtl8188eu_t *rtl8188eu, uint8_t channel); +int u80211_drv_rtl8188eu_set_key(u80211_drv_rtl8188eu_t *rtl8188eu, const u80211_drv_key_t *key); +int u80211_drv_rtl8188eu_del_key(u80211_drv_rtl8188eu_t *rtl8188eu, uint8_t index); +int u80211_drv_rtl8188eu_tx_buffer_allocate(size_t size, void **buffer); +void u80211_drv_rtl8188eu_tx_buffer_free(void *buffer); +int u80211_drv_rtl8188eu_transmit(u80211_drv_rtl8188eu_t *rtl8188eu, void *buffer, size_t size, size_t current_offset, const u80211_drv_transmit_options_t *options); +int u80211_drv_rtl8188eu_rx_start(u80211_drv_rtl8188eu_t *rtl8188eu); + +int u80211_drv_rtl8188eu_calibrate(u80211_drv_device_handle_t device); + +int u80211_drv_rtl8188eu_firmware_prepare(u80211_drv_device_handle_t device, const void *firmware_data, size_t firmware_size, const uint8_t **firmware_payload, size_t *firmware_payload_size); +int u80211_drv_rtl8188eu_firmware_upload(u80211_drv_device_handle_t device, const uint8_t *firmware_payload, size_t firmware_payload_size); +int u80211_drv_rtl8188eu_firmware_start(u80211_drv_device_handle_t device); + +int u80211_drv_rtl8188eu_reg_read8(u80211_drv_device_handle_t device, uint16_t reg, uint8_t *value); +int u80211_drv_rtl8188eu_reg_read16(u80211_drv_device_handle_t device, uint16_t reg, uint16_t *value); +int u80211_drv_rtl8188eu_reg_read32(u80211_drv_device_handle_t device, uint16_t reg, uint32_t *value); +int u80211_drv_rtl8188eu_reg_write8(u80211_drv_device_handle_t device, uint16_t reg, uint8_t value); +int u80211_drv_rtl8188eu_reg_write16(u80211_drv_device_handle_t device, uint16_t reg, uint16_t value); +int u80211_drv_rtl8188eu_reg_write32(u80211_drv_device_handle_t device, uint16_t reg, uint32_t value); +int u80211_drv_rtl8188eu_reg_write_region(u80211_drv_device_handle_t device, uint16_t reg, const void *data, uint16_t size); + +#endif diff --git a/kernel-src/io/net/u80211_drv/include/u80211_drv/status.h b/kernel-src/io/net/u80211_drv/include/u80211_drv/status.h new file mode 100644 index 00000000..63d31dc7 --- /dev/null +++ b/kernel-src/io/net/u80211_drv/include/u80211_drv/status.h @@ -0,0 +1,14 @@ +#ifndef U80211_DRV_STATUS_H +#define U80211_DRV_STATUS_H + +#define U80211_DRV_STATUS_SUCCESS 0 +#define U80211_DRV_STATUS_NO_MATCH 1 +#define U80211_DRV_STATUS_UNKNOWN_ERROR 2 +#define U80211_DRV_STATUS_TIMEOUT 3 +#define U80211_DRV_STATUS_NOT_SUPPORTED 4 +#define U80211_DRV_STATUS_FAULTY_HARDWARE 5 +#define U80211_DRV_STATUS_OUT_OF_MEMORY 6 +#define U80211_DRV_STATUS_INVALID_ARGUMENT 7 +#define U80211_DRV_STATUS_MALFORMED_PACKET 8 + +#endif diff --git a/kernel-src/io/net/u80211_drv/include/u80211_drv/string.h b/kernel-src/io/net/u80211_drv/include/u80211_drv/string.h new file mode 100644 index 00000000..f2034867 --- /dev/null +++ b/kernel-src/io/net/u80211_drv/include/u80211_drv/string.h @@ -0,0 +1,9 @@ +#ifndef U80211_DRV_STRING_H +#define U80211_DRV_STRING_H + +#include + +void *u80211_drv_memcpy(void *destination, const void *source, size_t size); +void *u80211_drv_memset(void *destination, int value, size_t size); + +#endif diff --git a/kernel-src/io/net/u80211_drv/include/u80211_drv/u80211_drv.h b/kernel-src/io/net/u80211_drv/include/u80211_drv/u80211_drv.h new file mode 100644 index 00000000..9152a126 --- /dev/null +++ b/kernel-src/io/net/u80211_drv/include/u80211_drv/u80211_drv.h @@ -0,0 +1,25 @@ +#ifndef U80211_DRV_U80211_DRV_H +#define U80211_DRV_U80211_DRV_H + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// probes a interface to check if there is a matching driver for a specific usb device +// return U80211_DRV_STATUS_SUCCESS when there is a match +int u80211_drv_probe(u80211_drv_device_handle_t device, u80211_drv_interface_handle_t interface); + +// attaches an interface to a driver +// returns U80211_DRV_STATUS_SUCCESS when driver successfully attaches the interface +int u80211_drv_attach(u80211_drv_device_handle_t device, u80211_drv_interface_handle_t interface); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kernel-src/io/net/u80211_drv/include/u80211_drv/util.h b/kernel-src/io/net/u80211_drv/include/u80211_drv/util.h new file mode 100644 index 00000000..dbfadc1c --- /dev/null +++ b/kernel-src/io/net/u80211_drv/include/u80211_drv/util.h @@ -0,0 +1,54 @@ +#ifndef U80211_DRV_UTIL_H +#define U80211_DRV_UTIL_H + +#include + +#include + +static inline uint16_t u80211_drv_host_to_le16(uint16_t value) { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return value; +#else + return __builtin_bswap16(value); +#endif +} + +static inline uint32_t u80211_drv_host_to_le32(uint32_t value) { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return value; +#else + return __builtin_bswap32(value); +#endif +} + +static inline uint16_t u80211_drv_le_to_host16(uint16_t value) { + return u80211_drv_host_to_le16(value); +} + +static inline uint32_t u80211_drv_le_to_host32(uint32_t value) { + return u80211_drv_host_to_le32(value); +} + +static inline uint16_t u80211_drv_deserialize_le16(const void *source) { + uint16_t value; + u80211_drv_memcpy(&value, source, sizeof(value)); + return u80211_drv_le_to_host16(value); +} + +static inline uint32_t u80211_drv_deserialize_le32(const void *source) { + uint32_t value; + u80211_drv_memcpy(&value, source, sizeof(value)); + return u80211_drv_le_to_host32(value); +} + +static inline void u80211_drv_serialize_le16(uint8_t *destination, uint16_t value) { + uint16_t little_endian_value = u80211_drv_host_to_le16(value); + u80211_drv_memcpy(destination, &little_endian_value, sizeof(little_endian_value)); +} + +static inline void u80211_drv_serialize_le32(uint8_t *destination, uint32_t value) { + uint32_t little_endian_value = u80211_drv_host_to_le32(value); + u80211_drv_memcpy(destination, &little_endian_value, sizeof(little_endian_value)); +} + +#endif diff --git a/kernel-src/io/net/u80211_drv/kernel_interface.c b/kernel-src/io/net/u80211_drv/kernel_interface.c new file mode 100644 index 00000000..2e6c8c38 --- /dev/null +++ b/kernel-src/io/net/u80211_drv/kernel_interface.c @@ -0,0 +1,262 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void *u80211_drv_kernel_allocate(size_t size) { + return alloc(size); +} + +void u80211_drv_kernel_free(void *memory) { + free(memory); +} + +int u80211_drv_kernel_get_firmware(const char *name, u80211_drv_kernel_firmware_callback_t callback, void *context) { + int error = firmware_load(name, (firmware_callback_t)callback, context); + if (error == 0) + return U80211_DRV_STATUS_SUCCESS; + + if (error == ENOMEM) + return U80211_DRV_STATUS_OUT_OF_MEMORY; + + return U80211_DRV_STATUS_UNKNOWN_ERROR; +} + +void u80211_drv_kernel_stall_us(unsigned int microseconds) { + timekeeper_wait_us(microseconds); +} + +void u80211_drv_kernel_print(int level, const char *msg) { + switch (level) { + case U80211_DRV_KERNEL_PRINT_LEVEL_INFO: + printf("u80211_drv: [INFO] %s\n", msg); + break; + case U80211_DRV_KERNEL_PRINT_LEVEL_WARN: + printf("u80211_drv: [WARN] %s\n", msg); + break; + case U80211_DRV_KERNEL_PRINT_LEVEL_ERROR: + printf("u80211_drv: [ERROR] %s\n", msg); + break; + default: + printf("u80211_drv: [UNKNOWN] %s\n", msg); + break; + } +} + +int u80211_drv_kernel_get_device_descriptor(u80211_drv_device_handle_t opaque_device, u80211_drv_device_descriptor_t *descriptor) { + usb_device_t *device = opaque_device; + descriptor->vendor_id = device->desc.idVendor; + descriptor->product_id = device->desc.idProduct; + return U80211_DRV_STATUS_SUCCESS; +} + +int u80211_drv_kernel_get_interface_descriptor(u80211_drv_interface_handle_t opaque_interface, u80211_drv_interface_descriptor_t *descriptor) { + usb_interface_t *interface = opaque_interface; + descriptor->number = interface->desc->bInterfaceNumber; + descriptor->class_code = interface->desc->bInterfaceClass; + descriptor->subclass = interface->desc->bInterfaceSubClass; + descriptor->protocol = interface->desc->bInterfaceProtocol; + descriptor->endpoint_count = interface->desc->bNumEndpoints; + return U80211_DRV_STATUS_SUCCESS; +} + +int u80211_drv_kernel_get_endpoints(u80211_drv_interface_handle_t opaque_interface, u80211_drv_endpoint_descriptor_t *endpoints, size_t endpoint_count) { + usb_interface_t *interface = opaque_interface; + + for (size_t i = 0; i < endpoint_count; ++i) { + usb_endpoint_desc_t *endpoint = interface->endpoints[i].desc; + endpoints[i].address = endpoint->bEndpointAddress; + endpoints[i].attributes = endpoint->bmAttributes; + endpoints[i].maximum_packet_size = endpoint->wMaxPacketSize; + endpoints[i].interval = endpoint->bInterval; + } + + return U80211_DRV_STATUS_SUCCESS; +} + +typedef struct { + usb_device_t *device; + usb_xfer_t xfer; + iovec_t iovec; + iovec_iterator_t iterator; + u80211_drv_kernel_transfer_callback_t callback; + void *context; + bool active; +} u80211_drv_transfer_t; + +static int u80211_drv_transfer_status(usb_status_t status) { + if (status == USB_STATUS_SUCCESS || status == USB_STATUS_SHORT_PACKET) + return U80211_DRV_STATUS_SUCCESS; + + return U80211_DRV_STATUS_UNKNOWN_ERROR; +} + +static int u80211_drv_transfer_error(int error) { + if (error == ENOMEM) + return U80211_DRV_STATUS_OUT_OF_MEMORY; + + if (error == EINVAL) + return U80211_DRV_STATUS_INVALID_ARGUMENT; + + return U80211_DRV_STATUS_UNKNOWN_ERROR; +} + +static void u80211_drv_transfer_complete(usb_device_t *, void *context, usb_status_t status, size_t transferred_size) { + u80211_drv_transfer_t *transfer = context; + int driver_status = u80211_drv_transfer_status(status); + if (driver_status != U80211_DRV_STATUS_SUCCESS) + transferred_size = 0; + + __atomic_store_n(&transfer->active, false, __ATOMIC_RELEASE); + transfer->callback(transfer->context, driver_status, transferred_size); +} + +int u80211_drv_kernel_allocate_bulk_xfer(u80211_drv_device_handle_t opaque_device, uint8_t endpoint_address, void *buffer, size_t buffer_size, u80211_drv_kernel_transfer_callback_t callback, void *context, u80211_drv_transfer_handle_t *transfer_out) { + usb_device_t *device = opaque_device; + usb_endpoint_t *endpoint = usb_find_endpoint(device, endpoint_address); + if (endpoint == NULL || (endpoint->desc->bmAttributes & USB_ENDPOINT_ATTRIB_TYPE_MASK) != USB_ENDPOINT_ATTRIB_TYPE_BULK) + return U80211_DRV_STATUS_INVALID_ARGUMENT; + + u80211_drv_transfer_t *transfer = alloc(sizeof(u80211_drv_transfer_t)); + if (transfer == NULL) + return U80211_DRV_STATUS_OUT_OF_MEMORY; + + transfer->device = device; + transfer->iovec.addr = buffer; + transfer->iovec.len = buffer_size; + transfer->callback = callback; + transfer->context = context; + transfer->xfer.ep = endpoint; + transfer->xfer.flags = (endpoint_address & USB_ENDPOINT_ADDRESS_DIR_IN ? USB_XFER_FLAG_TO_HOST : USB_XFER_FLAG_TO_DEVICE) | USB_XFER_FLAG_IOVEC; + transfer->xfer.type = USB_XFER_TYPE_BULK; + transfer->xfer.iov = &transfer->iterator; + transfer->xfer.completion = u80211_drv_transfer_complete; + transfer->xfer.completion_ctx = transfer; + *transfer_out = transfer; + return U80211_DRV_STATUS_SUCCESS; +} + +int u80211_drv_kernel_submit_xfer(u80211_drv_transfer_handle_t opaque_transfer) { + u80211_drv_transfer_t *transfer = opaque_transfer; + + bool expected = false; + if (!__atomic_compare_exchange_n(&transfer->active, &expected, true, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) + return U80211_DRV_STATUS_INVALID_ARGUMENT; + + iovec_iterator_init(&transfer->iterator, &transfer->iovec, 1); + int error = usb_submit_xfer(transfer->device, &transfer->xfer); + if (error == 0) + return U80211_DRV_STATUS_SUCCESS; + + __atomic_store_n(&transfer->active, false, __ATOMIC_RELEASE); + return u80211_drv_transfer_error(error); +} + +typedef struct { + semaphore_t semaphore; + usb_status_t status; + size_t transferred_size; +} u80211_drv_sync_transfer_t; + +static void u80211_drv_sync_transfer_complete(usb_device_t *, void *context, usb_status_t status, size_t transferred_size) { + u80211_drv_sync_transfer_t *transfer = context; + transfer->status = status; + transfer->transferred_size = transferred_size; + semaphore_signal(&transfer->semaphore); +} + +static int u80211_drv_wait_for_transfer(u80211_drv_sync_transfer_t *transfer, int error, size_t *transferred_size) { + if (error != 0) + return u80211_drv_transfer_error(error); + + semaphore_wait(&transfer->semaphore, false); + int status = u80211_drv_transfer_status(transfer->status); + *transferred_size = status == U80211_DRV_STATUS_SUCCESS ? transfer->transferred_size : 0; + return status; +} + +int u80211_drv_kernel_submit_control_xfer_and_wait(u80211_drv_device_handle_t opaque_device, uint8_t flags, uint8_t request, uint16_t value, uint16_t index, void *buf, uint16_t buffer_size, size_t *transferred_size, unsigned int timeout) { + (void)timeout; + // TODO: implement timeouts once transfer cancellation is available + // TODO: once scatter-gather control transfers are implemented, drop the bounce page stuff + void *bounce_page = NULL; + void *transfer_buffer = NULL; + if (buffer_size != 0) { + bounce_page = mm_alloc_page(MEMORY_SECTION_DEFAULT); + if (bounce_page == NULL) + return U80211_DRV_STATUS_OUT_OF_MEMORY; + + transfer_buffer = MAKE_HHDM(bounce_page); + if ((flags & U80211_DRV_KERNEL_XFER_DIRECTION_MASK) == U80211_DRV_KERNEL_XFER_OUT) + memcpy(transfer_buffer, buf, buffer_size); + } + + usb_setup_t setup = { + .bmRequestType = flags, + .bRequest = request, + .wValue = value, + .wIndex = index, + .wLength = buffer_size, + }; + u80211_drv_sync_transfer_t transfer; + SEMAPHORE_INIT(&transfer.semaphore, 0); + + int status = u80211_drv_wait_for_transfer( + &transfer, + usb_control_xfer(opaque_device, &setup, transfer_buffer, u80211_drv_sync_transfer_complete, &transfer), + transferred_size + ); + + if (status == U80211_DRV_STATUS_SUCCESS && *transferred_size != 0 && (flags & U80211_DRV_KERNEL_XFER_DIRECTION_MASK) == U80211_DRV_KERNEL_XFER_IN) + memcpy(buf, transfer_buffer, *transferred_size); + + if (bounce_page != NULL) + mm_release_page(bounce_page); + return status; +} + +int u80211_drv_kernel_submit_bulk_xfer_and_wait(u80211_drv_device_handle_t opaque_device, uint8_t endpoint_address, void *buf, size_t buffer_size, size_t *transferred_size, unsigned int timeout) { + (void)timeout; + // TODO: Implement timeouts once USB transfer cancellation is available. + usb_device_t *device = opaque_device; + usb_endpoint_t *endpoint = usb_find_endpoint(device, endpoint_address); + if (endpoint == NULL || (endpoint->desc->bmAttributes & USB_ENDPOINT_ATTRIB_TYPE_MASK) != USB_ENDPOINT_ATTRIB_TYPE_BULK) + return U80211_DRV_STATUS_INVALID_ARGUMENT; + + iovec_t iovec = { + .addr = buf, + .len = buffer_size, + }; + iovec_iterator_t iterator; + iovec_iterator_init(&iterator, &iovec, 1); + u80211_drv_sync_transfer_t transfer; + SEMAPHORE_INIT(&transfer.semaphore, 0); + usb_xfer_t xfer = { + .ep = endpoint, + .flags = (endpoint_address & USB_ENDPOINT_ADDRESS_DIR_IN ? USB_XFER_FLAG_TO_HOST : USB_XFER_FLAG_TO_DEVICE) | USB_XFER_FLAG_IOVEC, + .type = USB_XFER_TYPE_BULK, + .iov = &iterator, + .completion = u80211_drv_sync_transfer_complete, + .completion_ctx = &transfer, + }; + + return u80211_drv_wait_for_transfer(&transfer, usb_submit_xfer(device, &xfer), transferred_size); +} + +int u80211_drv_device_ready(void *device, const u80211_drv_device_metadata_t *metadata, const u80211_drv_device_ops_t *ops, u80211_drv_network_device_handle_t *network_device) { + printf("device ready\n"); + return 0; +} + +void u80211_drv_packet_received(u80211_drv_network_device_handle_t device, void *packet, size_t packet_size) { + printf("got packet!\n"); +} diff --git a/kernel-src/io/net/u80211_drv/src/rtl8188eu/bb_table.c b/kernel-src/io/net/u80211_drv/src/rtl8188eu/bb_table.c new file mode 100644 index 00000000..6c08a7c5 --- /dev/null +++ b/kernel-src/io/net/u80211_drv/src/rtl8188eu/bb_table.c @@ -0,0 +1,252 @@ +/* $OpenBSD: r92creg.h,v 1.31 2024/09/01 03:14:48 jsg Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include +#include + +#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) +#define RTL8188EU_AGC_TABLE_ENTRY_COUNT 128 + +// Imported from OpenBSD sys/dev/ic/r92creg.h. +static const uint16_t rtl8188eu_bb_regs[] = { + 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818, 0x81c, 0x820, + 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c, 0x840, 0x844, + 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c, 0x860, 0x864, 0x868, + 0x86c, 0x870, 0x874, 0x878, 0x87c, 0x880, 0x884, 0x888, 0x88c, + 0x890, 0x894, 0x898, 0x89c, 0x900, 0x904, 0x908, 0x90c, 0x910, + 0x914, 0xa00, 0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c, + 0xa20, 0xa24, 0xa28, 0xa2c, 0xa70, 0xa74, 0xa78, 0xa7c, 0xa80, + 0xb2c, 0xc00, 0xc04, 0xc08, 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, + 0xc20, 0xc24, 0xc28, 0xc2c, 0xc30, 0xc34, 0xc38, 0xc3c, 0xc40, + 0xc44, 0xc48, 0xc4c, 0xc50, 0xc54, 0xc58, 0xc5c, 0xc60, 0xc64, + 0xc68, 0xc6c, 0xc70, 0xc74, 0xc78, 0xc7c, 0xc80, 0xc84, 0xc88, + 0xc8c, 0xc90, 0xc94, 0xc98, 0xc9c, 0xca0, 0xca4, 0xca8, 0xcac, + 0xcb0, 0xcb4, 0xcb8, 0xcbc, 0xcc0, 0xcc4, 0xcc8, 0xccc, 0xcd0, + 0xcd4, 0xcd8, 0xcdc, 0xce0, 0xce4, 0xce8, 0xcec, 0xd00, 0xd04, + 0xd08, 0xd0c, 0xd10, 0xd14, 0xd18, 0xd2c, 0xd30, 0xd34, 0xd38, + 0xd3c, 0xd40, 0xd44, 0xd48, 0xd4c, 0xd50, 0xd54, 0xd58, 0xd5c, + 0xd60, 0xd64, 0xd68, 0xd6c, 0xd70, 0xd74, 0xd78, 0xe00, 0xe04, + 0xe08, 0xe10, 0xe14, 0xe18, 0xe1c, 0xe28, 0xe30, 0xe34, 0xe38, + 0xe3c, 0xe40, 0xe44, 0xe48, 0xe4c, 0xe50, 0xe54, 0xe58, 0xe5c, + 0xe60, 0xe68, 0xe6c, 0xe70, 0xe74, 0xe78, 0xe7c, 0xe80, 0xe84, + 0xe88, 0xe8c, 0xed0, 0xed4, 0xed8, 0xedc, 0xee0, 0xee8, 0xeec, + 0xf14, 0xf4c, 0xf00 +}; + +static const uint32_t rtl8188eu_bb_values[] = { + 0x80040000, 0x00000003, 0x0000fc00, 0x0000000a, 0x10001331, + 0x020c3d10, 0x02200385, 0x00000000, 0x01000100, 0x00390204, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00010000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x569a11a9, 0x01000014, 0x66f60110, + 0x061f0649, 0x00000000, 0x27272700, 0x07000760, 0x25004000, + 0x00000808, 0x00000000, 0xb0000c1c, 0x00000001, 0x00000000, + 0xccc000c0, 0x00000800, 0xfffffffe, 0x40302010, 0x00706050, + 0x00000000, 0x00000023, 0x00000000, 0x81121111, 0x00000002, + 0x00000201, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e7f120f, + 0x9500bb78, 0x1114d028, 0x00881117, 0x89140f00, 0x1a1b0000, + 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, + 0x00000900, 0x225b0606, 0x218075b1, 0x80000000, 0x48071d40, + 0x03a05611, 0x000000e4, 0x6c6c6c6c, 0x08800000, 0x40000100, + 0x08800000, 0x40000100, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x69e9ac47, 0x469652af, 0x49795994, 0x0a97971c, + 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, 0x69553420, + 0x43bc0094, 0x00013169, 0x00250492, 0x00000000, 0x7112848b, + 0x47c00bff, 0x00000036, 0x2c7f000d, 0x020610db, 0x0000001f, + 0x00b91612, 0x390000e4, 0x20f60000, 0x40000100, 0x20200000, + 0x00091521, 0x00000000, 0x00121820, 0x00007f7f, 0x00000000, + 0x000300a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x28000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x64b22427, 0x00766932, + 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c, 0x00000740, + 0x00020401, 0x0000907f, 0x20010201, 0xa0633333, 0x3333bc43, + 0x7a8f5b6f, 0xcc979975, 0x00000000, 0x80608000, 0x00000000, + 0x00127353, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x6437140a, 0x00000000, 0x00000282, 0x30032064, 0x4653de68, + 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e, 0x322c2220, + 0x000e3c24, 0x2d2d2d2d, 0x2d2d2d2d, 0x0390272d, 0x2d2d2d2d, + 0x2d2d2d2d, 0x2d2d2d2d, 0x2d2d2d2d, 0x00000000, 0x1000dc1f, + 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00, 0x01004800, + 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f, 0x02140102, + 0x28160d05, 0x00000008, 0x001b25a4, 0x00c00014, 0x00c00014, + 0x01000014, 0x01000014, 0x01000014, 0x01000014, 0x00c00014, + 0x01000014, 0x00c00014, 0x00c00014, 0x00c00014, 0x00c00014, + 0x00000014, 0x00000014, 0x21555448, 0x01c00014, 0x00000003, + 0x00000000, 0x00000300 +}; + +static const uint32_t rtl8188eu_agc_values[] = { + 0xfb000001, 0xfb010001, 0xfb020001, 0xfb030001, 0xfb040001, + 0xfb050001, 0xfa060001, 0xf9070001, 0xf8080001, 0xf7090001, + 0xf60a0001, 0xf50b0001, 0xf40c0001, 0xf30d0001, 0xf20e0001, + 0xf10f0001, 0xf0100001, 0xef110001, 0xee120001, 0xed130001, + 0xec140001, 0xeb150001, 0xea160001, 0xe9170001, 0xe8180001, + 0xe7190001, 0xe61a0001, 0xe51b0001, 0xe41c0001, 0xe31d0001, + 0xe21e0001, 0xe11f0001, 0x8a200001, 0x89210001, 0x88220001, + 0x87230001, 0x86240001, 0x85250001, 0x84260001, 0x83270001, + 0x82280001, 0x6b290001, 0x6a2a0001, 0x692b0001, 0x682c0001, + 0x672d0001, 0x662e0001, 0x652f0001, 0x64300001, 0x63310001, + 0x62320001, 0x61330001, 0x46340001, 0x45350001, 0x44360001, + 0x43370001, 0x42380001, 0x41390001, 0x403a0001, 0x403b0001, + 0x403c0001, 0x403d0001, 0x403e0001, 0x403f0001, 0xfb400001, + 0xfb410001, 0xfb420001, 0xfb430001, 0xfb440001, 0xfb450001, + 0xfb460001, 0xfb470001, 0xfb480001, 0xfa490001, 0xf94a0001, + 0xf84b0001, 0xf74c0001, 0xf64d0001, 0xf54e0001, 0xf44f0001, + 0xf3500001, 0xf2510001, 0xf1520001, 0xf0530001, 0xef540001, + 0xee550001, 0xed560001, 0xec570001, 0xeb580001, 0xea590001, + 0xe95a0001, 0xe85b0001, 0xe75c0001, 0xe65d0001, 0xe55e0001, + 0xe45f0001, 0xe3600001, 0xe2610001, 0xc3620001, 0xc2630001, + 0xc1640001, 0x8b650001, 0x8a660001, 0x89670001, 0x88680001, + 0x87690001, 0x866a0001, 0x856b0001, 0x846c0001, 0x676d0001, + 0x666e0001, 0x656f0001, 0x64700001, 0x63710001, 0x62720001, + 0x61730001, 0x60740001, 0x46750001, 0x45760001, 0x44770001, + 0x43780001, 0x42790001, 0x417a0001, 0x407b0001, 0x407c0001, + 0x407d0001, 0x407e0001, 0x407f0001 +}; + +int u80211_drv_rtl8188eu_bb_enable(u80211_drv_device_handle_t device) { + uint16_t value; + int status = u80211_drv_rtl8188eu_reg_read16(device, U80211_DRV_RTL8188EU_REG_SYS_FUNC, &value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value |= U80211_DRV_RTL8188EU_REG_SYS_FUNC_BBRSTB | + U80211_DRV_RTL8188EU_REG_SYS_FUNC_BB_GLB_RSTN | + U80211_DRV_RTL8188EU_REG_SYS_FUNC_DIO_RF; + status = u80211_drv_rtl8188eu_reg_write16(device, U80211_DRV_RTL8188EU_REG_SYS_FUNC, value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write8( + device, + U80211_DRV_RTL8188EU_REG_RF_CTRL, + U80211_DRV_RTL8188EU_REG_RF_CTRL_ENABLE | + U80211_DRV_RTL8188EU_REG_RF_CTRL_RSTB | + U80211_DRV_RTL8188EU_REG_RF_CTRL_SDMRSTB + ); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + return u80211_drv_rtl8188eu_reg_write8( + device, + U80211_DRV_RTL8188EU_REG_SYS_FUNC, + U80211_DRV_RTL8188EU_REG_SYS_FUNC_USBA | + U80211_DRV_RTL8188EU_REG_SYS_FUNC_USBD | + U80211_DRV_RTL8188EU_REG_SYS_FUNC_BB_GLB_RSTN | + U80211_DRV_RTL8188EU_REG_SYS_FUNC_BBRSTB + ); +} + +int u80211_drv_rtl8188eu_bb_enable_datapaths(u80211_drv_device_handle_t device) { + // enable cck datapath + uint32_t rfmod; + int status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_FPGA0_RFMOD, &rfmod); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + rfmod |= U80211_DRV_RTL8188EU_REG_FPGA0_RFMOD_CCK_ENABLE; + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_FPGA0_RFMOD, rfmod); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // enable ofdm data path + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_FPGA0_RFMOD, &rfmod); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + rfmod |= U80211_DRV_RTL8188EU_REG_FPGA0_RFMOD_OFDM_ENABLE; + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_FPGA0_RFMOD, rfmod); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // sanity check + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_FPGA0_RFMOD, &rfmod); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + uint32_t enable_mask = U80211_DRV_RTL8188EU_REG_FPGA0_RFMOD_CCK_ENABLE | U80211_DRV_RTL8188EU_REG_FPGA0_RFMOD_OFDM_ENABLE; + if ((rfmod & enable_mask) != enable_mask) + return U80211_DRV_STATUS_FAULTY_HARDWARE; + + return U80211_DRV_STATUS_SUCCESS; +} + +int u80211_drv_rtl8188eu_bb_load_table(u80211_drv_device_handle_t device) { + for (size_t i = 0; i < ARRAY_SIZE(rtl8188eu_bb_regs); ++i) { + int status = u80211_drv_rtl8188eu_reg_write32(device, rtl8188eu_bb_regs[i], rtl8188eu_bb_values[i]); + if (status != U80211_DRV_STATUS_SUCCESS) { + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_ERROR, "rtl8188eu: BB table write failed"); + return status; + } + + u80211_drv_kernel_stall_us(1); + } + + return U80211_DRV_STATUS_SUCCESS; +} + +int u80211_drv_rtl8188eu_bb_load_agc_table(u80211_drv_device_handle_t device) { + for (size_t i = 0; i < ARRAY_SIZE(rtl8188eu_agc_values); ++i) { + int status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_OFDM0_AGCRSSITABLE, rtl8188eu_agc_values[i]); + if (status != U80211_DRV_STATUS_SUCCESS) { + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_ERROR, "rtl8188eu: AGC table write failed"); + return status; + } + + u80211_drv_kernel_stall_us(1); + } + + int status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_OFDM0_AGCCORE1, U80211_DRV_RTL8188EU_REG_OFDM0_AGCCORE1_LATCH); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + u80211_drv_kernel_stall_us(1); + + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_OFDM0_AGCCORE1, U80211_DRV_RTL8188EU_REG_OFDM0_AGCCORE1_FINAL); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + u80211_drv_kernel_stall_us(1); + return U80211_DRV_STATUS_SUCCESS; +} + +int u80211_drv_rtl8188eu_bb_apply_efuse_calibration(u80211_drv_rtl8188eu_t *rtl8188eu) { + uint32_t value; + int status = u80211_drv_rtl8188eu_reg_read32(rtl8188eu->device, U80211_DRV_RTL8188EU_REG_AFE_XTAL_CTRL, &value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + uint32_t crystal_cap = rtl8188eu->efuse.xtal_k; + uint32_t crystal_field = crystal_cap | (crystal_cap << 6); + value &= ~U80211_DRV_RTL8188EU_REG_AFE_XTAL_CTRL_ADDRESS_MASK; + value |= (crystal_field << U80211_DRV_RTL8188EU_REG_AFE_XTAL_CTRL_ADDRESS_SHIFT) & U80211_DRV_RTL8188EU_REG_AFE_XTAL_CTRL_ADDRESS_MASK; + status = u80211_drv_rtl8188eu_reg_write32(rtl8188eu->device, U80211_DRV_RTL8188EU_REG_AFE_XTAL_CTRL, value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read32(rtl8188eu->device, U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_A, &value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + rtl8188eu->cck_high_power = (value & U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_CCK_HIGH_POWER) != 0; + return U80211_DRV_STATUS_SUCCESS; +} diff --git a/kernel-src/io/net/u80211_drv/src/rtl8188eu/calibration.c b/kernel-src/io/net/u80211_drv/src/rtl8188eu/calibration.c new file mode 100644 index 00000000..548a153c --- /dev/null +++ b/kernel-src/io/net/u80211_drv/src/rtl8188eu/calibration.c @@ -0,0 +1,663 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include +#include + +#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) + +#define RTL8188EU_IQK_RUN_COUNT 3 +#define RTL8188EU_IQK_TOLERANCE 5 +#define RTL8188EU_IQK_DELAY_US 1000 +#define RTL8188EU_LC_MAX_POLLS 100 +#define RTL8188EU_LC_POLL_DELAY_US 100 + +#define RTL8188EU_REG_GPIO_MUXCFG 0x0040 +#define RTL8188EU_REG_GPIO_MUXCFG_ENBT (1u << 5) + +#define RTL8188EU_REG_TXPAUSE 0x0522 +#define RTL8188EU_REG_TXPAUSE_IQK_QUEUES 0x3f +#define RTL8188EU_REG_BCN_CTRL1 0x0551 +#define RTL8188EU_REG_BCN_CTRL_ENABLE (1u << 3) + +#define RTL8188EU_REG_CCK0_AFESETTING 0x0a04 +#define RTL8188EU_REG_OFDM1_LSTF 0x0d00 +#define RTL8188EU_REG_CONFIG_ANT_A 0x0b68 +#define RTL8188EU_REG_OFDM0_TRXPATHENA 0x0c04 +#define RTL8188EU_REG_OFDM0_TRMUXPAR 0x0c08 +#define RTL8188EU_REG_OFDM0_RXIQIMBALANCE_A 0x0c14 +#define RTL8188EU_REG_OFDM0_ECCATHRESHOLD 0x0c4c +#define RTL8188EU_REG_OFDM0_TXIQIMBALANCE_A 0x0c80 +#define RTL8188EU_REG_OFDM0_TXAFE_A 0x0c94 +#define RTL8188EU_REG_OFDM0_RXIQEXTANTA 0x0ca0 + +#define RTL8188EU_REG_FPGA0_IQK 0x0e28 +#define RTL8188EU_REG_TX_IQK_TONE_A 0x0e30 +#define RTL8188EU_REG_RX_IQK_TONE_A 0x0e34 +#define RTL8188EU_REG_TX_IQK_PI_A 0x0e38 +#define RTL8188EU_REG_RX_IQK_PI_A 0x0e3c +#define RTL8188EU_REG_TX_IQK 0x0e40 +#define RTL8188EU_REG_RX_IQK 0x0e44 +#define RTL8188EU_REG_IQK_AGC_PTS 0x0e48 +#define RTL8188EU_REG_IQK_AGC_RSP 0x0e4c +#define RTL8188EU_REG_RX_IQK_TONE_B 0x0e54 +#define RTL8188EU_REG_TX_POWER_BEFORE_IQK_A 0x0e94 +#define RTL8188EU_REG_TX_POWER_AFTER_IQK_A 0x0e9c +#define RTL8188EU_REG_RX_POWER_BEFORE_IQK_A 0x0ea4 +#define RTL8188EU_REG_RX_POWER_AFTER_IQK_A 0x0eac + +#define RTL8188EU_IQK_TX_FAILURE (1u << 28) +#define RTL8188EU_IQK_RX_FAILURE (1u << 27) +#define RTL8188EU_IQK_RESULT_MASK 0x03ff +#define RTL8188EU_IQK_TX0_FAILURE 0x0142 +#define RTL8188EU_IQK_TX1_FAILURE 0x0042 +#define RTL8188EU_IQK_RX0_FAILURE 0x0132 +#define RTL8188EU_IQK_RX1_FAILURE 0x0036 + +#define RTL8188EU_RF_AC 0x00 +#define RTL8188EU_RF_AC_MODE_MASK 0x70000 +#define RTL8188EU_RF_AC_MODE_STANDBY 0x10000 +#define RTL8188EU_RF_CHNLBW_LCSTART 0x08000 +#define RTL8188EU_CONTINUOUS_TX_MASK 0x70 + +static const uint16_t rtl8188eu_iqk_adda_regs[] = { + 0x085c, + 0x0e6c, 0x0e70, 0x0e74, + 0x0e78, 0x0e7c, 0x0e80, 0x0e84, + 0x0e88, 0x0e8c, + 0x0ed0, 0x0ed4, 0x0ed8, 0x0edc, + 0x0ee0, 0x0eec, +}; + +typedef struct { + uint32_t adda[ARRAY_SIZE(rtl8188eu_iqk_adda_regs)]; + uint8_t txpause; + uint8_t bcn_ctrl; + uint8_t bcn_ctrl1; + uint32_t gpio_mux; + uint32_t trxpathena; + uint32_t trmuxpar; + uint32_t rfifacesw0; + uint32_t rfifacesw1; + uint32_t rfifaceoe0; + uint32_t rfifaceoe1; + uint32_t ant_a; + uint32_t cck_afe; + uint8_t agc_gain; +} rtl8188eu_iqk_saved_t; + +typedef struct { + uint16_t tx[2]; + uint16_t rx[2]; + bool tx_valid; + bool rx_valid; +} rtl8188eu_iqk_result_t; + +static int rtl8188eu_iqk_save(u80211_drv_device_handle_t device, rtl8188eu_iqk_saved_t *saved) { + // IQK reconfigures a lot of baseband stuff, so we need to save these. + for (size_t i = 0; i < ARRAY_SIZE(rtl8188eu_iqk_adda_regs); ++i) { + int status = u80211_drv_rtl8188eu_reg_read32(device, rtl8188eu_iqk_adda_regs[i], &saved->adda[i]); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + } + + int status = u80211_drv_rtl8188eu_reg_read8(device, RTL8188EU_REG_TXPAUSE, &saved->txpause); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read8(device, U80211_DRV_RTL8188EU_REG_BCN_CTRL, &saved->bcn_ctrl); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read8(device, RTL8188EU_REG_BCN_CTRL1, &saved->bcn_ctrl1); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read32(device, RTL8188EU_REG_GPIO_MUXCFG, &saved->gpio_mux); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read32(device, RTL8188EU_REG_OFDM0_TRXPATHENA, &saved->trxpathena); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read32(device, RTL8188EU_REG_OFDM0_TRMUXPAR, &saved->trmuxpar); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_RF_IFACE_SW_A, &saved->rfifacesw0); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_RF_IFACE_SW_A + 4, &saved->rfifacesw1); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_RF_IFACE_OE_A, &saved->rfifaceoe0); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_RF_IFACE_OE_A + 4, &saved->rfifaceoe1); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read32(device, RTL8188EU_REG_CONFIG_ANT_A, &saved->ant_a); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read32(device, RTL8188EU_REG_CCK0_AFESETTING, &saved->cck_afe); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + uint32_t agc; + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_OFDM0_AGCCORE1, &agc); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + saved->agc_gain = agc & UINT8_MAX; + return U80211_DRV_STATUS_SUCCESS; +} + +static int rtl8188eu_iqk_prepare(u80211_drv_device_handle_t device, const rtl8188eu_iqk_saved_t *saved) { + int status = u80211_drv_rtl8188eu_reg_write32(device, rtl8188eu_iqk_adda_regs[0], 0x0b1b25a0); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + for (size_t i = 1; i < ARRAY_SIZE(rtl8188eu_iqk_adda_regs); ++i) { + status = u80211_drv_rtl8188eu_reg_write32(device, rtl8188eu_iqk_adda_regs[i], 0x0bdb25a0); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + } + + uint32_t hssi_param1; + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_HSSI_PARAM1_A, &hssi_param1); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if ((hssi_param1 & U80211_DRV_RTL8188EU_REG_HSSI_PARAM1_PI) == 0) { + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_HSSI_PARAM1_A, hssi_param1 | U80211_DRV_RTL8188EU_REG_HSSI_PARAM1_PI); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + } + + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_OFDM0_TRXPATHENA, 0x03a05600); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_OFDM0_TRMUXPAR, 0x000800e4); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_RF_IFACE_SW_A + 4, 0x22204000); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write8(device, RTL8188EU_REG_TXPAUSE, RTL8188EU_REG_TXPAUSE_IQK_QUEUES); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_BCN_CTRL, saved->bcn_ctrl & ~RTL8188EU_REG_BCN_CTRL_ENABLE); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write8(device, RTL8188EU_REG_BCN_CTRL1, saved->bcn_ctrl1 & ~RTL8188EU_REG_BCN_CTRL_ENABLE); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write8(device, RTL8188EU_REG_GPIO_MUXCFG, (uint8_t)saved->gpio_mux & ~RTL8188EU_REG_GPIO_MUXCFG_ENBT); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_CONFIG_ANT_A, 0x00080000); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_FPGA0_IQK, 0x80800000); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_TX_IQK, 0x01007c00); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + return u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_RX_IQK, 0x01004800); +} + +static int rtl8188eu_iqk_measure_once(u80211_drv_device_handle_t device, rtl8188eu_iqk_result_t *result) { + result->tx_valid = false; + result->rx_valid = false; + + int status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_TX_IQK_TONE_A, 0x10008c1f); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_RX_IQK_TONE_B, 0x10008c1f); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_TX_IQK_PI_A, 0x82140102); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_RX_IQK_PI_A, 0x28160502); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_IQK_AGC_RSP, 0x00462911); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_IQK_AGC_PTS, 0xf9000000); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_IQK_AGC_PTS, 0xf8000000); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + u80211_drv_kernel_stall_us(RTL8188EU_IQK_DELAY_US); + + uint32_t iqk_status; + status = u80211_drv_rtl8188eu_reg_read32(device, RTL8188EU_REG_RX_POWER_AFTER_IQK_A, &iqk_status); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if ((iqk_status & RTL8188EU_IQK_TX_FAILURE) != 0) + return U80211_DRV_STATUS_SUCCESS; + + uint32_t value; + status = u80211_drv_rtl8188eu_reg_read32(device, RTL8188EU_REG_TX_POWER_BEFORE_IQK_A, &value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + result->tx[0] = (value >> 16) & RTL8188EU_IQK_RESULT_MASK; + status = u80211_drv_rtl8188eu_reg_read32(device, RTL8188EU_REG_TX_POWER_AFTER_IQK_A, &value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + result->tx[1] = (value >> 16) & RTL8188EU_IQK_RESULT_MASK; + if (result->tx[0] == RTL8188EU_IQK_TX0_FAILURE || result->tx[1] == RTL8188EU_IQK_TX1_FAILURE) + return U80211_DRV_STATUS_SUCCESS; + + result->tx_valid = true; + + if ((iqk_status & RTL8188EU_IQK_RX_FAILURE) != 0) + return U80211_DRV_STATUS_SUCCESS; + + status = u80211_drv_rtl8188eu_reg_read32(device, RTL8188EU_REG_RX_POWER_BEFORE_IQK_A, &value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + result->rx[0] = (value >> 16) & RTL8188EU_IQK_RESULT_MASK; + result->rx[1] = (iqk_status >> 16) & RTL8188EU_IQK_RESULT_MASK; + if (result->rx[0] == RTL8188EU_IQK_RX0_FAILURE || result->rx[1] == RTL8188EU_IQK_RX1_FAILURE) + return U80211_DRV_STATUS_SUCCESS; + + result->rx_valid = true; + return U80211_DRV_STATUS_SUCCESS; +} + +static void rtl8188eu_iqk_record_error(int *result, int status) { + if (*result == U80211_DRV_STATUS_SUCCESS && status != U80211_DRV_STATUS_SUCCESS) + *result = status; +} + +static int rtl8188eu_iqk_leave_mode(u80211_drv_device_handle_t device) { + int result = U80211_DRV_STATUS_SUCCESS; + int status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_FPGA0_IQK, 0); + rtl8188eu_iqk_record_error(&result, status); + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_LSSI_PARAM_A, 0x00032ed3); + rtl8188eu_iqk_record_error(&result, status); + return result; +} + +static int rtl8188eu_iqk_restore(u80211_drv_device_handle_t device, const rtl8188eu_iqk_saved_t *saved) { + int result = rtl8188eu_iqk_leave_mode(device); + int status; + + for (size_t i = 0; i < ARRAY_SIZE(rtl8188eu_iqk_adda_regs); ++i) { + status = u80211_drv_rtl8188eu_reg_write32(device, rtl8188eu_iqk_adda_regs[i], saved->adda[i]); + rtl8188eu_iqk_record_error(&result, status); + } + status = u80211_drv_rtl8188eu_reg_write8(device, RTL8188EU_REG_TXPAUSE, saved->txpause); + rtl8188eu_iqk_record_error(&result, status); + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_BCN_CTRL, saved->bcn_ctrl); + rtl8188eu_iqk_record_error(&result, status); + status = u80211_drv_rtl8188eu_reg_write8(device, RTL8188EU_REG_BCN_CTRL1, saved->bcn_ctrl1); + rtl8188eu_iqk_record_error(&result, status); + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_GPIO_MUXCFG, saved->gpio_mux); + rtl8188eu_iqk_record_error(&result, status); + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_OFDM0_TRXPATHENA, saved->trxpathena); + rtl8188eu_iqk_record_error(&result, status); + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_RF_IFACE_SW_A, saved->rfifacesw0); + rtl8188eu_iqk_record_error(&result, status); + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_RF_IFACE_SW_A + 4, saved->rfifacesw1); + rtl8188eu_iqk_record_error(&result, status); + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_RF_IFACE_OE_A, saved->rfifaceoe0); + rtl8188eu_iqk_record_error(&result, status); + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_RF_IFACE_OE_A + 4, saved->rfifaceoe1); + rtl8188eu_iqk_record_error(&result, status); + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_OFDM0_TRMUXPAR, saved->trmuxpar); + rtl8188eu_iqk_record_error(&result, status); + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_CONFIG_ANT_A, saved->ant_a); + rtl8188eu_iqk_record_error(&result, status); + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_CCK0_AFESETTING, saved->cck_afe); + rtl8188eu_iqk_record_error(&result, status); + + uint32_t agc; + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_OFDM0_AGCCORE1, &agc); + rtl8188eu_iqk_record_error(&result, status); + if (status == U80211_DRV_STATUS_SUCCESS) { + agc &= ~UINT32_C(0xff); + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_OFDM0_AGCCORE1, agc | 0x50); + rtl8188eu_iqk_record_error(&result, status); + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_OFDM0_AGCCORE1, agc | saved->agc_gain); + rtl8188eu_iqk_record_error(&result, status); + } + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_TX_IQK_TONE_A, 0x01008c00); + rtl8188eu_iqk_record_error(&result, status); + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_RX_IQK_TONE_A, 0x01008c00); + rtl8188eu_iqk_record_error(&result, status); + return result; +} + +static unsigned int rtl8188eu_iqk_difference(uint16_t a, uint16_t b) { + return a > b ? a - b : b - a; +} + +static bool rtl8188eu_iqk_results_close(const rtl8188eu_iqk_result_t *a, const rtl8188eu_iqk_result_t *b) { + if (!a->tx_valid || !a->rx_valid || !b->tx_valid || !b->rx_valid) + return false; + + return rtl8188eu_iqk_difference(a->tx[0], b->tx[0]) <= RTL8188EU_IQK_TOLERANCE && + rtl8188eu_iqk_difference(a->tx[1], b->tx[1]) <= RTL8188EU_IQK_TOLERANCE && + rtl8188eu_iqk_difference(a->rx[0], b->rx[0]) <= RTL8188EU_IQK_TOLERANCE && + rtl8188eu_iqk_difference(a->rx[1], b->rx[1]) <= RTL8188EU_IQK_TOLERANCE; +} + +static int32_t rtl8188eu_iqk_sign_extend_10(uint16_t value) { + return (value & 0x0200) != 0 ? (int32_t)value - 0x0400 : value; +} + +static int32_t rtl8188eu_iqk_arithmetic_shift(int32_t value, unsigned int shift) { + if (value >= 0) + return value >> shift; + + return -(((-value) + ((1u << shift) - 1)) >> shift); +} + +static int rtl8188eu_iqk_write_results(u80211_drv_device_handle_t device, const rtl8188eu_iqk_result_t *result) { + uint32_t reg; + int status = u80211_drv_rtl8188eu_reg_read32(device, RTL8188EU_REG_OFDM0_TXIQIMBALANCE_A, ®); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + uint32_t factor = (reg >> 22) & RTL8188EU_IQK_RESULT_MASK; + int32_t x_product = rtl8188eu_iqk_sign_extend_10(result->tx[0]) * (int32_t)factor; + int32_t tx_a = rtl8188eu_iqk_arithmetic_shift(x_product, 8); + + reg = (reg & ~UINT32_C(0x000003ff)) | ((uint32_t)tx_a & 0x000003ff); + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_OFDM0_TXIQIMBALANCE_A, reg); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read32(device, RTL8188EU_REG_OFDM0_ECCATHRESHOLD, ®); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if (((uint32_t)rtl8188eu_iqk_arithmetic_shift(x_product, 7) & 1) != 0) + reg |= UINT32_C(0x80000000); + else + reg &= ~UINT32_C(0x80000000); + + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_OFDM0_ECCATHRESHOLD, reg); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + int32_t y_product = rtl8188eu_iqk_sign_extend_10(result->tx[1]) * (int32_t)factor; + int32_t tx_c = rtl8188eu_iqk_arithmetic_shift(y_product, 8); + + status = u80211_drv_rtl8188eu_reg_read32(device, RTL8188EU_REG_OFDM0_TXAFE_A, ®); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + reg = (reg & ~UINT32_C(0xf0000000)) | (((uint32_t)tx_c & 0x000003c0) << 22); + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_OFDM0_TXAFE_A, reg); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read32(device, RTL8188EU_REG_OFDM0_TXIQIMBALANCE_A, ®); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + reg = (reg & ~UINT32_C(0x003f0000)) | (((uint32_t)tx_c & 0x0000003f) << 16); + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_OFDM0_TXIQIMBALANCE_A, reg); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read32(device, RTL8188EU_REG_OFDM0_ECCATHRESHOLD, ®); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if (((uint32_t)rtl8188eu_iqk_arithmetic_shift(y_product, 7) & 1) != 0) + reg |= UINT32_C(0x20000000); + else + reg &= ~UINT32_C(0x20000000); + + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_OFDM0_ECCATHRESHOLD, reg); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read32(device, RTL8188EU_REG_OFDM0_RXIQIMBALANCE_A, ®); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + reg = (reg & ~UINT32_C(0x000003ff)) | (result->rx[0] & 0x03ff); + reg = (reg & ~UINT32_C(0x0000fc00)) | ((uint32_t)(result->rx[1] & 0x003f) << 10); + status = u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_OFDM0_RXIQIMBALANCE_A, reg); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read32(device, RTL8188EU_REG_OFDM0_RXIQEXTANTA, ®); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + reg = (reg & ~UINT32_C(0xf0000000)) | ((uint32_t)(result->rx[1] & 0x03c0) << 22); + return u80211_drv_rtl8188eu_reg_write32(device, RTL8188EU_REG_OFDM0_RXIQEXTANTA, reg); +} + +static int rtl8188eu_iq_calibrate(u80211_drv_device_handle_t device) { + rtl8188eu_iqk_saved_t saved; + int status = rtl8188eu_iqk_save(device, &saved); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + rtl8188eu_iqk_result_t results[RTL8188EU_IQK_RUN_COUNT]; + bool hardware_modified = false; + bool stable = false; + unsigned int accepted_run = 0; + + for (unsigned int run = 0; run < RTL8188EU_IQK_RUN_COUNT; ++run) { + hardware_modified = true; + status = rtl8188eu_iqk_prepare(device, &saved); + if (status != U80211_DRV_STATUS_SUCCESS) + break; + + rtl8188eu_iqk_result_t discarded; + status = rtl8188eu_iqk_measure_once(device, &discarded); + if (status != U80211_DRV_STATUS_SUCCESS) + break; + status = rtl8188eu_iqk_measure_once(device, &results[run]); + if (status != U80211_DRV_STATUS_SUCCESS) + break; + status = rtl8188eu_iqk_leave_mode(device); + if (status != U80211_DRV_STATUS_SUCCESS) + break; + + if (run == 0) + continue; + + int restore_status = rtl8188eu_iqk_restore(device, &saved); + hardware_modified = false; + if (restore_status != U80211_DRV_STATUS_SUCCESS) { + status = restore_status; + break; + } + + if (rtl8188eu_iqk_results_close(&results[run - 1], &results[run])) { + stable = true; + accepted_run = run; + break; + } + } + + if (hardware_modified) { + int restore_status = rtl8188eu_iqk_restore(device, &saved); + if (status == U80211_DRV_STATUS_SUCCESS) + status = restore_status; + } + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if (!stable) { + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_WARN, "rtl8188eu: IQ calibration did not stabilize"); + return U80211_DRV_STATUS_SUCCESS; + } + + return rtl8188eu_iqk_write_results(device, &results[accepted_run]); +} + +static int rtl8188eu_lc_calibrate(u80211_drv_device_handle_t device) { + uint8_t txmode; + int status = u80211_drv_rtl8188eu_reg_read8(device, RTL8188EU_REG_OFDM1_LSTF + 3, &txmode); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + int result = U80211_DRV_STATUS_SUCCESS; + bool continuous_tx = (txmode & RTL8188EU_CONTINUOUS_TX_MASK) != 0; + bool txmode_modified = false; + bool txpause_modified = false; + bool rf_ac_modified = false; + uint8_t txpause = 0; + uint32_t rf_ac = 0; + + if (continuous_tx) { + // disable continuous tx + txmode_modified = true; + status = u80211_drv_rtl8188eu_reg_write8(device, RTL8188EU_REG_OFDM1_LSTF + 3, txmode & ~RTL8188EU_CONTINUOUS_TX_MASK); + if (status != U80211_DRV_STATUS_SUCCESS) { + result = status; + goto restore; + } + + status = u80211_drv_rtl8188eu_rf_read(device, RTL8188EU_RF_AC, &rf_ac); + if (status != U80211_DRV_STATUS_SUCCESS) { + result = status; + goto restore; + } + rf_ac_modified = true; + status = u80211_drv_rtl8188eu_rf_write(device, RTL8188EU_RF_AC, (rf_ac & ~RTL8188EU_RF_AC_MODE_MASK) | RTL8188EU_RF_AC_MODE_STANDBY); + if (status != U80211_DRV_STATUS_SUCCESS) { + result = status; + goto restore; + } + } else { + // pause tx + status = u80211_drv_rtl8188eu_reg_read8(device, RTL8188EU_REG_TXPAUSE, &txpause); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + txpause_modified = true; + status = u80211_drv_rtl8188eu_reg_write8(device, RTL8188EU_REG_TXPAUSE, UINT8_MAX); + if (status != U80211_DRV_STATUS_SUCCESS) { + result = status; + goto restore; + } + } + + // calibrate lc + uint32_t chnlbw; + status = u80211_drv_rtl8188eu_rf_read(device, U80211_DRV_RTL8188EU_RF_CHNLBW, &chnlbw); + if (status != U80211_DRV_STATUS_SUCCESS) { + result = status; + goto restore; + } + status = u80211_drv_rtl8188eu_rf_write( + device, + U80211_DRV_RTL8188EU_RF_CHNLBW, + chnlbw | RTL8188EU_RF_CHNLBW_LCSTART + ); + if (status != U80211_DRV_STATUS_SUCCESS) { + result = status; + goto restore; + } + + unsigned int poll; + for (poll = 0; poll < RTL8188EU_LC_MAX_POLLS; ++poll) { + status = u80211_drv_rtl8188eu_rf_read(device, U80211_DRV_RTL8188EU_RF_CHNLBW, &chnlbw); + if (status != U80211_DRV_STATUS_SUCCESS) { + result = status; + goto restore; + } + if ((chnlbw & RTL8188EU_RF_CHNLBW_LCSTART) == 0) + break; + + u80211_drv_kernel_stall_us(RTL8188EU_LC_POLL_DELAY_US); + } + if (poll == RTL8188EU_LC_MAX_POLLS) + result = U80211_DRV_STATUS_TIMEOUT; + +restore: + if (rf_ac_modified) { + status = u80211_drv_rtl8188eu_rf_write(device, RTL8188EU_RF_AC, rf_ac); + rtl8188eu_iqk_record_error(&result, status); + } + if (txmode_modified) { + status = u80211_drv_rtl8188eu_reg_write8(device, RTL8188EU_REG_OFDM1_LSTF + 3, txmode); + rtl8188eu_iqk_record_error(&result, status); + } + if (txpause_modified) { + status = u80211_drv_rtl8188eu_reg_write8(device, RTL8188EU_REG_TXPAUSE, txpause); + rtl8188eu_iqk_record_error(&result, status); + } + return result; +} + +static int rtl8188eu_calibration_gpio_cleanup(u80211_drv_device_handle_t device) { + uint8_t gpio; + int status = u80211_drv_rtl8188eu_reg_read8(device, RTL8188EU_REG_GPIO_MUXCFG, &gpio); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + return u80211_drv_rtl8188eu_reg_write8(device, RTL8188EU_REG_GPIO_MUXCFG, gpio & ~RTL8188EU_REG_GPIO_MUXCFG_ENBT); +} + +int u80211_drv_rtl8188eu_calibrate(u80211_drv_device_handle_t device) { + int status = rtl8188eu_iq_calibrate(device); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = rtl8188eu_lc_calibrate(device); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + return rtl8188eu_calibration_gpio_cleanup(device); +} diff --git a/kernel-src/io/net/u80211_drv/src/rtl8188eu/channel.c b/kernel-src/io/net/u80211_drv/src/rtl8188eu/channel.c new file mode 100644 index 00000000..39ad62c5 --- /dev/null +++ b/kernel-src/io/net/u80211_drv/src/rtl8188eu/channel.c @@ -0,0 +1,51 @@ +#include + +#include +#include + +// TODO: serialize channel setting (either here or in u80211) +int u80211_drv_rtl8188eu_set_channel(u80211_drv_rtl8188eu_t *rtl8188eu, uint8_t channel) { + if (channel < 1 || channel > 11) + return U80211_DRV_STATUS_INVALID_ARGUMENT; + + // set the transmission power for this channel + int status = u80211_drv_rtl8188eu_set_tx_power(rtl8188eu, channel); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // tell wmac to use 20 mhz-sized channels + uint8_t bwopmode; + status = u80211_drv_rtl8188eu_reg_read8(rtl8188eu->device, U80211_DRV_RTL8188EU_REG_BWOPMODE, &bwopmode); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + bwopmode |= U80211_DRV_RTL8188EU_REG_BWOPMODE_20MHZ; + status = u80211_drv_rtl8188eu_reg_write8(rtl8188eu->device, U80211_DRV_RTL8188EU_REG_BWOPMODE, bwopmode); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // tell baseband blocks we are using 20 mhz channels + uint32_t rfmod; + status = u80211_drv_rtl8188eu_reg_read32(rtl8188eu->device, U80211_DRV_RTL8188EU_REG_FPGA0_RFMOD, &rfmod); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + rfmod &= ~U80211_DRV_RTL8188EU_REG_FPGA_RFMOD_40MHZ; + status = u80211_drv_rtl8188eu_reg_write32(rtl8188eu->device, U80211_DRV_RTL8188EU_REG_FPGA0_RFMOD, rfmod); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read32(rtl8188eu->device, U80211_DRV_RTL8188EU_REG_FPGA1_RFMOD, &rfmod); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + rfmod &= ~U80211_DRV_RTL8188EU_REG_FPGA_RFMOD_40MHZ; + status = u80211_drv_rtl8188eu_reg_write32(rtl8188eu->device, U80211_DRV_RTL8188EU_REG_FPGA1_RFMOD, rfmod); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // program channel and 20mhz bandwidth + uint32_t chnlbw = rtl8188eu->rf_chnlbw & ~U80211_DRV_RTL8188EU_RF_CHNLBW_CHANNEL_BW_MASK; + chnlbw |= U80211_DRV_RTL8188EU_RF_CHNLBW_BW20 | channel; + return u80211_drv_rtl8188eu_rf_write(rtl8188eu->device, U80211_DRV_RTL8188EU_RF_CHNLBW, chnlbw); +} diff --git a/kernel-src/io/net/u80211_drv/src/rtl8188eu/efuse.c b/kernel-src/io/net/u80211_drv/src/rtl8188eu/efuse.c new file mode 100644 index 00000000..28367122 --- /dev/null +++ b/kernel-src/io/net/u80211_drv/src/rtl8188eu/efuse.c @@ -0,0 +1,202 @@ +#include + +#include +#include +#include +#include + +#define EFUSE_ADDRESS_HIGH_MASK 0x03 +#define EFUSE_CONTROL_READ_READY (1u << 7) +#define EFUSE_MAX_POLLS 500 +#define EFUSE_READ_SETTLE_US 50 +#define EFUSE_SECTION_LEN (U80211_DRV_RTL8188EU_EFUSE_WORDS_PER_SECTION * 2) +#define EFUSE_SECTION_COUNT (U80211_DRV_RTL8188EU_EFUSE_MAP_LEN / EFUSE_SECTION_LEN) +#define EFUSE_RTL_ID_OFFSET 0x000 +#define EFUSE_CCK_TX_POWER_BASE_INDEX_OFFSET 0x010 +#define EFUSE_HT40_1S_TX_POWER_BASE_INDEX_OFFSET 0x016 +#define EFUSE_HT20_OFDM_TX_POWER_DIFF_OFFSET 0x01b +#define EFUSE_XTAL_K_OFFSET 0x0b9 +#define EFUSE_MAC_ADDRESS_OFFSET 0x0d7 + +int u80211_drv_rtl8188eu_efuse_prepare(u80211_drv_device_handle_t device) { + uint16_t value; + int status; + + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_EFUSE_ACCESS, U80211_DRV_RTL8188EU_EFUSE_ACCESS_ENABLE); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read16(device, U80211_DRV_RTL8188EU_REG_SYS_ISO_CTRL, &value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if ((value & U80211_DRV_RTL8188EU_REG_SYS_ISO_CTRL_PWC_EV12V) == 0) { + value |= U80211_DRV_RTL8188EU_REG_SYS_ISO_CTRL_PWC_EV12V; + status = u80211_drv_rtl8188eu_reg_write16(device, U80211_DRV_RTL8188EU_REG_SYS_ISO_CTRL, value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + } + + status = u80211_drv_rtl8188eu_reg_read16(device, U80211_DRV_RTL8188EU_REG_SYS_FUNC, &value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if ((value & U80211_DRV_RTL8188EU_REG_SYS_FUNC_ELDR) == 0) { + value |= U80211_DRV_RTL8188EU_REG_SYS_FUNC_ELDR; + status = u80211_drv_rtl8188eu_reg_write16(device, U80211_DRV_RTL8188EU_REG_SYS_FUNC, value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + } + + status = u80211_drv_rtl8188eu_reg_read16(device, U80211_DRV_RTL8188EU_REG_SYS_CLKR, &value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + uint16_t required_clocks = U80211_DRV_RTL8188EU_REG_SYS_CLKR_LOADER_ENABLE | U80211_DRV_RTL8188EU_REG_SYS_CLKR_ANA8M; + if ((value & required_clocks) != required_clocks) { + value |= required_clocks; + status = u80211_drv_rtl8188eu_reg_write16(device, U80211_DRV_RTL8188EU_REG_SYS_CLKR, value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + } + + return U80211_DRV_STATUS_SUCCESS; +} + +int u80211_drv_rtl8188eu_efuse_finish(u80211_drv_device_handle_t device) { + return u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_EFUSE_ACCESS, U80211_DRV_RTL8188EU_EFUSE_ACCESS_DISABLE); +} + +static int efuse_read_physical8(u80211_drv_device_handle_t device, uint16_t address, uint8_t *result) { + if (address >= U80211_DRV_RTL8188EU_EFUSE_PHYSICAL_LEN) + return U80211_DRV_STATUS_FAULTY_HARDWARE; + + int status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_EFUSE_CTRL + 1, address & 0xff); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + uint8_t value8; + status = u80211_drv_rtl8188eu_reg_read8(device, U80211_DRV_RTL8188EU_REG_EFUSE_CTRL + 2, &value8); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value8 &= ~EFUSE_ADDRESS_HIGH_MASK; + value8 |= (address >> 8) & EFUSE_ADDRESS_HIGH_MASK; + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_EFUSE_CTRL + 2, value8); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read8(device, U80211_DRV_RTL8188EU_REG_EFUSE_CTRL + 3, &value8); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value8 &= ~EFUSE_CONTROL_READ_READY; + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_EFUSE_CTRL + 3, value8); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + uint32_t value32; + unsigned int poll; + for (poll = 0; poll < EFUSE_MAX_POLLS; ++poll) { + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_EFUSE_CTRL, &value32); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if ((value32 & U80211_DRV_RTL8188EU_REG_EFUSE_CTRL_READ_READY) != 0) + break; + } + + if (poll == EFUSE_MAX_POLLS) + return U80211_DRV_STATUS_TIMEOUT; + + u80211_drv_kernel_stall_us(EFUSE_READ_SETTLE_US); + + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_EFUSE_CTRL, &value32); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + *result = value32 & 0xff; + return U80211_DRV_STATUS_SUCCESS; +} + +int u80211_drv_rtl8188eu_read_efuse(u80211_drv_device_handle_t device, uint8_t efuse_map[U80211_DRV_RTL8188EU_EFUSE_MAP_LEN]) { + u80211_drv_memset(efuse_map, 0xff, U80211_DRV_RTL8188EU_EFUSE_MAP_LEN); + + uint16_t physical_address = 0; + while (physical_address < U80211_DRV_RTL8188EU_EFUSE_PHYSICAL_LEN) { + uint8_t header; + int status = efuse_read_physical8(device, physical_address++, &header); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if (header == 0xff) + return U80211_DRV_STATUS_SUCCESS; + + unsigned int section; + uint8_t word_mask; + if ((header & 0x1f) == 0x0f) { + section = (header & 0xe0) >> 5; + + if (physical_address >= U80211_DRV_RTL8188EU_EFUSE_PHYSICAL_LEN) + return U80211_DRV_STATUS_FAULTY_HARDWARE; + + uint8_t extended_header; + status = efuse_read_physical8(device, physical_address++, &extended_header); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if ((extended_header & 0x0f) == 0x0f) + continue; + + section |= (extended_header & 0xf0) >> 1; + word_mask = extended_header & 0x0f; + } else { + section = (header >> 4) & 0x0f; + word_mask = header & 0x0f; + } + + if (section >= EFUSE_SECTION_COUNT) + return U80211_DRV_STATUS_FAULTY_HARDWARE; + + uint16_t logical_address = section * EFUSE_SECTION_LEN; + for (unsigned int word = 0; word < U80211_DRV_RTL8188EU_EFUSE_WORDS_PER_SECTION; ++word) { + if ((word_mask & (1u << word)) != 0) { + logical_address += 2; + continue; + } + + if (logical_address + 1 >= U80211_DRV_RTL8188EU_EFUSE_MAP_LEN || physical_address + 1 >= U80211_DRV_RTL8188EU_EFUSE_PHYSICAL_LEN) + return U80211_DRV_STATUS_FAULTY_HARDWARE; + + status = efuse_read_physical8(device, physical_address++, &efuse_map[logical_address++]); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = efuse_read_physical8(device, physical_address++, &efuse_map[logical_address++]); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + } + } + + return U80211_DRV_STATUS_SUCCESS; +} + +int u80211_drv_rtl8188eu_parse_efuse(const uint8_t efuse_map[U80211_DRV_RTL8188EU_EFUSE_MAP_LEN], u80211_drv_rtl8188eu_efuse_t *result) { + uint16_t rtl_id = (uint16_t)efuse_map[EFUSE_RTL_ID_OFFSET] | ((uint16_t)efuse_map[EFUSE_RTL_ID_OFFSET + 1] << 8); + if (rtl_id != U80211_DRV_RTL8188EU_EFUSE_RTL_ID) + return U80211_DRV_STATUS_FAULTY_HARDWARE; + + result->rtl_id = rtl_id; + for (unsigned int i = 0; i < U80211_DRV_RTL8188EU_MAC_ADDRESS_LEN; ++i) + result->mac_address[i] = efuse_map[EFUSE_MAC_ADDRESS_OFFSET + i]; + + for (unsigned int i = 0; i < U80211_DRV_RTL8188EU_CCK_TX_POWER_BASE_INDEX_COUNT; ++i) + result->cck_tx_power_base_indexes[i] = efuse_map[EFUSE_CCK_TX_POWER_BASE_INDEX_OFFSET + i]; + + for (unsigned int i = 0; i < U80211_DRV_RTL8188EU_HT40_1S_TX_POWER_BASE_INDEX_COUNT; ++i) + result->ht40_1s_tx_power_base_indexes[i] = efuse_map[EFUSE_HT40_1S_TX_POWER_BASE_INDEX_OFFSET + i]; + result->ht20_ofdm_tx_power_diff = efuse_map[EFUSE_HT20_OFDM_TX_POWER_DIFF_OFFSET]; + + result->xtal_k = efuse_map[EFUSE_XTAL_K_OFFSET] & 0x3f; + return U80211_DRV_STATUS_SUCCESS; +} diff --git a/kernel-src/io/net/u80211_drv/src/rtl8188eu/firmware.c b/kernel-src/io/net/u80211_drv/src/rtl8188eu/firmware.c new file mode 100644 index 00000000..b975320f --- /dev/null +++ b/kernel-src/io/net/u80211_drv/src/rtl8188eu/firmware.c @@ -0,0 +1,265 @@ +#include +#include + +#include +#include + +#define RTL8188EU_FIRMWARE_SIGNATURE 0x88e +#define RTL8188EU_FIRMWARE_PREPARE_DELAY_US 50 +#define RTL8188EU_FIRMWARE_WRITE_SIZE 196 +#define RTL8188EU_FIRMWARE_PAGE_COUNT 8 +#define RTL8188EU_FIRMWARE_MAX_POLLS 1000 +#define RTL8188EU_FIRMWARE_CHECKSUM_POLL_DELAY_US 5 +#define RTL8188EU_FIRMWARE_READY_POLL_DELAY_US 10 + +static int firmware_reset(u80211_drv_device_handle_t device) { + // hold mcu wrapper + uint8_t value8; + int status = u80211_drv_rtl8188eu_reg_read8(device, U80211_DRV_RTL8188EU_REG_RSV_CTRL, &value8); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value8 &= ~U80211_DRV_RTL8188EU_REG_RSV_CTRL_WLOCK_00; + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_RSV_CTRL, value8); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // assert wrapper reset + uint16_t value16; + status = u80211_drv_rtl8188eu_reg_read16(device, U80211_DRV_RTL8188EU_REG_RSV_CTRL, &value16); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value16 &= ~U80211_DRV_RTL8188EU_REG_RSV_CTRL_MCU_RST; + status = u80211_drv_rtl8188eu_reg_write16(device, U80211_DRV_RTL8188EU_REG_RSV_CTRL, value16); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // assert cpu reset + status = u80211_drv_rtl8188eu_reg_read16(device, U80211_DRV_RTL8188EU_REG_SYS_FUNC, &value16); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value16 &= ~U80211_DRV_RTL8188EU_REG_SYS_FUNC_CPUEN; + status = u80211_drv_rtl8188eu_reg_write16(device, U80211_DRV_RTL8188EU_REG_SYS_FUNC, value16); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // hold mcu wrapper + status = u80211_drv_rtl8188eu_reg_read8(device, U80211_DRV_RTL8188EU_REG_RSV_CTRL, &value8); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value8 &= ~U80211_DRV_RTL8188EU_REG_RSV_CTRL_WLOCK_00; + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_RSV_CTRL, value8); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // deassert mcu wrapper reset + status = u80211_drv_rtl8188eu_reg_read16(device, U80211_DRV_RTL8188EU_REG_RSV_CTRL, &value16); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value16 |= U80211_DRV_RTL8188EU_REG_RSV_CTRL_MCU_RST; + status = u80211_drv_rtl8188eu_reg_write16(device, U80211_DRV_RTL8188EU_REG_RSV_CTRL, value16); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // deassert cpu reset + status = u80211_drv_rtl8188eu_reg_read16(device, U80211_DRV_RTL8188EU_REG_SYS_FUNC, &value16); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value16 |= U80211_DRV_RTL8188EU_REG_SYS_FUNC_CPUEN; + return u80211_drv_rtl8188eu_reg_write16(device, U80211_DRV_RTL8188EU_REG_SYS_FUNC, value16); +} + +int u80211_drv_rtl8188eu_firmware_prepare(u80211_drv_device_handle_t device, const void *firmware_data, size_t firmware_size, const uint8_t **firmware_payload, size_t *firmware_payload_size) { + // verify if the firmware is ok + const uint8_t *payload = firmware_data; + size_t payload_size = firmware_size; + uint16_t signature = (uint16_t)payload[0] | ((uint16_t)payload[1] << 8); + if ((signature >> 4) == RTL8188EU_FIRMWARE_SIGNATURE) { + payload += U80211_DRV_RTL8188EU_FIRMWARE_HEADER_SIZE; + payload_size -= U80211_DRV_RTL8188EU_FIRMWARE_HEADER_SIZE; + } + + // check if there is stale ram in the mcu + uint8_t value8; + int status = u80211_drv_rtl8188eu_reg_read8(device, U80211_DRV_RTL8188EU_REG_MCUFWDL, &value8); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if ((value8 & U80211_DRV_RTL8188EU_REG_MCUFWDL_RAM_DOWNLOAD_SELECT) != 0) { + // clear stale ram and reset firmware + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_MCUFWDL, 0); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = firmware_reset(device); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + } + + // enable firmware download + status = u80211_drv_rtl8188eu_reg_read8(device, U80211_DRV_RTL8188EU_REG_MCUFWDL, &value8); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value8 |= U80211_DRV_RTL8188EU_REG_MCUFWDL_ENABLE; + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_MCUFWDL, value8); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + uint32_t value32; + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_MCUFWDL, &value32); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value32 &= ~U80211_DRV_RTL8188EU_REG_MCUFWDL_ROM_DOWNLOAD_LENGTH; + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_MCUFWDL, value32); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // reset firmware checksum + status = u80211_drv_rtl8188eu_reg_read8(device, U80211_DRV_RTL8188EU_REG_MCUFWDL, &value8); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value8 |= U80211_DRV_RTL8188EU_REG_MCUFWDL_CHECKSUM_REPORT; + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_MCUFWDL, value8); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + u80211_drv_kernel_stall_us(RTL8188EU_FIRMWARE_PREPARE_DELAY_US); + *firmware_payload = payload; + *firmware_payload_size = payload_size; + return U80211_DRV_STATUS_SUCCESS; +} + +static int firmware_write_page(u80211_drv_device_handle_t device, unsigned int page, const uint8_t *data, size_t size) { + // set the page selector + uint32_t value; + int status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_MCUFWDL, &value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value &= ~U80211_DRV_RTL8188EU_REG_MCUFWDL_PAGE_MASK; + value |= (uint32_t)page << 16; + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_MCUFWDL, value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // write firmware in 196-byte chunks. + // this is actually needed because some chips apparently have issues + // with different-sized writes: https://github.com/a5a5aa555oo/rtl8xxxu/issues/2 + uint16_t address = U80211_DRV_RTL8188EU_FIRMWARE_START_ADDRESS; + while (size >= RTL8188EU_FIRMWARE_WRITE_SIZE) { + status = u80211_drv_rtl8188eu_reg_write_region(device, address, data, RTL8188EU_FIRMWARE_WRITE_SIZE); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + address += RTL8188EU_FIRMWARE_WRITE_SIZE; + data += RTL8188EU_FIRMWARE_WRITE_SIZE; + size -= RTL8188EU_FIRMWARE_WRITE_SIZE; + } + + if (size != 0) + return u80211_drv_rtl8188eu_reg_write_region(device, address, data, (uint16_t)size); + + return U80211_DRV_STATUS_SUCCESS; +} + +int u80211_drv_rtl8188eu_firmware_upload(u80211_drv_device_handle_t device, const uint8_t *firmware_payload, size_t firmware_payload_size) { + if (firmware_payload_size > U80211_DRV_RTL8188EU_FIRMWARE_PAGE_SIZE * RTL8188EU_FIRMWARE_PAGE_COUNT) + return U80211_DRV_STATUS_INVALID_ARGUMENT; + + unsigned int page = 0; + while (firmware_payload_size != 0) { + size_t page_size = firmware_payload_size; + if (page_size > U80211_DRV_RTL8188EU_FIRMWARE_PAGE_SIZE) + page_size = U80211_DRV_RTL8188EU_FIRMWARE_PAGE_SIZE; + + int status = firmware_write_page(device, page, firmware_payload, page_size); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + firmware_payload += page_size; + firmware_payload_size -= page_size; + ++page; + } + + return U80211_DRV_STATUS_SUCCESS; +} + +int u80211_drv_rtl8188eu_firmware_start(u80211_drv_device_handle_t device) { + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: waiting for firmware checksum"); + + uint32_t value32; + unsigned int poll; + int status; + for (poll = 0; poll < RTL8188EU_FIRMWARE_MAX_POLLS; ++poll) { + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_MCUFWDL, &value32); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if ((value32 & U80211_DRV_RTL8188EU_REG_MCUFWDL_CHECKSUM_REPORT) != 0) + break; + + u80211_drv_kernel_stall_us(RTL8188EU_FIRMWARE_CHECKSUM_POLL_DELAY_US); + } + + if (poll == RTL8188EU_FIRMWARE_MAX_POLLS) { + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_ERROR, "rtl8188eu: firmware checksum timed out"); + return U80211_DRV_STATUS_TIMEOUT; + } + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: firmware checksum ready"); + + // leave firmware download mode + uint8_t value8; + status = u80211_drv_rtl8188eu_reg_read8(device, U80211_DRV_RTL8188EU_REG_MCUFWDL, &value8); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value8 &= ~U80211_DRV_RTL8188EU_REG_MCUFWDL_ENABLE; + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_MCUFWDL, value8); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_MCUFWDL + 1, 0); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // mark the downloaded image ready and discard stale firmware state + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_MCUFWDL, &value32); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value32 &= ~U80211_DRV_RTL8188EU_REG_MCUFWDL_WINTINI_READY; + value32 |= U80211_DRV_RTL8188EU_REG_MCUFWDL_READY; + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_MCUFWDL, value32); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = firmware_reset(device); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: waiting for firmware ready"); + for (poll = 0; poll < RTL8188EU_FIRMWARE_MAX_POLLS; ++poll) { + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_MCUFWDL, &value32); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if ((value32 & U80211_DRV_RTL8188EU_REG_MCUFWDL_WINTINI_READY) != 0) { + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: firmware ready"); + return U80211_DRV_STATUS_SUCCESS; + } + + u80211_drv_kernel_stall_us(RTL8188EU_FIRMWARE_READY_POLL_DELAY_US); + } + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_ERROR, "rtl8188eu: firmware ready timed out"); + return U80211_DRV_STATUS_TIMEOUT; +} diff --git a/kernel-src/io/net/u80211_drv/src/rtl8188eu/key.c b/kernel-src/io/net/u80211_drv/src/rtl8188eu/key.c new file mode 100644 index 00000000..e7fed524 --- /dev/null +++ b/kernel-src/io/net/u80211_drv/src/rtl8188eu/key.c @@ -0,0 +1,129 @@ +#include +#include +#include + +#include +#include +#include + +#define RTL8188EU_CAM_WRITE_DELAY_US 100 +#define RTL8188EU_CAM_KEY_WORD_FIRST 2 +#define RTL8188EU_CAM_KEY_WORD_LAST 5 + +static int rtl8188eu_cam_write_word(u80211_drv_device_handle_t device, uint8_t entry, uint8_t word, uint32_t value) { + uint32_t address = (uint32_t)entry * U80211_DRV_RTL8188EU_CAM_ENTRY_WORD_COUNT + word; + int status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_CAMWRITE, value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write32(device, + U80211_DRV_RTL8188EU_REG_CAMCMD, + U80211_DRV_RTL8188EU_REG_CAMCMD_POLLING | U80211_DRV_RTL8188EU_REG_CAMCMD_WRITE | address + ); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + u80211_drv_kernel_stall_us(RTL8188EU_CAM_WRITE_DELAY_US); + return U80211_DRV_STATUS_SUCCESS; +} + +static int rtl8188eu_key_parameters(const u80211_drv_key_t *key, uint32_t *algorithm) { + switch (key->cipher) { + case U80211_DRV_CIPHER_CCMP: + if (key->key_len != 16) + return U80211_DRV_STATUS_INVALID_ARGUMENT; + + *algorithm = U80211_DRV_RTL8188EU_CAM_ALGORITHM_CCMP; + return U80211_DRV_STATUS_SUCCESS; + case U80211_DRV_CIPHER_TKIP: + if (key->key_len != 32) + return U80211_DRV_STATUS_INVALID_ARGUMENT; + + *algorithm = U80211_DRV_RTL8188EU_CAM_ALGORITHM_TKIP; + return U80211_DRV_STATUS_SUCCESS; + case U80211_DRV_CIPHER_WEP40: + if (key->key_len != 5) + return U80211_DRV_STATUS_INVALID_ARGUMENT; + + *algorithm = U80211_DRV_RTL8188EU_CAM_ALGORITHM_WEP40; + return U80211_DRV_STATUS_SUCCESS; + case U80211_DRV_CIPHER_WEP104: + if (key->key_len != 13) + return U80211_DRV_STATUS_INVALID_ARGUMENT; + + *algorithm = U80211_DRV_RTL8188EU_CAM_ALGORITHM_WEP104; + return U80211_DRV_STATUS_SUCCESS; + default: + return U80211_DRV_STATUS_NOT_SUPPORTED; + } +} + +static uint32_t rtl8188eu_key_word(const u80211_drv_key_t *key, size_t offset) { + uint32_t value = 0; + for (size_t i = 0; i < sizeof(value) && offset + i < key->key_len && offset + i < 16; ++i) + value |= (uint32_t)key->key[offset + i] << (i * 8); + + return value; +} + +#define KNOWN_FLAGS (U80211_DRV_KEY_PAIRWISE | U80211_DRV_KEY_GROUP | U80211_DRV_KEY_RX | U80211_DRV_KEY_TX) + +int u80211_drv_rtl8188eu_set_key(u80211_drv_rtl8188eu_t *rtl8188eu, const u80211_drv_key_t *key) { + if (key->index > U80211_DRV_RTL8188EU_CAM_CTL0_KEY_ID_MASK) + return U80211_DRV_STATUS_INVALID_ARGUMENT; + + bool pairwise = (key->flags & U80211_DRV_KEY_PAIRWISE) != 0; + bool group = (key->flags & U80211_DRV_KEY_GROUP) != 0; + if (pairwise == group || (key->flags & (U80211_DRV_KEY_RX | U80211_DRV_KEY_TX)) == 0 || (key->flags & ~KNOWN_FLAGS) != 0) + return U80211_DRV_STATUS_INVALID_ARGUMENT; + + uint32_t algorithm; + int status = rtl8188eu_key_parameters(key, &algorithm); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // invalidate an existing entry before changing any of its contents + status = rtl8188eu_cam_write_word(rtl8188eu->device, key->index, 0, 0); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // clear the high words + status = rtl8188eu_cam_write_word(rtl8188eu->device, key->index, 6, 0); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = rtl8188eu_cam_write_word(rtl8188eu->device, key->index, 7, 0); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // copy the key + for (uint8_t word = RTL8188EU_CAM_KEY_WORD_FIRST; word <= RTL8188EU_CAM_KEY_WORD_LAST; ++word) { + status = rtl8188eu_cam_write_word(rtl8188eu->device, key->index, word, rtl8188eu_key_word(key, (word - 2) * 4)); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + } + + // write the mac address high bytes + uint32_t mac_high = key->peer[2] | ((uint32_t)key->peer[3] << 8) | ((uint32_t)key->peer[4] << 16) | ((uint32_t)key->peer[5] << 24); + status = rtl8188eu_cam_write_word(rtl8188eu->device, key->index, 1, mac_high); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // write key id, cipher id, low mac bytes and valid bit + uint32_t control = (key->index & U80211_DRV_RTL8188EU_CAM_CTL0_KEY_ID_MASK) | + (algorithm << U80211_DRV_RTL8188EU_CAM_CTL0_ALGORITHM_SHIFT) | + U80211_DRV_RTL8188EU_CAM_CTL0_VALID | + ((uint32_t)key->peer[0] << 16) | + ((uint32_t)key->peer[1] << 24); + if (group) + control |= U80211_DRV_RTL8188EU_CAM_CTL0_GROUP; + + return rtl8188eu_cam_write_word(rtl8188eu->device, key->index, 0, control); +} + +int u80211_drv_rtl8188eu_del_key(u80211_drv_rtl8188eu_t *rtl8188eu, uint8_t index) { + if (index > U80211_DRV_RTL8188EU_CAM_CTL0_KEY_ID_MASK) + return U80211_DRV_STATUS_INVALID_ARGUMENT; + + return rtl8188eu_cam_write_word(rtl8188eu->device, index, 0, 0); +} diff --git a/kernel-src/io/net/u80211_drv/src/rtl8188eu/mac.c b/kernel-src/io/net/u80211_drv/src/rtl8188eu/mac.c new file mode 100644 index 00000000..61fd46ef --- /dev/null +++ b/kernel-src/io/net/u80211_drv/src/rtl8188eu/mac.c @@ -0,0 +1,384 @@ +#include + +#include +#include + +#define RTL8188EU_LLT_MAX_POLLS 20 +#define RTL8188EU_LLT_POLL_DELAY_US 5 + +int u80211_drv_rtl8188eu_mac_enable_infrastructure(u80211_drv_device_handle_t device) { + // explicitly leave the RX and TX engines disabled. + uint16_t cr = U80211_DRV_RTL8188EU_REG_CR_HCI_TXDMA_ENABLE | + U80211_DRV_RTL8188EU_REG_CR_HCI_RXDMA_ENABLE | + U80211_DRV_RTL8188EU_REG_CR_TXDMA_ENABLE | + U80211_DRV_RTL8188EU_REG_CR_RXDMA_ENABLE | + U80211_DRV_RTL8188EU_REG_CR_PROTOCOL_ENABLE | + U80211_DRV_RTL8188EU_REG_CR_SCHEDULE_ENABLE | + U80211_DRV_RTL8188EU_REG_CR_SECURITY_ENABLE | + U80211_DRV_RTL8188EU_REG_CR_CALTIMER_ENABLE; + + return u80211_drv_rtl8188eu_reg_write16(device, U80211_DRV_RTL8188EU_REG_CR, cr); +} + +int u80211_drv_rtl8188eu_mac_enable_tx_rx(u80211_drv_device_handle_t device) { + const uint16_t enable_mask = U80211_DRV_RTL8188EU_REG_CR_MAC_TX_ENABLE | U80211_DRV_RTL8188EU_REG_CR_MAC_RX_ENABLE; + uint16_t cr; + int status = u80211_drv_rtl8188eu_reg_read16(device, U80211_DRV_RTL8188EU_REG_CR, &cr); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + cr |= enable_mask; + status = u80211_drv_rtl8188eu_reg_write16(device, U80211_DRV_RTL8188EU_REG_CR, cr); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read16(device, U80211_DRV_RTL8188EU_REG_CR, &cr); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if ((cr & enable_mask) != enable_mask) + return U80211_DRV_STATUS_FAULTY_HARDWARE; + + return U80211_DRV_STATUS_SUCCESS; +} + +int u80211_drv_rtl8188eu_mac_disable_rx_aggregation(u80211_drv_device_handle_t device) { + uint8_t usb_special; + int status = u80211_drv_rtl8188eu_reg_read8(device, U80211_DRV_RTL8188EU_REG_USB_SPECIAL_OPTION, &usb_special); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + usb_special &= ~U80211_DRV_RTL8188EU_REG_USB_SPECIAL_OPTION_AGG_ENABLE; + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_USB_SPECIAL_OPTION, usb_special); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + uint8_t trxdma_ctrl; + status = u80211_drv_rtl8188eu_reg_read8(device, U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL, &trxdma_ctrl); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + trxdma_ctrl &= ~U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL_RXDMA_AGG_ENABLE; + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL, trxdma_ctrl); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read8(device, U80211_DRV_RTL8188EU_REG_USB_SPECIAL_OPTION, &usb_special); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read8(device, U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL, &trxdma_ctrl); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if ((usb_special & U80211_DRV_RTL8188EU_REG_USB_SPECIAL_OPTION_AGG_ENABLE) != 0 || (trxdma_ctrl & U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL_RXDMA_AGG_ENABLE) != 0) + return U80211_DRV_STATUS_FAULTY_HARDWARE; + + return U80211_DRV_STATUS_SUCCESS; +} + +static uint16_t tx_queue_mapping(uint8_t bulk_out_endpoint_count) { + // map wifi traffic classes onto hardware queues + uint16_t vi_queue = bulk_out_endpoint_count >= 2 ? U80211_DRV_RTL8188EU_TRXDMA_QUEUE_NORMAL : U80211_DRV_RTL8188EU_TRXDMA_QUEUE_HIGH; + uint16_t be_bk_queue; + + if (bulk_out_endpoint_count >= 3) + be_bk_queue = U80211_DRV_RTL8188EU_TRXDMA_QUEUE_LOW; + else if (bulk_out_endpoint_count == 2) + be_bk_queue = U80211_DRV_RTL8188EU_TRXDMA_QUEUE_NORMAL; + else + be_bk_queue = U80211_DRV_RTL8188EU_TRXDMA_QUEUE_HIGH; + + return (U80211_DRV_RTL8188EU_TRXDMA_QUEUE_HIGH << U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL_VO_SHIFT) | + (vi_queue << U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL_VI_SHIFT) | + (be_bk_queue << U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL_BE_SHIFT) | + (be_bk_queue << U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL_BK_SHIFT) | + (U80211_DRV_RTL8188EU_TRXDMA_QUEUE_HIGH << U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL_MG_SHIFT) | + (U80211_DRV_RTL8188EU_TRXDMA_QUEUE_HIGH << U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL_HI_SHIFT); +} + +int u80211_drv_rtl8188eu_mac_configure_tx_queues(u80211_drv_device_handle_t device, uint8_t bulk_out_endpoint_count) { + // configure packet buffer pages + uint32_t high_pages = U80211_DRV_RTL8188EU_TX_PAGE_NUM_HI_PQ; + uint32_t normal_pages = bulk_out_endpoint_count >= 2 ? U80211_DRV_RTL8188EU_TX_PAGE_NUM_NORM_PQ : 0; + uint32_t low_pages = bulk_out_endpoint_count >= 3 ? U80211_DRV_RTL8188EU_TX_PAGE_NUM_LO_PQ : 0; + uint32_t public_pages = U80211_DRV_RTL8188EU_TX_TOTAL_PAGE_NUM - high_pages - normal_pages - low_pages - 1; + + int status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_RQPN_NPQ, normal_pages << U80211_DRV_RTL8188EU_REG_RQPN_NPQ_SHIFT); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + uint32_t rqpn = U80211_DRV_RTL8188EU_REG_RQPN_LOAD | + (high_pages << U80211_DRV_RTL8188EU_REG_RQPN_HI_SHIFT) | + (low_pages << U80211_DRV_RTL8188EU_REG_RQPN_LO_SHIFT) | + (public_pages << U80211_DRV_RTL8188EU_REG_RQPN_PUB_SHIFT); + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_RQPN, rqpn); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + uint16_t trxdma_ctrl; + status = u80211_drv_rtl8188eu_reg_read16(device, U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL, &trxdma_ctrl); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + trxdma_ctrl = (trxdma_ctrl & U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL_LOW_CONTROL_MASK) | tx_queue_mapping(bulk_out_endpoint_count); + return u80211_drv_rtl8188eu_reg_write16(device, U80211_DRV_RTL8188EU_REG_TRXDMA_CTRL, trxdma_ctrl); +} + +int u80211_drv_rtl8188eu_mac_configure_rx_fifo_boundary(u80211_drv_device_handle_t device) { + uint16_t reg = U80211_DRV_RTL8188EU_REG_TRXFF_BNDY + 2; + int status = u80211_drv_rtl8188eu_reg_write16(device, reg, U80211_DRV_RTL8188EU_RX_FIFO_BOUNDARY); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + uint16_t boundary; + status = u80211_drv_rtl8188eu_reg_read16(device, reg, &boundary); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if (boundary != U80211_DRV_RTL8188EU_RX_FIFO_BOUNDARY) + return U80211_DRV_STATUS_FAULTY_HARDWARE; + + return U80211_DRV_STATUS_SUCCESS; +} + +int u80211_drv_rtl8188eu_mac_configure_packet_buffer(u80211_drv_device_handle_t device) { + uint8_t boundary = U80211_DRV_RTL8188EU_TX_TOTAL_PAGE_NUM + 1; + const uint16_t boundary_regs[] = { + U80211_DRV_RTL8188EU_REG_TXPKTBUF_BCNQ_BDNY, + U80211_DRV_RTL8188EU_REG_TXPKTBUF_MGQ_BDNY, + U80211_DRV_RTL8188EU_REG_TXPKTBUF_WMAC_LBK_BF_HD, + U80211_DRV_RTL8188EU_REG_TRXFF_BNDY, + U80211_DRV_RTL8188EU_REG_TDECTRL + 1, + }; + + for (size_t i = 0; i < sizeof(boundary_regs) / sizeof(boundary_regs[0]); ++i) { + int status = u80211_drv_rtl8188eu_reg_write8(device, boundary_regs[i], boundary); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + } + + return u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_PBP, U80211_DRV_RTL8188EU_REG_PBP_128_BYTES); +} + +static int rtl8188eu_llt_write(u80211_drv_device_handle_t device, uint8_t address, uint8_t data) { + // write the LLT entry + uint32_t command = U80211_DRV_RTL8188EU_REG_LLT_INIT_OP_WRITE | ((uint32_t)address << 8) | data; + int status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_LLT_INIT, command); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // wait for the write operation to complete + for (unsigned int poll = 0; poll < RTL8188EU_LLT_MAX_POLLS; ++poll) { + uint32_t value; + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_LLT_INIT, &value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if ((value & U80211_DRV_RTL8188EU_REG_LLT_INIT_OP_MASK) == 0) + return U80211_DRV_STATUS_SUCCESS; + + u80211_drv_kernel_stall_us(RTL8188EU_LLT_POLL_DELAY_US); + } + + return U80211_DRV_STATUS_TIMEOUT; +} + +int u80211_drv_rtl8188eu_mac_initialize_llt(u80211_drv_device_handle_t device) { + // write the linear tx page list + for (unsigned int entry = 0; entry < U80211_DRV_RTL8188EU_TX_TOTAL_PAGE_NUM; ++entry) { + int status = rtl8188eu_llt_write(device, (uint8_t)entry, (uint8_t)(entry + 1)); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + } + + int status = rtl8188eu_llt_write(device, U80211_DRV_RTL8188EU_TX_TOTAL_PAGE_NUM, U80211_DRV_RTL8188EU_LLT_END); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // write the cyclic pages + uint8_t first_remaining_page = U80211_DRV_RTL8188EU_TX_TOTAL_PAGE_NUM + 1; + for (unsigned int entry = first_remaining_page; entry < U80211_DRV_RTL8188EU_LLT_LAST_ENTRY; ++entry) { + status = rtl8188eu_llt_write(device, (uint8_t)entry, (uint8_t)(entry + 1)); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + } + + return rtl8188eu_llt_write(device, U80211_DRV_RTL8188EU_LLT_LAST_ENTRY, first_remaining_page); +} + +int u80211_drv_rtl8188eu_mac_configure_wmac(u80211_drv_rtl8188eu_t *rtl8188eu) { + // 32-byte phy data aftter every rx descriptor + u80211_drv_device_handle_t device = rtl8188eu->device; + int status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_RX_DRVINFO_SZ, U80211_DRV_RTL8188EU_RX_DRVINFO_SZ); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // program the efuse mac into the wmac + for (unsigned int i = 0; i < U80211_DRV_RTL8188EU_MAC_ADDRESS_LEN; ++i) { + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_MACID + i, rtl8188eu->efuse.mac_address[i]); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + } + + // set to 'no link' mode + uint8_t msr; + status = u80211_drv_rtl8188eu_reg_read8(device, U80211_DRV_RTL8188EU_REG_MSR, &msr); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + msr &= ~U80211_DRV_RTL8188EU_REG_MSR_NETWORK_TYPE_MASK; + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_MSR, msr); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // configure the receive filter + // (any frames, append phy receive status, report icv and mic information) + uint32_t rcr = U80211_DRV_RTL8188EU_REG_RCR_AAP | + U80211_DRV_RTL8188EU_REG_RCR_APM | + U80211_DRV_RTL8188EU_REG_RCR_AM | + U80211_DRV_RTL8188EU_REG_RCR_AB | + U80211_DRV_RTL8188EU_REG_RCR_AMF | + U80211_DRV_RTL8188EU_REG_RCR_HTC_LOC_CTRL | + U80211_DRV_RTL8188EU_REG_RCR_APP_PHYSTS | + U80211_DRV_RTL8188EU_REG_RCR_APP_ICV | + U80211_DRV_RTL8188EU_REG_RCR_APP_MIC; + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_RCR, rcr); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // accept all multicasts + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_MAR, UINT32_MAX); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_MAR + 4, UINT32_MAX); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // accept management and data, reject control + status = u80211_drv_rtl8188eu_reg_write16(device, U80211_DRV_RTL8188EU_REG_RXFLTMAP0, UINT16_MAX); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write16(device, U80211_DRV_RTL8188EU_REG_RXFLTMAP1, 0); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + return u80211_drv_rtl8188eu_reg_write16(device, U80211_DRV_RTL8188EU_REG_RXFLTMAP2, UINT16_MAX); +} + +int u80211_drv_rtl8188eu_mac_set_edca(u80211_drv_device_handle_t device, u80211_drv_rtl8188eu_access_category_t access_category, u80211_drv_rtl8188eu_edca_params_t params) { + uint16_t reg; + switch (access_category) { + case U80211_DRV_RTL8188EU_ACCESS_CATEGORY_VO: + reg = U80211_DRV_RTL8188EU_REG_EDCA_VO; + break; + case U80211_DRV_RTL8188EU_ACCESS_CATEGORY_VI: + reg = U80211_DRV_RTL8188EU_REG_EDCA_VI; + break; + case U80211_DRV_RTL8188EU_ACCESS_CATEGORY_BE: + reg = U80211_DRV_RTL8188EU_REG_EDCA_BE; + break; + case U80211_DRV_RTL8188EU_ACCESS_CATEGORY_BK: + reg = U80211_DRV_RTL8188EU_REG_EDCA_BK; + break; + default: + return U80211_DRV_STATUS_INVALID_ARGUMENT; + } + + unsigned int aifs = params.aifsn * params.slot_time + 10; + if (params.ecwmin > 0x0f || params.ecwmax > 0x0f || aifs > UINT8_MAX) + return U80211_DRV_STATUS_INVALID_ARGUMENT; + + uint32_t value = ((uint32_t)params.txop << 16) | ((uint32_t)params.ecwmax << 12) | ((uint32_t)params.ecwmin << 8) | aifs; + return u80211_drv_rtl8188eu_reg_write32(device, reg, value); +} + +int u80211_drv_rtl8188eu_mac_configure_timing(u80211_drv_device_handle_t device) { + // set fallback response rate to 1mbps using cck + uint32_t rrsr; + int status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_RRSR, &rrsr); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + rrsr = (rrsr & ~U80211_DRV_RTL8188EU_REG_RRSR_RATE_MASK) | U80211_DRV_RTL8188EU_REG_RRSR_RATE_CCK_ONLY_1M; + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_RRSR, rrsr); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // set retry limits to 48 retries + status = u80211_drv_rtl8188eu_reg_write16(device, U80211_DRV_RTL8188EU_REG_RL, 0x3030); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // configure SIFS + const uint16_t sifs_regs[] = { + U80211_DRV_RTL8188EU_REG_SPEC_SIFS, + U80211_DRV_RTL8188EU_REG_SIFS_CCK, + U80211_DRV_RTL8188EU_REG_SIFS_OFDM, + U80211_DRV_RTL8188EU_REG_MAC_SPEC_SIFS, + U80211_DRV_RTL8188EU_REG_RESP_SIFS_CCK, + U80211_DRV_RTL8188EU_REG_RESP_SIFS_OFDM, + }; + for (size_t i = 0; i < sizeof(sifs_regs) / sizeof(sifs_regs[0]); ++i) { + status = u80211_drv_rtl8188eu_reg_write16(device, sifs_regs[i], 0x100a); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + } + + // use AMPDU new retry mechanism + uint8_t txq_ctrl; + status = u80211_drv_rtl8188eu_reg_read8(device, U80211_DRV_RTL8188EU_REG_FWHW_TXQ_CTRL, &txq_ctrl); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + txq_ctrl |= U80211_DRV_RTL8188EU_REG_FWHW_TXQ_CTRL_AMPDU_RTY_NEW; + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_FWHW_TXQ_CTRL, txq_ctrl); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // set ack timeout to 64 microseconds + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_ACKTO, 0x40); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // initialize beacon packet machinery + status = u80211_drv_rtl8188eu_reg_write16(device, U80211_DRV_RTL8188EU_REG_BCN_CTRL, 0x1010); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write16(device, U80211_DRV_RTL8188EU_REG_TBTT_PROHIBIT, 0x6404); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_DRVERLYINT, 0x05); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_BCNDMATIM, 0x02); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + return u80211_drv_rtl8188eu_reg_write16(device, U80211_DRV_RTL8188EU_REG_BCNTCFG, 0x660f); +} + +int u80211_drv_rtl8188eu_mac_configure_hardware_offloads(u80211_drv_device_handle_t device) { + // configure encryption offload + uint32_t cam_command = U80211_DRV_RTL8188EU_REG_CAMCMD_CLR | U80211_DRV_RTL8188EU_REG_CAMCMD_POLLING; + int status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_CAMCMD, cam_command); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // station-mode WPA keys are selected from the CAM by peer address or the + // cipher-header key ID. the default-key bits are for legacy key selection + // and can make encrypted data use a different CAM entry than the handshake. + uint8_t security_config = U80211_DRV_RTL8188EU_REG_SECCFG_TXENC_ENABLE | + U80211_DRV_RTL8188EU_REG_SECCFG_RXENC_ENABLE; + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_SECCFG, security_config); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // configure sequence handling offload + return u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_HWSEQ_CTRL, UINT8_MAX); +} diff --git a/kernel-src/io/net/u80211_drv/src/rtl8188eu/mac_table.c b/kernel-src/io/net/u80211_drv/src/rtl8188eu/mac_table.c new file mode 100644 index 00000000..2369b165 --- /dev/null +++ b/kernel-src/io/net/u80211_drv/src/rtl8188eu/mac_table.c @@ -0,0 +1,70 @@ +/* $OpenBSD: r92creg.h,v 1.31 2024/09/01 03:14:48 jsg Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include +#include + +#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) + +typedef struct { + uint16_t reg; + uint8_t value; +} rtl8188eu_reg8_t; + +// Imported from OpenBSD sys/dev/ic/r92creg.h. +static const rtl8188eu_reg8_t rtl8188eu_mac_table[] = { + { 0x026, 0x41 }, { 0x027, 0x35 }, { 0x040, 0x00 }, { 0x428, 0x0a }, + { 0x429, 0x10 }, { 0x430, 0x00 }, { 0x431, 0x01 }, { 0x432, 0x02 }, + { 0x433, 0x04 }, { 0x434, 0x05 }, { 0x435, 0x06 }, { 0x436, 0x07 }, + { 0x437, 0x08 }, { 0x438, 0x00 }, { 0x439, 0x00 }, { 0x43a, 0x01 }, + { 0x43b, 0x02 }, { 0x43c, 0x04 }, { 0x43d, 0x05 }, { 0x43e, 0x06 }, + { 0x43f, 0x07 }, { 0x440, 0x5d }, { 0x441, 0x01 }, { 0x442, 0x00 }, + { 0x444, 0x15 }, { 0x445, 0xf0 }, { 0x446, 0x0f }, { 0x447, 0x00 }, + { 0x458, 0x41 }, { 0x459, 0xa8 }, { 0x45a, 0x72 }, { 0x45b, 0xb9 }, + { 0x460, 0x66 }, { 0x461, 0x66 }, { 0x480, 0x08 }, { 0x4c8, 0xff }, + { 0x4c9, 0x08 }, { 0x4cc, 0xff }, { 0x4cd, 0xff }, { 0x4ce, 0x01 }, + { 0x4d3, 0x01 }, { 0x500, 0x26 }, { 0x501, 0xa2 }, { 0x502, 0x2f }, + { 0x503, 0x00 }, { 0x504, 0x28 }, { 0x505, 0xa3 }, { 0x506, 0x5e }, + { 0x507, 0x00 }, { 0x508, 0x2b }, { 0x509, 0xa4 }, { 0x50a, 0x5e }, + { 0x50b, 0x00 }, { 0x50c, 0x4f }, { 0x50d, 0xa4 }, { 0x50e, 0x00 }, + { 0x50f, 0x00 }, { 0x512, 0x1c }, { 0x514, 0x0a }, { 0x516, 0x0a }, + { 0x525, 0x4f }, { 0x550, 0x10 }, { 0x551, 0x10 }, { 0x559, 0x02 }, + { 0x55d, 0xff }, { 0x605, 0x30 }, { 0x608, 0x0e }, { 0x609, 0x2a }, + { 0x620, 0xff }, { 0x621, 0xff }, { 0x622, 0xff }, { 0x623, 0xff }, + { 0x624, 0xff }, { 0x625, 0xff }, { 0x626, 0xff }, { 0x627, 0xff }, + { 0x652, 0x20 }, { 0x63c, 0x0a }, { 0x63d, 0x0a }, { 0x63e, 0x0e }, + { 0x63f, 0x0e }, { 0x640, 0x40 }, { 0x66e, 0x05 }, { 0x700, 0x21 }, + { 0x701, 0x43 }, { 0x702, 0x65 }, { 0x703, 0x87 }, { 0x708, 0x21 }, + { 0x709, 0x43 }, { 0x70a, 0x65 }, { 0x70b, 0x87 } +}; + +int u80211_drv_rtl8188eu_mac_load_table(u80211_drv_device_handle_t device) { + for (size_t i = 0; i < ARRAY_SIZE(rtl8188eu_mac_table); ++i) { + int status = u80211_drv_rtl8188eu_reg_write8(device, rtl8188eu_mac_table[i].reg, rtl8188eu_mac_table[i].value); + if (status != U80211_DRV_STATUS_SUCCESS) { + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_ERROR, "rtl8188eu: MAC table write failed"); + return status; + } + } + + return u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_MAX_AGGR_NUM, U80211_DRV_RTL8188EU_REG_MAX_AGGR_NUM_8188EU); +} diff --git a/kernel-src/io/net/u80211_drv/src/rtl8188eu/main.c b/kernel-src/io/net/u80211_drv/src/rtl8188eu/main.c new file mode 100644 index 00000000..8e4480e1 --- /dev/null +++ b/kernel-src/io/net/u80211_drv/src/rtl8188eu/main.c @@ -0,0 +1,360 @@ +#include +#include +#include + +static int u80211_drv_rtl8188eu_led_enable_activity(u80211_drv_device_handle_t device) { + uint8_t ledcfg; + int status = u80211_drv_rtl8188eu_reg_read8(device, U80211_DRV_RTL8188EU_REG_LEDCFG2, &ledcfg); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + ledcfg &= ~U80211_DRV_RTL8188EU_REG_LEDCFG2_SW_LED_DISABLE; + ledcfg |= U80211_DRV_RTL8188EU_REG_LEDCFG2_HW_LED_CONTROL | U80211_DRV_RTL8188EU_REG_LEDCFG2_HW_LED_ENABLE; + return u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_LEDCFG2, ledcfg); +} + +static int transmit(void *device, void *buffer, size_t size, size_t current_offset, const u80211_drv_transmit_options_t *options) { + return u80211_drv_rtl8188eu_transmit(device, buffer, size, current_offset, options); +} + +static int set_channel(void *device, uint8_t channel) { + return u80211_drv_rtl8188eu_set_channel(device, channel); +} + +static int set_key(void *device, const u80211_drv_key_t *key) { + return u80211_drv_rtl8188eu_set_key(device, key); +} + +static int del_key(void *device, uint8_t index) { + return u80211_drv_rtl8188eu_del_key(device, index); +} + +static const u80211_drv_device_ops_t device_ops = { + .allocate_tx_buffer = u80211_drv_rtl8188eu_tx_buffer_allocate, + .free_tx_buffer = u80211_drv_rtl8188eu_tx_buffer_free, + .transmit = transmit, + .set_channel = set_channel, + .set_key = set_key, + .del_key = del_key, +}; + +static int discover_bulk_endpoints(u80211_drv_rtl8188eu_t *rtl8188eu) { + u80211_drv_interface_descriptor_t interface_descriptor; + int status = u80211_drv_kernel_get_interface_descriptor(rtl8188eu->interface, &interface_descriptor); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if (interface_descriptor.endpoint_count == 0) + return U80211_DRV_STATUS_NOT_SUPPORTED; + + u80211_drv_endpoint_descriptor_t *endpoints = u80211_drv_kernel_allocate(interface_descriptor.endpoint_count * sizeof(*endpoints)); + if (endpoints == NULL) + return U80211_DRV_STATUS_OUT_OF_MEMORY; + + status = u80211_drv_kernel_get_endpoints(rtl8188eu->interface, endpoints, interface_descriptor.endpoint_count); + if (status != U80211_DRV_STATUS_SUCCESS) { + u80211_drv_kernel_free(endpoints); + return status; + } + + rtl8188eu->bulk_out_endpoint_count = 0; + rtl8188eu->rx_endpoint = 0; + rtl8188eu->tx_endpoint_high = 0; + rtl8188eu->tx_endpoint_normal = 0; + rtl8188eu->tx_endpoint_low = 0; + + for (uint8_t i = 0; i < interface_descriptor.endpoint_count; ++i) { + if ((endpoints[i].attributes & U80211_DRV_KERNEL_ENDPOINT_TRANSFER_TYPE_MASK) != U80211_DRV_KERNEL_ENDPOINT_TRANSFER_TYPE_BULK) + continue; + if ((endpoints[i].address & U80211_DRV_KERNEL_XFER_DIRECTION_MASK) == U80211_DRV_KERNEL_XFER_IN) { + if (rtl8188eu->rx_endpoint == 0) + rtl8188eu->rx_endpoint = endpoints[i].address; + continue; + } + + switch (rtl8188eu->bulk_out_endpoint_count) { + case 0: + rtl8188eu->tx_endpoint_high = endpoints[i].address; + break; + case 1: + rtl8188eu->tx_endpoint_normal = endpoints[i].address; + break; + case 2: + rtl8188eu->tx_endpoint_low = endpoints[i].address; + break; + } + + ++rtl8188eu->bulk_out_endpoint_count; + } + + u80211_drv_kernel_free(endpoints); + + if (rtl8188eu->rx_endpoint == 0 || rtl8188eu->bulk_out_endpoint_count == 0) + return U80211_DRV_STATUS_NOT_SUPPORTED; + + return U80211_DRV_STATUS_SUCCESS; +} + +static void firmware_loaded(void *context, const void *firmware_data, size_t firmware_size) { + u80211_drv_rtl8188eu_t *rtl8188eu = context; + // the firmware is now in memory, we can continue initializing the chip. + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: found rtl8188eufw.bin"); + int status = u80211_drv_rtl8188eu_power_active(rtl8188eu->device); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + status = u80211_drv_rtl8188eu_mac_enable_infrastructure(rtl8188eu->device); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + status = u80211_drv_rtl8188eu_mac_configure_tx_queues(rtl8188eu->device, rtl8188eu->bulk_out_endpoint_count); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + status = u80211_drv_rtl8188eu_mac_configure_rx_fifo_boundary(rtl8188eu->device); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: uploading firmware"); + + // upload the firmware into the MCU + const uint8_t *firmware_payload; + size_t firmware_payload_size; + status = u80211_drv_rtl8188eu_firmware_prepare( + rtl8188eu->device, + firmware_data, + firmware_size, + &firmware_payload, + &firmware_payload_size + ); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + status = u80211_drv_rtl8188eu_firmware_upload(rtl8188eu->device, firmware_payload, firmware_payload_size); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + status = u80211_drv_rtl8188eu_firmware_start(rtl8188eu->device); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: firmware initialized"); + + status = u80211_drv_rtl8188eu_mac_load_table(rtl8188eu->device); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: MAC table initialized"); + + status = u80211_drv_rtl8188eu_bb_enable(rtl8188eu->device); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + status = u80211_drv_rtl8188eu_bb_load_table(rtl8188eu->device); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: BB table initialized"); + + status = u80211_drv_rtl8188eu_bb_load_agc_table(rtl8188eu->device); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: AGC table initialized"); + + status = u80211_drv_rtl8188eu_bb_apply_efuse_calibration(rtl8188eu); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: EFUSE crystal calibration applied"); + + status = u80211_drv_rtl8188eu_rf_load_table(rtl8188eu->device); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: RF table initialized"); + + status = u80211_drv_rtl8188eu_rf_read(rtl8188eu->device, U80211_DRV_RTL8188EU_RF_CHNLBW, &rtl8188eu->rf_chnlbw); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: RF channel state cached"); + + status = u80211_drv_rtl8188eu_mac_configure_packet_buffer(rtl8188eu->device); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: packet buffer configured"); + + status = u80211_drv_rtl8188eu_mac_initialize_llt(rtl8188eu->device); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: LLT initialized"); + + status = u80211_drv_rtl8188eu_mac_enable_tx_rx(rtl8188eu->device); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: MAC TX and RX enabled"); + + status = u80211_drv_rtl8188eu_mac_disable_rx_aggregation(rtl8188eu->device); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: RX aggregation disabled"); + + status = u80211_drv_rtl8188eu_mac_configure_wmac(rtl8188eu); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: WMAC configured"); + + status = u80211_drv_rtl8188eu_mac_configure_timing(rtl8188eu->device); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: timing configured"); + + status = u80211_drv_rtl8188eu_bb_enable_datapaths(rtl8188eu->device); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: BB datapaths enabled"); + + status = u80211_drv_rtl8188eu_mac_configure_hardware_offloads(rtl8188eu->device); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: hardware offloads configured"); + + status = u80211_drv_rtl8188eu_calibrate(rtl8188eu->device); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: RF calibration complete"); + + status = u80211_drv_rtl8188eu_set_channel(rtl8188eu, 1); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: channel 1 configured"); + + status = u80211_drv_rtl8188eu_led_enable_activity(rtl8188eu->device); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: activity LED enabled"); + + status = u80211_drv_rtl8188eu_rx_start(rtl8188eu); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: RX started"); + + u80211_drv_device_metadata_t metadata = { + .rate_bitmap = { + 0x14, // 1 and 2 Mbps + 0x18, // 5.5 and 6 Mbps + 0x44, // 9 and 11 Mbps + 0x01, // 12 Mbps + 0x10, // 18 Mbps + 0x00, + 0x01, // 24 Mbps + 0x00, + 0x00, + 0x01, // 36 Mbps + 0x00, + 0x00, + 0x01, // 48 Mbps + 0x10, // 54 Mbps + 0x00, + 0x00, + }, + }; + for (size_t i = 0; i < U80211_DRV_DEVICE_MAC_ADDRESS_LEN; ++i) + metadata.mac_address[i] = rtl8188eu->efuse.mac_address[i]; + + status = u80211_drv_device_ready(rtl8188eu, &metadata, &device_ops, &rtl8188eu->network_device); + if (status != U80211_DRV_STATUS_SUCCESS) + goto error; + + return; +error: + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_ERROR, "rtl8188eu: post firmware initialization failed"); +} + +int u80211_drv_rtl8188eu_init(u80211_drv_device_handle_t device, u80211_drv_interface_handle_t interface) { + uint32_t sys_cfg; + int status; + + // some cuts are not supported by this driver, check if we are attaching one of them + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_SYS_CFG, &sys_cfg); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if ((sys_cfg & U80211_DRV_RTL8188EU_REG_SYS_CFG_TRP_VAUX_EN) != 0 || U80211_DRV_RTL8188EU_REG_SYS_CFG_VER(sys_cfg) == 8) + return U80211_DRV_STATUS_NOT_SUPPORTED; + + u80211_drv_rtl8188eu_t *rtl8188eu = u80211_drv_kernel_allocate(sizeof(*rtl8188eu)); + if (rtl8188eu == NULL) + return U80211_DRV_STATUS_OUT_OF_MEMORY; + + rtl8188eu->device = device; + rtl8188eu->interface = interface; + __atomic_store_n(&rtl8188eu->network_device, NULL, __ATOMIC_RELAXED); + + // this is necessary to set up the TX queues and submit RX transfers later + status = discover_bulk_endpoints(rtl8188eu); + if (status != U80211_DRV_STATUS_SUCCESS) { + u80211_drv_kernel_free(rtl8188eu); + return status; + } + + // read efuses to get information like the MAC address + uint8_t *efuse_map = u80211_drv_kernel_allocate(U80211_DRV_RTL8188EU_EFUSE_MAP_LEN); + if (efuse_map == NULL) { + u80211_drv_kernel_free(rtl8188eu); + return U80211_DRV_STATUS_OUT_OF_MEMORY; + } + + status = u80211_drv_rtl8188eu_efuse_prepare(device); + if (status != U80211_DRV_STATUS_SUCCESS) { + u80211_drv_kernel_free(efuse_map); + u80211_drv_kernel_free(rtl8188eu); + return status; + } + + status = u80211_drv_rtl8188eu_read_efuse(device, efuse_map); + if (status != U80211_DRV_STATUS_SUCCESS) { + u80211_drv_kernel_free(efuse_map); + u80211_drv_kernel_free(rtl8188eu); + return status; + } + + status = u80211_drv_rtl8188eu_efuse_finish(device); + if (status != U80211_DRV_STATUS_SUCCESS) { + u80211_drv_kernel_free(efuse_map); + u80211_drv_kernel_free(rtl8188eu); + return status; + } + + status = u80211_drv_rtl8188eu_parse_efuse(efuse_map, &rtl8188eu->efuse); + if (status != U80211_DRV_STATUS_SUCCESS) { + u80211_drv_kernel_free(efuse_map); + u80211_drv_kernel_free(rtl8188eu); + return status; + } + + u80211_drv_kernel_free(efuse_map); + + // wait until firmware gets loaded from disk by the kernel + // TODO: have a way of cancelling this wait for detach + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: waiting for rtl8188eufw.bin"); + status = u80211_drv_kernel_get_firmware("rtl8188eufw.bin", firmware_loaded, rtl8188eu); + if (status != U80211_DRV_STATUS_SUCCESS) + u80211_drv_kernel_free(rtl8188eu); + + return status; +} diff --git a/kernel-src/io/net/u80211_drv/src/rtl8188eu/power.c b/kernel-src/io/net/u80211_drv/src/rtl8188eu/power.c new file mode 100644 index 00000000..69b2be3b --- /dev/null +++ b/kernel-src/io/net/u80211_drv/src/rtl8188eu/power.c @@ -0,0 +1,117 @@ +#include + +#include +#include +#include + +#define POWER_MAX_POLLS 500 +#define POWER_POLL_DELAY_US 10 + +int u80211_drv_rtl8188eu_power_active(u80211_drv_device_handle_t device) { + uint16_t value16; + int status = u80211_drv_rtl8188eu_reg_read16(device, U80211_DRV_RTL8188EU_REG_APS_FSMCO, &value16); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // disable wlan suspend and some pcie state machine stuff? + value16 &= ~(U80211_DRV_RTL8188EU_REG_APS_FSMCO_HW_SUSPEND | U80211_DRV_RTL8188EU_REG_APS_FSMCO_PCIE); + status = u80211_drv_rtl8188eu_reg_write16(device, U80211_DRV_RTL8188EU_REG_APS_FSMCO, value16); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: waiting for power ready"); + + uint32_t value32; + unsigned int poll; + for (poll = 0; poll < POWER_MAX_POLLS; ++poll) { + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_APS_FSMCO, &value32); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if ((value32 & U80211_DRV_RTL8188EU_REG_APS_FSMCO_POWER_READY) != 0) + break; + + u80211_drv_kernel_stall_us(POWER_POLL_DELAY_US); + } + + if (poll == POWER_MAX_POLLS) + return U80211_DRV_STATUS_TIMEOUT; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: power ready"); + + // hold baseband off for now + uint8_t value8; + status = u80211_drv_rtl8188eu_reg_read8(device, U80211_DRV_RTL8188EU_REG_SYS_FUNC, &value8); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value8 &= ~(U80211_DRV_RTL8188EU_REG_SYS_FUNC_BBRSTB | U80211_DRV_RTL8188EU_REG_SYS_FUNC_BB_GLB_RSTN); + status = u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_SYS_FUNC, value8); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // configure analog frontend crystal + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_AFE_XTAL_CTRL, &value32); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value32 |= U80211_DRV_RTL8188EU_REG_AFE_XTAL_CTRL_SCHMITT_TRIGGER; + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_AFE_XTAL_CTRL, value32); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // power on the device proper (disable hardware power down bit) + status = u80211_drv_rtl8188eu_reg_read16(device, U80211_DRV_RTL8188EU_REG_APS_FSMCO, &value16); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value16 &= ~U80211_DRV_RTL8188EU_REG_APS_FSMCO_HW_POWERDOWN; + status = u80211_drv_rtl8188eu_reg_write16(device, U80211_DRV_RTL8188EU_REG_APS_FSMCO, value16); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // disable wlan suspend and pcie state machine stuff (again) + status = u80211_drv_rtl8188eu_reg_read16(device, U80211_DRV_RTL8188EU_REG_APS_FSMCO, &value16); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value16 &= ~(U80211_DRV_RTL8188EU_REG_APS_FSMCO_HW_SUSPEND | U80211_DRV_RTL8188EU_REG_APS_FSMCO_PCIE); + status = u80211_drv_rtl8188eu_reg_write16(device, U80211_DRV_RTL8188EU_REG_APS_FSMCO, value16); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + // enable MAC + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_APS_FSMCO, &value32); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value32 |= U80211_DRV_RTL8188EU_REG_APS_FSMCO_MAC_ENABLE; + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_APS_FSMCO, value32); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: waiting for MAC ready"); + for (poll = 0; poll < POWER_MAX_POLLS; ++poll) { + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_APS_FSMCO, &value32); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if ((value32 & U80211_DRV_RTL8188EU_REG_APS_FSMCO_MAC_ENABLE) == 0) + break; + + u80211_drv_kernel_stall_us(POWER_POLL_DELAY_US); + } + + if (poll == POWER_MAX_POLLS) + return U80211_DRV_STATUS_TIMEOUT; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "rtl8188eu: MAC ready"); + + // enable low power low-dropout + status = u80211_drv_rtl8188eu_reg_read8(device, U80211_DRV_RTL8188EU_REG_LPLDO_CTRL, &value8); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value8 &= ~U80211_DRV_RTL8188EU_REG_LPLDO_CTRL_SLEEP; + return u80211_drv_rtl8188eu_reg_write8(device, U80211_DRV_RTL8188EU_REG_LPLDO_CTRL, value8); +} diff --git a/kernel-src/io/net/u80211_drv/src/rtl8188eu/register.c b/kernel-src/io/net/u80211_drv/src/rtl8188eu/register.c new file mode 100644 index 00000000..e2d23f03 --- /dev/null +++ b/kernel-src/io/net/u80211_drv/src/rtl8188eu/register.c @@ -0,0 +1,84 @@ +#include +#include + +#include +#include +#include +#include + +enum { + REALTEK_USB_READ = 0xc0, + REALTEK_USB_WRITE = 0x40, + REALTEK_USB_CMD_REQ = 0x05, + REALTEK_USB_CMD_IDX = 0x00, + REALTEK_USB_TIMEOUT_MS = 500, +}; + +static int reg_xfer(u80211_drv_device_handle_t device, uint8_t flags, uint16_t reg, void *data, uint16_t size) { + size_t transferred = 0; + int status = u80211_drv_kernel_submit_control_xfer_and_wait( + device, + flags, + REALTEK_USB_CMD_REQ, + reg, + REALTEK_USB_CMD_IDX, + data, + size, + &transferred, + REALTEK_USB_TIMEOUT_MS + ); + + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + if (transferred != size) + return U80211_DRV_STATUS_UNKNOWN_ERROR; + + return U80211_DRV_STATUS_SUCCESS; +} + +static int reg_read(u80211_drv_device_handle_t device, uint16_t reg, void *value, uint16_t size) { + return reg_xfer(device, REALTEK_USB_READ, reg, value, size); +} + +int u80211_drv_rtl8188eu_reg_read8(u80211_drv_device_handle_t device, uint16_t reg, uint8_t *value) { + return reg_read(device, reg, value, sizeof(*value)); +} + +int u80211_drv_rtl8188eu_reg_read16(u80211_drv_device_handle_t device, uint16_t reg, uint16_t *value) { + uint16_t little_endian_value; + int status = reg_read(device, reg, &little_endian_value, sizeof(little_endian_value)); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + *value = u80211_drv_le_to_host16(little_endian_value); + return U80211_DRV_STATUS_SUCCESS; +} + +int u80211_drv_rtl8188eu_reg_read32(u80211_drv_device_handle_t device, uint16_t reg, uint32_t *value) { + uint32_t little_endian_value; + int status = reg_read(device, reg, &little_endian_value, sizeof(little_endian_value)); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + *value = u80211_drv_le_to_host32(little_endian_value); + return U80211_DRV_STATUS_SUCCESS; +} + +int u80211_drv_rtl8188eu_reg_write8(u80211_drv_device_handle_t device, uint16_t reg, uint8_t value) { + return reg_xfer(device, REALTEK_USB_WRITE, reg, &value, sizeof(value)); +} + +int u80211_drv_rtl8188eu_reg_write16(u80211_drv_device_handle_t device, uint16_t reg, uint16_t value) { + uint16_t little_endian_value = u80211_drv_host_to_le16(value); + return reg_xfer(device, REALTEK_USB_WRITE, reg, &little_endian_value, sizeof(little_endian_value)); +} + +int u80211_drv_rtl8188eu_reg_write32(u80211_drv_device_handle_t device, uint16_t reg, uint32_t value) { + uint32_t little_endian_value = u80211_drv_host_to_le32(value); + return reg_xfer(device, REALTEK_USB_WRITE, reg, &little_endian_value, sizeof(little_endian_value)); +} + +int u80211_drv_rtl8188eu_reg_write_region(u80211_drv_device_handle_t device, uint16_t reg, const void *data, uint16_t size) { + return reg_xfer(device, REALTEK_USB_WRITE, reg, (void *)data, size); +} diff --git a/kernel-src/io/net/u80211_drv/src/rtl8188eu/rf_table.c b/kernel-src/io/net/u80211_drv/src/rtl8188eu/rf_table.c new file mode 100644 index 00000000..5cf6eed1 --- /dev/null +++ b/kernel-src/io/net/u80211_drv/src/rtl8188eu/rf_table.c @@ -0,0 +1,224 @@ +/* $OpenBSD: r92creg.h,v 1.31 2024/09/01 03:14:48 jsg Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include +#include + +#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) +#define RTL8188EU_RF_TABLE_ENTRY_COUNT 95 +#define RTL8188EU_RF_READ_DELAY_US 1000 + +// Imported from OpenBSD sys/dev/ic/r92creg.h. +static const uint16_t rtl8188eu_rf_regs[] = { + 0x00, 0x08, 0x18, 0x19, 0x1e, 0x1f, 0x2f, 0x3f, 0x42, 0x57, 0x58, + 0x67, 0x83, 0xb0, 0xb1, 0xb2, 0xb4, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, + 0xbb, 0xbf, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, + 0xdf, 0xef, 0x51, 0x52, 0x53, 0x56, 0x35, 0x35, 0x35, 0x36, 0x36, + 0x36, 0x36, 0xb6, 0x18, 0x5a, 0x19, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x00, 0x84, 0x86, 0x87, 0x8e, + 0x8f, 0xef, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xef, 0x00, 0x18, 0xfe, + 0xfe, 0x1f, 0xfe, 0xfe, 0x1e, 0x1f, 0x00 +}; + +static const uint32_t rtl8188eu_rf_values[] = { + 0x30000, 0x84000, 0x00407, 0x00012, 0x80009, 0x00880, 0x1a060, + 0x00000, 0x060c0, 0xd0000, 0xbe180, 0x01552, 0x00000, 0xff8fc, + 0x54400, 0xccc19, 0x43003, 0x4953e, 0x1c718, 0x060ff, 0x80001, + 0x40000, 0x00400, 0xc0000, 0x02400, 0x00009, 0x40c91, 0x99999, + 0x000a3, 0x88820, 0x76c06, 0x00000, 0x80000, 0x00180, 0x001a0, + 0x6b27d, 0x7e49d, 0x00073, 0x51ff3, 0x00086, 0x00186, 0x00286, + 0x01c25, 0x09c25, 0x11c25, 0x19c25, 0x48538, 0x00c07, 0x4bd00, + 0x739d0, 0x0adf3, 0x09df0, 0x08ded, 0x07dea, 0x06de7, 0x054ee, + 0x044eb, 0x034e8, 0x0246b, 0x01468, 0x0006d, 0x30159, 0x68200, + 0x000ce, 0x48a00, 0x65540, 0x88000, 0x020a0, 0xf02b0, 0xef7b0, + 0xd4fb0, 0xcf060, 0xb0090, 0xa0080, 0x90080, 0x8f780, 0x722b0, + 0x6f7b0, 0x54fb0, 0x4f060, 0x30090, 0x20080, 0x10080, 0x0f780, + 0x000a0, 0x10159, 0x0f407, 0x00000, 0x00000, 0x80003, 0x00000, + 0x00000, 0x00001, 0x80000, 0x33e60 +}; + +int u80211_drv_rtl8188eu_rf_write(u80211_drv_device_handle_t device, uint8_t rf_reg, uint32_t value) { + uint32_t command = ((uint32_t)rf_reg << U80211_DRV_RTL8188EU_REG_LSSI_PARAM_ADDRESS_SHIFT) | (value & U80211_DRV_RTL8188EU_REG_LSSI_PARAM_DATA_MASK); + int status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_LSSI_PARAM_A, command); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + u80211_drv_kernel_stall_us(1); + return U80211_DRV_STATUS_SUCCESS; +} + +int u80211_drv_rtl8188eu_rf_read(u80211_drv_device_handle_t device, uint8_t rf_reg, uint32_t *value) { + // drop read edge + uint32_t hssi_param2; + int status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_A, &hssi_param2); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_A, hssi_param2 & ~U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_READ_EDGE); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + u80211_drv_kernel_stall_us(RTL8188EU_RF_READ_DELAY_US); + + // program rf register address and raise read edge + uint32_t command = hssi_param2 & ~U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_READ_ADDRESS_MASK; + command |= ((uint32_t)rf_reg << U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_READ_ADDRESS_SHIFT) & U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_READ_ADDRESS_MASK; + command |= U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_READ_EDGE; + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_A, command); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + u80211_drv_kernel_stall_us(RTL8188EU_RF_READ_DELAY_US); + + // read back + uint32_t hssi_param1; + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_HSSI_PARAM1_A, &hssi_param1); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + uint16_t readback_reg = (hssi_param1 & U80211_DRV_RTL8188EU_REG_HSSI_PARAM1_PI) != 0 ? U80211_DRV_RTL8188EU_REG_HSPI_READBACK_A : U80211_DRV_RTL8188EU_REG_LSSI_READBACK_A; + uint32_t readback; + status = u80211_drv_rtl8188eu_reg_read32(device, readback_reg, &readback); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + *value = readback & U80211_DRV_RTL8188EU_RF_READBACK_MASK; + return U80211_DRV_STATUS_SUCCESS; +} + +static int rtl8188eu_rf_prepare(u80211_drv_device_handle_t device) { + uint32_t value; + int status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_RF_IFACE_OE_A, &value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value |= U80211_DRV_RTL8188EU_REG_RF_IFACE_OE_RF_ENV_ENABLE; + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_RF_IFACE_OE_A, value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + u80211_drv_kernel_stall_us(50); + + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_RF_IFACE_OE_A, &value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value |= U80211_DRV_RTL8188EU_REG_RF_IFACE_OE_RF_ENV; + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_RF_IFACE_OE_A, value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + u80211_drv_kernel_stall_us(50); + + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_A, &value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value &= ~U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_ADDRESS_LENGTH; + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_A, value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + u80211_drv_kernel_stall_us(50); + + status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_A, &value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value &= ~U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_DATA_LENGTH; + status = u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_HSSI_PARAM2_A, value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + u80211_drv_kernel_stall_us(50); + + return U80211_DRV_STATUS_SUCCESS; +} + +static int rtl8188eu_rf_apply_table(u80211_drv_device_handle_t device) { + for (size_t i = 0; i < ARRAY_SIZE(rtl8188eu_rf_regs); ++i) { + uint16_t reg = rtl8188eu_rf_regs[i]; + uint32_t delay; + + switch (reg) { + case 0xfe: + case 0xffe: + delay = 50000; + break; + case 0xfd: + delay = 5000; + break; + case 0xfc: + delay = 1000; + break; + case 0xfb: + delay = 50; + break; + case 0xfa: + delay = 5; + break; + case 0xf9: + delay = 1; + break; + default: { + int status = u80211_drv_rtl8188eu_rf_write(device, (uint8_t)reg, rtl8188eu_rf_values[i]); + if (status != U80211_DRV_STATUS_SUCCESS) { + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_ERROR, "rtl8188eu: RF table write failed"); + return status; + } + + u80211_drv_kernel_stall_us(5); + continue; + } + } + + u80211_drv_kernel_stall_us(delay); + } + + return U80211_DRV_STATUS_SUCCESS; +} + +static int rtl8188eu_rf_restore_env(u80211_drv_device_handle_t device, uint32_t saved_rf_env) { + uint32_t value; + int status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_RF_IFACE_SW_A, &value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value &= ~U80211_DRV_RTL8188EU_REG_RF_IFACE_SW_RF_ENV; + value |= saved_rf_env; + return u80211_drv_rtl8188eu_reg_write32(device, U80211_DRV_RTL8188EU_REG_RF_IFACE_SW_A, value); +} + +int u80211_drv_rtl8188eu_rf_load_table(u80211_drv_device_handle_t device) { + uint32_t value; + int status = u80211_drv_rtl8188eu_reg_read32(device, U80211_DRV_RTL8188EU_REG_RF_IFACE_SW_A, &value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + uint32_t saved_rf_env = value & U80211_DRV_RTL8188EU_REG_RF_IFACE_SW_RF_ENV; + status = rtl8188eu_rf_prepare(device); + if (status == U80211_DRV_STATUS_SUCCESS) + status = rtl8188eu_rf_apply_table(device); + + int restore_status = rtl8188eu_rf_restore_env(device, saved_rf_env); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + return restore_status; +} diff --git a/kernel-src/io/net/u80211_drv/src/rtl8188eu/rx.c b/kernel-src/io/net/u80211_drv/src/rtl8188eu/rx.c new file mode 100644 index 00000000..30d530d4 --- /dev/null +++ b/kernel-src/io/net/u80211_drv/src/rtl8188eu/rx.c @@ -0,0 +1,142 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + +#define RTL8188EU_RX_DESCRIPTOR_SIZE 24 +#define RTL8188EU_RX_BUFFER_SIZE (16 * 1024) + +#define RTL8188EU_RX_DESCRIPTOR_PACKET_LENGTH_MASK 0x00003fff +#define RTL8188EU_RX_DESCRIPTOR_CRC_ERROR (1u << 14) +#define RTL8188EU_RX_DESCRIPTOR_ICV_ERROR (1u << 15) +#define RTL8188EU_RX_DESCRIPTOR_DRVINFO_SIZE_MASK 0x000f0000 +#define RTL8188EU_RX_DESCRIPTOR_DRVINFO_SIZE_SHIFT 16 +#define RTL8188EU_RX_DESCRIPTOR_SECURITY_MASK 0x00700000 +#define RTL8188EU_RX_DESCRIPTOR_SECURITY_SHIFT 20 +#define RTL8188EU_RX_DESCRIPTOR_SECURITY_NONE 0 +#define RTL8188EU_RX_DESCRIPTOR_SECURITY_TKIP 2 +#define RTL8188EU_RX_DESCRIPTOR_SECURITY_AES 4 +#define RTL8188EU_RX_DESCRIPTOR_SHIFT_MASK 0x03000000 +#define RTL8188EU_RX_DESCRIPTOR_SHIFT_SHIFT 24 +#define RTL8188EU_RX_DESCRIPTOR_SOFTWARE_DECRYPTED (1u << 27) +#define RTL8188EU_RX_DESCRIPTOR_REPORT_SELECT_MASK 0x0000c000 + +#define RTL8188EU_RX_DESCRIPTOR_PACKET_COUNT_MASK 0x00ff0000 +#define RTL8188EU_RX_DESCRIPTOR_PACKET_COUNT_SHIFT 16 +#define RTL8188EU_RX_PACKET_ALIGNMENT 128 + +static size_t align_rx_packet(size_t size) { + return (size + RTL8188EU_RX_PACKET_ALIGNMENT - 1) & ~(RTL8188EU_RX_PACKET_ALIGNMENT - 1); +} + +static void process_rx_buffer(u80211_drv_rtl8188eu_t *rtl8188eu, void *buffer, size_t size) { + uint8_t *bytes = buffer; + size_t offset = 0; + size_t packet_count = 0; + + while (size - offset >= RTL8188EU_RX_DESCRIPTOR_SIZE) { + uint8_t *descriptor = bytes + offset; + uint32_t descriptor0 = u80211_drv_deserialize_le32(descriptor); + uint32_t descriptor2 = u80211_drv_deserialize_le32(descriptor + 8); + uint32_t descriptor3 = u80211_drv_deserialize_le32(descriptor + 12); + // there might be many packets in one transfer. + if (packet_count == 0) { + packet_count = (descriptor2 & RTL8188EU_RX_DESCRIPTOR_PACKET_COUNT_MASK) >> RTL8188EU_RX_DESCRIPTOR_PACKET_COUNT_SHIFT; + if (packet_count == 0) + packet_count = 1; + } + + // TODO: extract channel? + // TODO: extract rate? + // TODO: get dbm info from phy data? + bool is_rx_record = (descriptor3 & RTL8188EU_RX_DESCRIPTOR_REPORT_SELECT_MASK) == 0; + bool crc_icv_error = descriptor0 & (RTL8188EU_RX_DESCRIPTOR_CRC_ERROR | RTL8188EU_RX_DESCRIPTOR_ICV_ERROR); + uint32_t security = (descriptor0 & RTL8188EU_RX_DESCRIPTOR_SECURITY_MASK) >> RTL8188EU_RX_DESCRIPTOR_SECURITY_SHIFT; + bool software_decryption_required = (descriptor0 & RTL8188EU_RX_DESCRIPTOR_SOFTWARE_DECRYPTED) != 0; + size_t packet_size = descriptor0 & RTL8188EU_RX_DESCRIPTOR_PACKET_LENGTH_MASK; + size_t drvinfo_size = ((descriptor0 & RTL8188EU_RX_DESCRIPTOR_DRVINFO_SIZE_MASK) >> RTL8188EU_RX_DESCRIPTOR_DRVINFO_SIZE_SHIFT) * 8; + size_t descriptor_shift = (descriptor0 & RTL8188EU_RX_DESCRIPTOR_SHIFT_MASK) >> RTL8188EU_RX_DESCRIPTOR_SHIFT_SHIFT; + size_t packet_offset = RTL8188EU_RX_DESCRIPTOR_SIZE + drvinfo_size + descriptor_shift; + size_t remaining = size - offset; + + if (packet_offset > remaining || packet_size > remaining - packet_offset) + break; + + if (packet_size != 0 && packet_size <= U80211_DRV_80211_MAX_MPDU_SIZE && !crc_icv_error && is_rx_record) { + uint8_t *packet = descriptor + packet_offset; + // u80211 consumes the cipher header and trailer after hardware has decrypted the payload. + if (security != RTL8188EU_RX_DESCRIPTOR_SECURITY_NONE && + ((security != RTL8188EU_RX_DESCRIPTOR_SECURITY_TKIP && security != RTL8188EU_RX_DESCRIPTOR_SECURITY_AES) || + software_decryption_required)) + goto next_packet; + + u80211_drv_network_device_handle_t network_device = __atomic_load_n(&rtl8188eu->network_device, __ATOMIC_ACQUIRE); + if (network_device != NULL) + u80211_drv_packet_received(network_device, packet, packet_size); + } + + next_packet: + --packet_count; + if (packet_count == 0) + break; + + size_t unit_size = align_rx_packet(packet_offset + packet_size); + if (unit_size > remaining) + break; + offset += unit_size; + } +} + +static void rx_complete(void *context, int status, size_t transferred_size) { + u80211_drv_rtl8188eu_rx_slot_t *slot = context; + u80211_drv_rtl8188eu_t *rtl8188eu = slot->rtl8188eu; + + if (status == U80211_DRV_STATUS_SUCCESS) + process_rx_buffer(rtl8188eu, slot->buffer, transferred_size); + + status = u80211_drv_kernel_submit_xfer(slot->transfer); + if (status != U80211_DRV_STATUS_SUCCESS) + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_WARN, "rtl8188eu: failed to resubmit RX transfer"); +} + +int u80211_drv_rtl8188eu_rx_start(u80211_drv_rtl8188eu_t *rtl8188eu) { + for (size_t i = 0; i < U80211_DRV_RTL8188EU_RX_SLOT_COUNT; ++i) { + u80211_drv_rtl8188eu_rx_slot_t *slot = &rtl8188eu->rx_slots[i]; + slot->rtl8188eu = rtl8188eu; + slot->buffer = NULL; + slot->transfer = NULL; + } + + int status = U80211_DRV_STATUS_SUCCESS; + for (size_t i = 0; i < U80211_DRV_RTL8188EU_RX_SLOT_COUNT; ++i) { + u80211_drv_rtl8188eu_rx_slot_t *slot = &rtl8188eu->rx_slots[i]; + slot->buffer = u80211_drv_kernel_allocate(RTL8188EU_RX_BUFFER_SIZE); + if (slot->buffer == NULL) { + status = U80211_DRV_STATUS_OUT_OF_MEMORY; + break; + } + + status = u80211_drv_kernel_allocate_bulk_xfer( + rtl8188eu->device, + rtl8188eu->rx_endpoint, + slot->buffer, + RTL8188EU_RX_BUFFER_SIZE, + rx_complete, + slot, + &slot->transfer + ); + if (status != U80211_DRV_STATUS_SUCCESS) + break; + + status = u80211_drv_kernel_submit_xfer(slot->transfer); + if (status != U80211_DRV_STATUS_SUCCESS) + break; + } + + return status; +} diff --git a/kernel-src/io/net/u80211_drv/src/rtl8188eu/tx.c b/kernel-src/io/net/u80211_drv/src/rtl8188eu/tx.c new file mode 100644 index 00000000..dfb387c5 --- /dev/null +++ b/kernel-src/io/net/u80211_drv/src/rtl8188eu/tx.c @@ -0,0 +1,190 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define RTL8188EU_TX_DESCRIPTOR_SIZE 32 +#define RTL8188EU_TX_TIMEOUT_MS 1000 + +#define RTL8188EU_TX_QUEUE_BEST_EFFORT 0x00 +#define RTL8188EU_TX_QUEUE_MANAGEMENT 0x12 +#define RTL8188EU_TX_RAID_11BG 4 +#define RTL8188EU_TX_RAID_11B 6 +#define RTL8188EU_TX_RAID_SHIFT 16 +#define RTL8188EU_TX_DESCRIPTOR_MACID_MASK 0x1f +#define RTL8188EU_TX_DESCRIPTOR_ENABLE_DESCRIPTOR_ID (1u << 21) +#define RTL8188EU_TX_DESCRIPTOR_SECURITY_TKIP 0x00400000 +#define RTL8188EU_TX_DESCRIPTOR_SECURITY_AES 0x00c00000 + +#define RTL8188EU_TX_DESCRIPTOR_OWN (1u << 7) +#define RTL8188EU_TX_DESCRIPTOR_FIRST_SEGMENT (1u << 3) +#define RTL8188EU_TX_DESCRIPTOR_LAST_SEGMENT (1u << 2) +#define RTL8188EU_TX_DESCRIPTOR_BROADCAST_MULTICAST (1u << 0) +#define RTL8188EU_TX_DESCRIPTOR_AGGREGATION_BREAK (1u << 16) +#define RTL8188EU_TX_DESCRIPTOR_ANTENNA_A (1u << 24) +#define RTL8188EU_TX_DESCRIPTOR_ANTENNA_B (1u << 25) +#define RTL8188EU_TX_DESCRIPTOR_ANTENNA_C (1u << 29) +#define RTL8188EU_TX_DESCRIPTOR_USE_DRIVER_RATE (1u << 8) +#define RTL8188EU_TX_DESCRIPTOR_DATA_FALLBACK_LIMITS 0x0001ff00 +#define RTL8188EU_TX_DESCRIPTOR_RETRY_LIMIT_ENABLE (1u << 17) +#define RTL8188EU_TX_DESCRIPTOR_RETRY_LIMIT_SHIFT 18 +#define RTL8188EU_TX_MANAGEMENT_RETRY_LIMIT 6 + +static uint8_t data_endpoint(const u80211_drv_rtl8188eu_t *rtl8188eu) { + if (rtl8188eu->bulk_out_endpoint_count >= 3) + return rtl8188eu->tx_endpoint_low; + + if (rtl8188eu->bulk_out_endpoint_count == 2) + return rtl8188eu->tx_endpoint_normal; + + return rtl8188eu->tx_endpoint_high; +} + +static void calculate_checksum(uint8_t *descriptor) { + uint16_t checksum = 0; + for (size_t i = 0; i < RTL8188EU_TX_DESCRIPTOR_SIZE; i += sizeof(uint16_t)) + checksum ^= u80211_drv_deserialize_le16(descriptor + i); + + u80211_drv_serialize_le16(descriptor + 28, checksum); +} + +static int build_descriptor(const uint8_t *frame, size_t frame_size, const u80211_drv_transmit_options_t *options, uint8_t *descriptor, uint8_t *queue_out) { + int key_index = options == NULL ? -1 : options->key; + int cipher = options == NULL ? U80211_DRV_CIPHER_NONE : options->cipher; + + if (frame_size < U80211_DRV_80211_HEADER_MINIMUM_SIZE) + return U80211_DRV_STATUS_MALFORMED_PACKET; + + if (key_index < -1 || key_index > U80211_DRV_RTL8188EU_CAM_CTL0_KEY_ID_MASK) + return U80211_DRV_STATUS_INVALID_ARGUMENT; + + if ((key_index < 0) != (cipher == U80211_DRV_CIPHER_NONE)) + return U80211_DRV_STATUS_INVALID_ARGUMENT; + + uint16_t frame_control = u80211_drv_80211_frame_control(frame); + uint8_t frame_type = u80211_drv_80211_frame_type(frame_control); + uint8_t frame_subtype = u80211_drv_80211_frame_subtype(frame_control); + uint8_t queue; + + if (frame_type == U80211_DRV_80211_FRAME_TYPE_MANAGEMENT) + queue = RTL8188EU_TX_QUEUE_MANAGEMENT; + else if (frame_type == U80211_DRV_80211_FRAME_TYPE_DATA && (frame_subtype & U80211_DRV_80211_FRAME_DATA_QOS_BIT) == 0) + queue = RTL8188EU_TX_QUEUE_BEST_EFFORT; + else + return U80211_DRV_STATUS_NOT_SUPPORTED; + + u80211_drv_memset(descriptor, 0, RTL8188EU_TX_DESCRIPTOR_SIZE); + u80211_drv_serialize_le16(descriptor, (uint16_t)frame_size); // packet size + descriptor[2] = RTL8188EU_TX_DESCRIPTOR_SIZE; // packet start offset + // once HT is implemented, that stuff would go here. + descriptor[3] = RTL8188EU_TX_DESCRIPTOR_OWN | RTL8188EU_TX_DESCRIPTOR_FIRST_SEGMENT | RTL8188EU_TX_DESCRIPTOR_LAST_SEGMENT; + + const uint8_t *receiver = u80211_drv_80211_receiver_address(frame); + bool group_addressed = (receiver[0] & 1u) != 0; + if (group_addressed) + descriptor[3] |= RTL8188EU_TX_DESCRIPTOR_BROADCAST_MULTICAST; + + // use the mixed 11b/g table for unicast data and the basic 11b table for management and group-addressed traffic. + uint8_t raid = frame_type == U80211_DRV_80211_FRAME_TYPE_DATA && !group_addressed ? RTL8188EU_TX_RAID_11BG : RTL8188EU_TX_RAID_11B; + uint32_t descriptor1 = ((uint32_t)queue << 8) | ((uint32_t)raid << RTL8188EU_TX_RAID_SHIFT); + if (key_index >= 0) { + // use hardware encryption. set the selected cipher bit + if (frame_type != U80211_DRV_80211_FRAME_TYPE_DATA) + return U80211_DRV_STATUS_INVALID_ARGUMENT; + + if (cipher == U80211_DRV_CIPHER_CCMP) + descriptor1 |= RTL8188EU_TX_DESCRIPTOR_SECURITY_AES; + else if (cipher == U80211_DRV_CIPHER_TKIP) + descriptor1 |= RTL8188EU_TX_DESCRIPTOR_SECURITY_TKIP; + else + return U80211_DRV_STATUS_NOT_SUPPORTED; + + if (group_addressed) { + descriptor1 |= RTL8188EU_TX_DESCRIPTOR_ENABLE_DESCRIPTOR_ID; + descriptor1 |= (uint32_t)key_index & RTL8188EU_TX_DESCRIPTOR_MACID_MASK; + } + } + u80211_drv_serialize_le32(descriptor + 4, descriptor1); + + // do not combine packets and use a known working setting for antennas (0b111, last bit is set in dword 7) + u80211_drv_serialize_le32(descriptor + 8, RTL8188EU_TX_DESCRIPTOR_AGGREGATION_BREAK | RTL8188EU_TX_DESCRIPTOR_ANTENNA_A | RTL8188EU_TX_DESCRIPTOR_ANTENNA_B); + + uint16_t sequence_number = u80211_drv_80211_sequence_number(frame); + u80211_drv_serialize_le32(descriptor + 12, (uint32_t)sequence_number << 16); + + // this controls a lot of things about how packets are transmitted. + // at the moment, we only care about telling it to use our selected rate. + // this is a list of things of interest that would be handled here: + // qos, hw sequence control, short preamble, different bandwidth stuff + u80211_drv_serialize_le32(descriptor + 16, RTL8188EU_TX_DESCRIPTOR_USE_DRIVER_RATE); + + if (frame_type == U80211_DRV_80211_FRAME_TYPE_MANAGEMENT) { + // six hardware retries @ 1mbps for management packets + u80211_drv_serialize_le32(descriptor + 20, RTL8188EU_TX_DESCRIPTOR_RETRY_LIMIT_ENABLE | (RTL8188EU_TX_MANAGEMENT_RETRY_LIMIT << RTL8188EU_TX_DESCRIPTOR_RETRY_LIMIT_SHIFT)); + } else { + // TODO: encode our selected rate here as well once selection is implemented + // enable rate fallback for data packets (31 data retries + 15 request-to-send retries) + u80211_drv_serialize_le32(descriptor + 20, RTL8188EU_TX_DESCRIPTOR_DATA_FALLBACK_LIMITS); + } + + // dw6 would contain things related to usb aggregation. that is completely disabled in this driver, so it is skipped over. + + // dw7 has a checksum and the last bit of the antenna selector + u80211_drv_serialize_le32(descriptor + 28, RTL8188EU_TX_DESCRIPTOR_ANTENNA_C); + calculate_checksum(descriptor); + *queue_out = queue; + return U80211_DRV_STATUS_SUCCESS; +} + +int u80211_drv_rtl8188eu_tx_buffer_allocate(size_t size, void **buffer) { + if (size > U80211_DRV_80211_MAX_MPDU_SIZE) + return U80211_DRV_STATUS_INVALID_ARGUMENT; + + size_t allocation_size = size + RTL8188EU_TX_DESCRIPTOR_SIZE; + void *data = u80211_drv_kernel_allocate(allocation_size); + if (data == NULL) + return U80211_DRV_STATUS_OUT_OF_MEMORY; + + *buffer = (uint8_t *)data + RTL8188EU_TX_DESCRIPTOR_SIZE; + return U80211_DRV_STATUS_SUCCESS; +} + +void u80211_drv_rtl8188eu_tx_buffer_free(void *buffer) { + u80211_drv_kernel_free((uint8_t *)buffer - RTL8188EU_TX_DESCRIPTOR_SIZE); +} + +int u80211_drv_rtl8188eu_transmit(u80211_drv_rtl8188eu_t *rtl8188eu, void *buffer, size_t size, size_t current_offset, const u80211_drv_transmit_options_t *options) { + uint8_t *frame = (uint8_t *)buffer + current_offset; + size_t frame_size = size - current_offset; + uint8_t *descriptor = frame - RTL8188EU_TX_DESCRIPTOR_SIZE; + + uint8_t queue; + int status = build_descriptor(frame, frame_size, options, descriptor, &queue); + if (status != U80211_DRV_STATUS_SUCCESS) + goto cleanup; + + uint8_t endpoint = queue == RTL8188EU_TX_QUEUE_MANAGEMENT ? rtl8188eu->tx_endpoint_high : data_endpoint(rtl8188eu); + size_t transfer_size = RTL8188EU_TX_DESCRIPTOR_SIZE + frame_size; + size_t transferred_size = 0; + status = u80211_drv_kernel_submit_bulk_xfer_and_wait( + rtl8188eu->device, + endpoint, + descriptor, + transfer_size, + &transferred_size, + RTL8188EU_TX_TIMEOUT_MS + ); + + if (status == U80211_DRV_STATUS_SUCCESS && transferred_size != transfer_size) + status = U80211_DRV_STATUS_UNKNOWN_ERROR; + +cleanup: + u80211_drv_rtl8188eu_tx_buffer_free(buffer); + return status; +} diff --git a/kernel-src/io/net/u80211_drv/src/rtl8188eu/tx_power.c b/kernel-src/io/net/u80211_drv/src/rtl8188eu/tx_power.c new file mode 100644 index 00000000..e2a9df67 --- /dev/null +++ b/kernel-src/io/net/u80211_drv/src/rtl8188eu/tx_power.c @@ -0,0 +1,134 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Nathanial Sloss + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include + +#define RTL8188EU_MAX_TX_POWER 0x3f + +typedef struct { + uint8_t cck1; + uint8_t cck2; + uint8_t cck55; + uint8_t cck11; + uint8_t ofdm; + uint8_t mcs; +} rtl8188eu_tx_power_t; + +static unsigned int rtl8188eu_channel_group(uint8_t channel) { + if (channel <= 2) + return 0; + + if (channel <= 5) + return 1; + + if (channel <= 8) + return 2; + + if (channel <= 11) + return 3; + + if (channel <= 13) + return 4; + + return 5; +} + +static int rtl8188eu_sign_extend_4(uint8_t value) { + value &= 0x0f; + return (value & 0x08) != 0 ? (int)value - 16 : value; +} + +static uint8_t rtl8188eu_clamp_tx_power(int value) { + if (value < 0) + return 0; + + if (value > RTL8188EU_MAX_TX_POWER) + return RTL8188EU_MAX_TX_POWER; + + return value; +} + +static rtl8188eu_tx_power_t rtl8188eu_compute_tx_power(const u80211_drv_rtl8188eu_efuse_t *efuse, uint8_t channel) { + unsigned int group = rtl8188eu_channel_group(channel); + int cck = efuse->cck_tx_power_base_indexes[group]; + unsigned int ht_group = group == 5 ? 4 : group; + int ht = efuse->ht40_1s_tx_power_base_indexes[ht_group]; + int ofdm = ht + rtl8188eu_sign_extend_4(efuse->ht20_ofdm_tx_power_diff); + int mcs = ht + rtl8188eu_sign_extend_4(efuse->ht20_ofdm_tx_power_diff >> 4); + + return (rtl8188eu_tx_power_t) { + .cck1 = rtl8188eu_clamp_tx_power(cck), + .cck2 = rtl8188eu_clamp_tx_power(cck - 9), + .cck55 = rtl8188eu_clamp_tx_power(cck), + .cck11 = rtl8188eu_clamp_tx_power(cck), + .ofdm = rtl8188eu_clamp_tx_power(ofdm), + .mcs = rtl8188eu_clamp_tx_power(mcs), + }; +} + +static uint32_t rtl8188eu_repeat_power(uint8_t power) { + return (uint32_t)power * UINT32_C(0x01010101); +} + +int u80211_drv_rtl8188eu_set_tx_power(u80211_drv_rtl8188eu_t *rtl8188eu, uint8_t channel) { + if (channel < 1 || channel > 14) + return U80211_DRV_STATUS_INVALID_ARGUMENT; + + rtl8188eu_tx_power_t power = rtl8188eu_compute_tx_power(&rtl8188eu->efuse, channel); + uint32_t value; + int status = u80211_drv_rtl8188eu_reg_read32(rtl8188eu->device, U80211_DRV_RTL8188EU_REG_TXAGC_A_CCK1, &value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value &= ~U80211_DRV_RTL8188EU_REG_TXAGC_A_CCK1_MASK; + value |= (uint32_t)power.cck1 << 8; + status = u80211_drv_rtl8188eu_reg_write32(rtl8188eu->device, U80211_DRV_RTL8188EU_REG_TXAGC_A_CCK1, value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_read32(rtl8188eu->device, U80211_DRV_RTL8188EU_REG_TXAGC_B_CCK11_A_CCK2_11, &value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + value &= UINT32_C(0x000000ff); + value |= (uint32_t)power.cck2 << 8; + value |= (uint32_t)power.cck55 << 16; + value |= (uint32_t)power.cck11 << 24; + status = u80211_drv_rtl8188eu_reg_write32(rtl8188eu->device, U80211_DRV_RTL8188EU_REG_TXAGC_B_CCK11_A_CCK2_11, value); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + uint32_t ofdm = rtl8188eu_repeat_power(power.ofdm); + status = u80211_drv_rtl8188eu_reg_write32(rtl8188eu->device, U80211_DRV_RTL8188EU_REG_TXAGC_A_RATE18_06, ofdm); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + status = u80211_drv_rtl8188eu_reg_write32(rtl8188eu->device, U80211_DRV_RTL8188EU_REG_TXAGC_A_RATE54_24, ofdm); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + uint32_t mcs = rtl8188eu_repeat_power(power.mcs); + status = u80211_drv_rtl8188eu_reg_write32(rtl8188eu->device, U80211_DRV_RTL8188EU_REG_TXAGC_A_MCS03, mcs); + if (status != U80211_DRV_STATUS_SUCCESS) + return status; + + return u80211_drv_rtl8188eu_reg_write32(rtl8188eu->device, U80211_DRV_RTL8188EU_REG_TXAGC_A_MCS07, mcs); +} diff --git a/kernel-src/io/net/u80211_drv/src/string.c b/kernel-src/io/net/u80211_drv/src/string.c new file mode 100644 index 00000000..775c19f5 --- /dev/null +++ b/kernel-src/io/net/u80211_drv/src/string.c @@ -0,0 +1,23 @@ +#include +#include + +#include + +void *u80211_drv_memcpy(void *destination, const void *source, size_t size) { + uint8_t *destination_bytes = destination; + const uint8_t *source_bytes = source; + + for (size_t i = 0; i < size; ++i) + destination_bytes[i] = source_bytes[i]; + + return destination; +} + +void *u80211_drv_memset(void *destination, int value, size_t size) { + uint8_t *destination_bytes = destination; + + for (size_t i = 0; i < size; ++i) + destination_bytes[i] = (uint8_t)value; + + return destination; +} diff --git a/kernel-src/io/net/u80211_drv/src/u80211_drv.c b/kernel-src/io/net/u80211_drv/src/u80211_drv.c new file mode 100644 index 00000000..9e2cc575 --- /dev/null +++ b/kernel-src/io/net/u80211_drv/src/u80211_drv.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include +#include + +typedef int (*u80211_drv_initialize_fn_t)(u80211_drv_device_handle_t device, u80211_drv_interface_handle_t interface); + +typedef struct { + uint32_t id; + uint32_t interface; + u80211_drv_initialize_fn_t fn; + const char *name; +} u80211_drv_match_table_entry_t; + +static const u80211_drv_match_table_entry_t match_table[] = { + {0x20013310, 0xffffff, u80211_drv_rtl8188eu_init, "DWA-123 (Revision D1, rtl8188eu driver)"}, +}; + +#define MATCH_TABLE_ENTRIES (sizeof(match_table) / sizeof(*match_table)) + +static const u80211_drv_match_table_entry_t *get_table_entry(const u80211_drv_device_descriptor_t *device_descriptor, + const u80211_drv_interface_descriptor_t *interface_descriptor) { + uint32_t id = ((uint32_t)device_descriptor->vendor_id << 16) | device_descriptor->product_id; + uint32_t interface = ((uint32_t)interface_descriptor->class_code << 16) | ((uint32_t)interface_descriptor->subclass << 8) | interface_descriptor->protocol; + + for (size_t i = 0; i < MATCH_TABLE_ENTRIES; ++i) { + if (match_table[i].id == id && match_table[i].interface == interface) + return &match_table[i]; + } + + return NULL; +} + +int u80211_drv_probe(u80211_drv_device_handle_t device, u80211_drv_interface_handle_t interface) { + u80211_drv_device_descriptor_t device_descriptor; + u80211_drv_interface_descriptor_t interface_descriptor; + if (u80211_drv_kernel_get_device_descriptor(device, &device_descriptor) != U80211_DRV_STATUS_SUCCESS || + u80211_drv_kernel_get_interface_descriptor(interface, &interface_descriptor) != U80211_DRV_STATUS_SUCCESS) + return U80211_DRV_STATUS_UNKNOWN_ERROR; + + const u80211_drv_match_table_entry_t *entry = get_table_entry(&device_descriptor, &interface_descriptor); + + return entry ? U80211_DRV_STATUS_SUCCESS : U80211_DRV_STATUS_NO_MATCH; +} + +int u80211_drv_attach(u80211_drv_device_handle_t device, u80211_drv_interface_handle_t interface) { + u80211_drv_device_descriptor_t device_descriptor; + u80211_drv_interface_descriptor_t interface_descriptor; + if (u80211_drv_kernel_get_device_descriptor(device, &device_descriptor) != U80211_DRV_STATUS_SUCCESS || + u80211_drv_kernel_get_interface_descriptor(interface, &interface_descriptor) != U80211_DRV_STATUS_SUCCESS) + return U80211_DRV_STATUS_UNKNOWN_ERROR; + + const u80211_drv_match_table_entry_t *entry = get_table_entry(&device_descriptor, &interface_descriptor); + + if (entry == NULL) + return U80211_DRV_STATUS_NO_MATCH; + + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, "Matched device:"); + u80211_drv_kernel_print(U80211_DRV_KERNEL_PRINT_LEVEL_INFO, entry->name); + + return entry->fn(device, interface); +} diff --git a/kernel-src/io/usb/ctrl/xhci.c b/kernel-src/io/usb/ctrl/xhci.c index 57944015..de7947a1 100644 --- a/kernel-src/io/usb/ctrl/xhci.c +++ b/kernel-src/io/usb/ctrl/xhci.c @@ -798,4 +798,4 @@ void xhci_init(void) { } } -INIT_ROUTINE_DEFINE(xhci, INIT_ROUTINE_FLAGS_NONE, xhci_init, acpi); +INIT_ROUTINE_DEFINE(xhci, INIT_ROUTINE_FLAGS_NONE, xhci_init, acpi, u80211_drv_usb); diff --git a/kernel-src/main.c b/kernel-src/main.c index afbc6701..101c1a79 100644 --- a/kernel-src/main.c +++ b/kernel-src/main.c @@ -66,6 +66,8 @@ void kernel_entry() { if (GET_KERNEL_ARGUMENT(initrd, bool)) initrd_unpack(); + vfs_root_event_signal(); + // spawn init proc_run_init();