KT24-1110_65E-HA-651B/apps/common/usb/host/aoa.c
2024-11-10 18:44:17 +08:00

233 lines
7.5 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file aoa.c
* @brief https://source.android.com/devices/accessories/aoa
* http://www.hackermi.com/2015-04/aoa-analyse/
* Android 开放配件协议 1.0
* @author chenrixin@zh-jieli.com
* @version 1
* @date 2020-03-25
*/
#include "includes.h"
#include "app_config.h"
#include "usb_config.h"
#include "usb/host/usb_host.h"
#include "usb/usb_phy.h"
#include "device_drive.h"
#include "usb_ctrl_transfer.h"
#include "usb_bulk_transfer.h"
#include "usb_storage.h"
#include "adb.h"
#include "aoa.h"
#include "usb_hid_keys.h"
#if TCFG_AOA_ENABLE
#include "gamebox.h"
#define LOG_TAG_CONST USB
#define LOG_TAG "[AOA]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_DUMP_ENABLE */
#define LOG_CLI_ENABLE
#include "debug.h"
//0x2D00 有一个接口,该接口有两个批量端点,用于输入和输出通信。
//0x2D01 有两个接口,每个接口有两个批量端点,用于输入和输出通信。
//第一个接口处理标准通信,
//第二个接口则处理 ADB 通信。
//要使用接口,请找到第一个批量输入和输出端点,
//使用 SET_CONFIGURATION (0x09) 设备请求将设备配置的值设为 1然后使用端点进行通信
//
static void aoa_timer_handler(void *priv);
static u32 aoa_timer_id;
static struct aoa_device_t aoa;
static struct device aoa_device;
static int set_power(struct usb_host_device *host_dev, u32 value)
{
if (aoa_timer_id) {
usr_timer_del(aoa_timer_id);
aoa_timer_id = 0;
}
return DEV_ERR_NONE;
}
static int get_power(struct usb_host_device *host_dev, u32 value)
{
return DEV_ERR_NONE;
}
static const struct interface_ctrl aoa_ctrl = {
.interface_class = USB_CLASS_AOA,
.set_power = set_power,
.get_power = get_power,
.ioctl = NULL,
};
static const struct usb_interface_info aoa_inf = {
.ctrl = (struct interface_ctrl *) &aoa_ctrl,
.dev.aoa = &aoa,
};
static const char *credetials[] = {"JieLiTec",
"GameBox",
"Android accessories devcie !",
"1.0.0",
"http://www.zh-jieli.com",
"1234567890ABCDEF",
};
void aoa_switch(struct usb_host_device *host_dev)
{
u16 version;
log_info("aoa_switch");
usb_get_aoa_version(host_dev, &version);
log_info("AOA version: %x", version);
for (int i = 0; i < 5; i++) {
log_info("send string [%d] %s", i, credetials[i]);
int r = usb_set_credentials(host_dev, credetials[i], i);
if (r < 0) {
break;
}
}
usb_switch2aoa(host_dev);
}
int usb_aoa_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
{
struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
pBuf += sizeof(struct usb_interface_descriptor);
int len = 0;
const usb_dev usb_id = host_device2id(host_dev);
aoa_device.private_data = host_dev;
host_dev->interface_info[interface_num] = &aoa_inf;
for (int endnum = 0; endnum < interface->bNumEndpoints; endnum++) {
struct usb_endpoint_descriptor *end_desc = (struct usb_endpoint_descriptor *)pBuf;
if (end_desc->bDescriptorType != USB_DT_ENDPOINT ||
end_desc->bLength != USB_DT_ENDPOINT_SIZE) {
log_error("ep bDescriptorType = %d bLength = %d", end_desc->bDescriptorType, end_desc->bLength);
return -USB_DT_ENDPOINT;
}
len += USB_DT_ENDPOINT_SIZE;
pBuf += USB_DT_ENDPOINT_SIZE;
if ((end_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
if (end_desc->bEndpointAddress & USB_DIR_IN) {
aoa.target_epin = end_desc->bEndpointAddress & 0x0f;
#if HUSB_MODE
aoa.rxmaxp = end_desc->wMaxPacketSize;
#endif
} else {
aoa.target_epout = end_desc->bEndpointAddress & 0x0f;
#if HUSB_MODE
aoa.txmaxp = end_desc->wMaxPacketSize;
#endif
}
}
}
return len;
}
static int aoa_tx_data(const u8 *pbuf, u32 len)
{
struct usb_host_device *host_dev = aoa_device.private_data;
usb_dev usb_id = host_device2id(host_dev);
g_printf("TX:");
printf_buf(pbuf, len);
return usb_h_ep_write_async(usb_id, aoa.host_epout, 64, aoa.target_epout, pbuf, len, USB_ENDPOINT_XFER_BULK, 1);
}
static void aoa_epin_isr(struct usb_host_device *host_dev, u32 ep)
{
u8 buffer[64] = {0};
usb_dev usb_id = host_device2id(host_dev);
u32 rx_len = usb_h_ep_read_async(usb_id, ep, aoa.target_epin, buffer, sizeof(buffer), USB_ENDPOINT_XFER_BULK, 0);
g_printf("RX:");
printf_buf(buffer, rx_len);
usb_h_ep_read_async(usb_id, ep, aoa.target_epin, NULL, 0, USB_ENDPOINT_XFER_BULK, 1);
}
#define Accessory_assigned_ID 0x0001
u32 aoa_process(u32 mode, u32 id)
{
struct usb_host_device *host_dev = aoa_device.private_data;
struct usb_device_descriptor device_desc;
usb_get_device_descriptor(host_dev, &device_desc);
if ((device_desc.idVendor == 0x18d1) &&
((device_desc.idProduct & 0x2d00) == 0x2d00)) {
log_info("aoa mode ready idVendor:%x idProduct: %x",
device_desc.idVendor, device_desc.idProduct);
} else {
log_info("aoa switch idVendor:%x idProduct: %x",
device_desc.idVendor, device_desc.idProduct);
aoa_switch(host_dev);
usb_host_remount(id, 3, 30, 50, 1);
return 0;
}
usb_aoa_register_hid(host_dev, Accessory_assigned_ID, sizeof(hid_report_desc));
u32 offset = 0;
while (offset < sizeof(hid_report_desc)) {
u32 cnt = min(sizeof(hid_report_desc) - offset, 63);
usb_aoa_set_hid_report_desc(host_dev, Accessory_assigned_ID, offset, &hid_report_desc[offset], cnt);
offset += cnt;
}
aoa.host_epout = usb_get_ep_num(id, USB_DIR_OUT, USB_ENDPOINT_XFER_BULK);
aoa.host_epin = usb_get_ep_num(id, USB_DIR_IN, USB_ENDPOINT_XFER_BULK);
log_debug("D(%d)->H(%d)", aoa.target_epin, aoa.host_epin);
log_debug("H(%d)->D(%d)", aoa.host_epout, aoa.target_epout);
usb_h_set_ep_isr(host_dev, aoa.host_epin | USB_DIR_IN, aoa_epin_isr, host_dev);
u8 *ep_buffer = usb_h_get_ep_buffer(id, aoa.host_epin | USB_DIR_IN);
usb_h_ep_config(id, aoa.host_epin | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, 1, 0, ep_buffer, 64);
int r = usb_h_ep_read_async(id, aoa.host_epin, aoa.target_epin, NULL, 0, USB_ENDPOINT_XFER_BULK, 1);
ep_buffer = usb_h_get_ep_buffer(id, aoa.host_epout | USB_DIR_OUT);
usb_h_ep_config(id, aoa.host_epout | USB_DIR_OUT, USB_ENDPOINT_XFER_BULK, 0, 0, ep_buffer, 64);
aoa_timer_id = usr_timer_add((void *)0, aoa_timer_handler, 4, 0);
g_printf("aoa succ");
return 1;
}
static void aoa_timer_handler(void *priv)
{
struct usb_host_device *host_dev = aoa_device.private_data;
u8 tx_buffer[32];
if (mouse_data_send == 1) {
tx_buffer[0] = MOUSE_POINT_ID;
memcpy(&tx_buffer[1], &mouse_data, sizeof(mouse_data));
usb_aoa_send_hid_event(host_dev, Accessory_assigned_ID, tx_buffer, sizeof(mouse_data) + 1);
memset(&mouse_data, 0, sizeof(mouse_data)) ;
mouse_data_send = 0;
}
tx_buffer[0] = TOUCH_SCREEN_ID;
struct touch_screen_t t;
memset(&t, 0, sizeof(t));
if (point_list_pop(&t)) {
memcpy(&tx_buffer[1], &t, sizeof(t));
usb_aoa_send_hid_event(host_dev, Accessory_assigned_ID, tx_buffer, sizeof(t) + 1);
}
}
#endif