mirror of
https://github.com/suchmememanyskill/TegraExplorer.git
synced 2024-11-26 05:42:07 +00:00
Basic controller input
This commit is contained in:
parent
12c3ffc2e4
commit
7ad77cffb0
8 changed files with 1162 additions and 14 deletions
66
source/hid/hid.c
Normal file
66
source/hid/hid.c
Normal file
|
@ -0,0 +1,66 @@
|
|||
#include "hid.h"
|
||||
#include "joycon.h"
|
||||
#include "../utils/btn.h"
|
||||
|
||||
static Inputs inputs = {0};
|
||||
u16 LbaseX = 0, LbaseY = 0, RbaseX = 0, RbaseY = 0;
|
||||
|
||||
void hidInit(){
|
||||
jc_init_hw();
|
||||
}
|
||||
|
||||
Inputs *hidRead(){
|
||||
jc_gamepad_rpt_t *controller = joycon_poll();
|
||||
|
||||
inputs.a = controller->a;
|
||||
inputs.b = controller->b;
|
||||
inputs.x = controller->x;
|
||||
inputs.y = controller->y;
|
||||
inputs.r = controller->r;
|
||||
inputs.l = controller->l;
|
||||
inputs.zr = controller->zr;
|
||||
inputs.zl = controller->zl;
|
||||
inputs.minus = controller->minus;
|
||||
inputs.plus = controller->plus;
|
||||
inputs.home = controller->home;
|
||||
inputs.cap = controller->cap;
|
||||
|
||||
if (controller->conn_l){
|
||||
if (LbaseX == 0 || LbaseY == 0){
|
||||
LbaseX = controller->lstick_x;
|
||||
LbaseY = controller->lstick_y;
|
||||
}
|
||||
|
||||
inputs.Lup = (controller->up || (controller->lstick_y > LbaseY + 500)) ? 1 : 0;
|
||||
inputs.Ldown = (controller->down || (controller->lstick_y < LbaseY - 500)) ? 1 : 0;
|
||||
inputs.Lleft = (controller->left || (controller->lstick_x < LbaseX - 500)) ? 1 : 0;
|
||||
inputs.Lright = (controller->right || (controller->lstick_x > LbaseX + 500)) ? 1 : 0;
|
||||
}
|
||||
|
||||
if (controller->conn_r){
|
||||
if (RbaseX == 0 || RbaseY == 0){
|
||||
RbaseX = controller->rstick_x;
|
||||
RbaseY = controller->rstick_y;
|
||||
}
|
||||
|
||||
inputs.Rup = (controller->rstick_y > RbaseY + 500) ? 1 : 0;
|
||||
inputs.Rdown = (controller->rstick_y < RbaseY - 500) ? 1 : 0;
|
||||
inputs.Rleft = (controller->rstick_x < RbaseX - 500) ? 1 : 0;
|
||||
inputs.Rright = (controller->rstick_x > RbaseX + 500) ? 1 : 0;
|
||||
}
|
||||
|
||||
u8 btn = btn_read();
|
||||
inputs.volp = (btn & BTN_VOL_UP) ? 1 : 0;
|
||||
inputs.volm = (btn & BTN_VOL_DOWN) ? 1 : 0;
|
||||
inputs.pow = (btn & BTN_POWER) ? 1 : 0;
|
||||
|
||||
return &inputs;
|
||||
}
|
||||
|
||||
Inputs *hidWaitForButton(u32 mask){
|
||||
Inputs *in = hidRead();
|
||||
while ((in->buttons & mask) == 0){
|
||||
in = hidRead();
|
||||
}
|
||||
return in;
|
||||
}
|
50
source/hid/hid.h
Normal file
50
source/hid/hid.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
#pragma once
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define BIT(n) (1 << n)
|
||||
#define KEY_A BIT(3)
|
||||
#define KEY_B BIT(2)
|
||||
#define KEY_LUP BIT(18)
|
||||
#define KEY_LDOWN BIT(17)
|
||||
#define KEY_RUP BIT(7)
|
||||
#define KEY_RDOWN BIT(6)
|
||||
|
||||
typedef struct _inputs {
|
||||
union {
|
||||
struct {
|
||||
// Joy-Con (R).
|
||||
u32 y:1;
|
||||
u32 x:1;
|
||||
u32 b:1;
|
||||
u32 a:1;
|
||||
u32 r:1;
|
||||
u32 zr:1;
|
||||
u32 Rdown:1;
|
||||
u32 Rup:1;
|
||||
u32 Rright:1;
|
||||
u32 Rleft:1;
|
||||
|
||||
// Shared
|
||||
u32 minus:1;
|
||||
u32 plus:1;
|
||||
u32 home:1;
|
||||
u32 cap:1;
|
||||
u32 volp:1;
|
||||
u32 volm:1;
|
||||
u32 pow:1;
|
||||
|
||||
// Joy-Con (L).
|
||||
u32 Ldown:1;
|
||||
u32 Lup:1;
|
||||
u32 Lright:1;
|
||||
u32 Lleft:1;
|
||||
u32 l:1;
|
||||
u32 zl:1;
|
||||
};
|
||||
u32 buttons;
|
||||
};
|
||||
} Inputs;
|
||||
|
||||
void hidInit();
|
||||
Inputs *hidRead();
|
||||
Inputs *hidWaitForButton(u32 mask);
|
807
source/hid/joycon.c
Normal file
807
source/hid/joycon.c
Normal file
|
@ -0,0 +1,807 @@
|
|||
/*
|
||||
* Joy-Con UART driver for Nintendo Switch
|
||||
*
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "joycon.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../power/max17050.h"
|
||||
#include "../power/regulator_5v.h"
|
||||
#include "../soc/bpmp.h"
|
||||
#include "../soc/clock.h"
|
||||
#include "../soc/gpio.h"
|
||||
#include "../soc/pinmux.h"
|
||||
#include "../soc/uart.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
// For disabling driver when logging is enabled.
|
||||
// #include "../libs/lvgl/lvgl.h"
|
||||
|
||||
#define JC_WIRED_CMD 0x91
|
||||
#define JC_WIRED_HID 0x92
|
||||
#define JC_WIRED_INIT_REPLY 0x94
|
||||
#define JC_INIT_HANDSHAKE 0xA5
|
||||
|
||||
#define JC_WIRED_CMD_MAC 0x01
|
||||
#define JC_WIRED_CMD_10 0x10
|
||||
|
||||
#define JC_HID_OUTPUT_RPT 0x01
|
||||
#define JC_HID_RUMBLE_RPT 0x10
|
||||
|
||||
#define JC_HID_INPUT_RPT 0x30
|
||||
#define JC_HID_SUBMCD_RPT 0x21
|
||||
|
||||
#define JC_HID_SUBCMD_HCI_STATE 0x06
|
||||
#define HCI_STATE_SLEEP 0x00
|
||||
#define HCI_STATE_RECONNECT 0x01
|
||||
#define HCI_STATE_PAIR 0x02
|
||||
#define HCI_STATE_HOME 0x04
|
||||
#define JC_HID_SUBCMD_SPI_READ 0x10
|
||||
#define JC_HID_SUBCMD_RUMBLE_CTL 0x48
|
||||
#define JC_HID_SUBCMD_SND_RUMBLE 0xFF
|
||||
|
||||
#define JC_BTN_MASK_L 0xFF2900 // 0xFFE900: with charge status.
|
||||
#define JC_BTN_MASK_R 0x76FF
|
||||
|
||||
#define JC_ID_L 1
|
||||
#define JC_ID_R 2
|
||||
|
||||
enum
|
||||
{
|
||||
JC_BATT_EMTPY = 0,
|
||||
JC_BATT_CRIT = 2,
|
||||
JC_BATT_LOW = 4,
|
||||
JC_BATT_MID = 6,
|
||||
JC_BATT_FULL = 8
|
||||
};
|
||||
|
||||
static const u8 init_jc[] = {
|
||||
0xA1, 0xA2, 0xA3, 0xA4
|
||||
};
|
||||
|
||||
static const u8 init_handshake[] = {
|
||||
0x19, 0x01, 0x03, 0x07, 0x00, // Uart header.
|
||||
JC_INIT_HANDSHAKE, 0x02, // Wired cmd and wired subcmd.
|
||||
0x01, 0x7E, 0x00, 0x00, 0x00 // Wired subcmd data.
|
||||
};
|
||||
|
||||
static const u8 init_get_info[] = {
|
||||
0x19, 0x01, 0x03, 0x07, 0x00, // Uart header.
|
||||
JC_WIRED_CMD, JC_WIRED_CMD_MAC, // Wired cmd and subcmd.
|
||||
0x00, 0x00, 0x00, 0x00, 0x24 // Wired subcmd data.
|
||||
};
|
||||
|
||||
static const u8 init_finilize[] = {
|
||||
0x19, 0x01, 0x03, 0x07, 0x00, // Uart header.
|
||||
JC_WIRED_CMD, JC_WIRED_CMD_10, // Wired cmd and subcmd.
|
||||
0x00, 0x00, 0x00, 0x00, 0x3D // Wired subcmd data.
|
||||
};
|
||||
|
||||
static const u8 nx_pad_status[] = {
|
||||
0x19, 0x01, 0x03, 0x08, 0x00, // Uart header.
|
||||
JC_WIRED_HID, 0x00, // Wired cmd and hid cmd.
|
||||
0x01, 0x00, 0x00, 0x69, 0x2D, 0x1F // hid data.
|
||||
};
|
||||
|
||||
typedef struct _jc_uart_hdr_t
|
||||
{
|
||||
u8 magic[3];
|
||||
u8 total_size_lsb;
|
||||
u8 total_size_msb;
|
||||
} jc_uart_hdr_t;
|
||||
|
||||
typedef struct _jc_wired_hdr_t
|
||||
{
|
||||
jc_uart_hdr_t uart_hdr;
|
||||
u8 cmd;
|
||||
u8 data[5];
|
||||
u8 crc;
|
||||
u8 payload[];
|
||||
} jc_wired_hdr_t;
|
||||
|
||||
typedef struct _jc_hid_out_rpt_t
|
||||
{
|
||||
u8 cmd;
|
||||
u8 pkt_id;
|
||||
u8 rumble[8];
|
||||
u8 subcmd;
|
||||
u8 subcmd_data[];
|
||||
} jc_hid_out_rpt_t;
|
||||
|
||||
typedef struct _jc_hid_out_spi_read_t
|
||||
{
|
||||
u32 addr;
|
||||
u8 size;
|
||||
} jc_hid_out_spi_read_t;
|
||||
|
||||
typedef struct _jc_hid_in_rpt_t
|
||||
{
|
||||
u8 cmd;
|
||||
u8 pkt_id;
|
||||
u8 conn_info:4;
|
||||
u8 batt_info:4;
|
||||
u8 btn_right;
|
||||
u8 btn_shared;
|
||||
u8 btn_left;
|
||||
u8 stick_h_left;
|
||||
u8 stick_m_left;
|
||||
u8 stick_v_left;
|
||||
u8 stick_h_right;
|
||||
u8 stick_m_right;
|
||||
u8 stick_v_right;
|
||||
u8 vib_decider;
|
||||
u8 submcd_ack;
|
||||
u8 subcmd;
|
||||
u8 subcmd_data[];
|
||||
} jc_hid_in_rpt_t;
|
||||
|
||||
typedef struct _jc_hid_in_spi_read_t
|
||||
{
|
||||
u32 addr;
|
||||
u8 size;
|
||||
u8 data[];
|
||||
} jc_hid_in_spi_read_t;
|
||||
|
||||
typedef struct _jc_hid_in_pair_data_t
|
||||
{
|
||||
u8 magic;
|
||||
u8 size;
|
||||
u16 checksum;
|
||||
u8 mac[6];
|
||||
u8 ltk[16];
|
||||
u8 pad0[10];
|
||||
u8 bt_caps; // bit3: Secure conn supported host, bit5: Paired to TBFC supported host, bit6: iTBFC page supported
|
||||
u8 pad1;
|
||||
} jc_hid_in_pair_data_t;
|
||||
|
||||
typedef struct _joycon_ctxt_t
|
||||
{
|
||||
u8 buf[0x100]; //FIXME: If heap is used, dumping breaks.
|
||||
u8 uart;
|
||||
u8 type;
|
||||
u8 mac[6];
|
||||
u32 hw_init_done;
|
||||
u32 last_received_time;
|
||||
u32 last_status_req_time;
|
||||
u8 rumble_sent;
|
||||
u8 connected;
|
||||
} joycon_ctxt_t;
|
||||
|
||||
static joycon_ctxt_t jc_l;
|
||||
static joycon_ctxt_t jc_r;
|
||||
|
||||
static bool jc_init_done = false;
|
||||
static u32 hid_pkt_inc = 0;
|
||||
|
||||
static jc_gamepad_rpt_t jc_gamepad;
|
||||
|
||||
void jc_power_supply(u8 uart, bool enable);
|
||||
|
||||
void joycon_send_raw(u8 uart_port, const u8 *buf, u16 size)
|
||||
{
|
||||
uart_send(uart_port, buf, size);
|
||||
uart_wait_idle(uart_port, UART_TX_IDLE);
|
||||
}
|
||||
|
||||
static u16 jc_packet_add_uart_hdr(jc_wired_hdr_t *out, u8 wired_cmd, u8 *data, u16 size)
|
||||
{
|
||||
out->uart_hdr.magic[0] = 0x19;
|
||||
out->uart_hdr.magic[1] = 0x01;
|
||||
out->uart_hdr.magic[2] = 0x3;
|
||||
|
||||
out->uart_hdr.total_size_lsb = 7;
|
||||
out->uart_hdr.total_size_msb = 0;
|
||||
out->cmd = wired_cmd;
|
||||
|
||||
if (data)
|
||||
memcpy(out->data, data, size);
|
||||
|
||||
out->crc = 0; // wired crc8ccit can be skipped.
|
||||
|
||||
return sizeof(jc_wired_hdr_t);
|
||||
}
|
||||
|
||||
static u16 jc_hid_output_rpt_craft(jc_wired_hdr_t *rpt, u8 *payload, u16 size)
|
||||
{
|
||||
u16 pkt_size = jc_packet_add_uart_hdr(rpt, JC_WIRED_HID, NULL, 0);
|
||||
pkt_size += size;
|
||||
|
||||
rpt->uart_hdr.total_size_lsb += size;
|
||||
rpt->data[0] = size >> 8;
|
||||
rpt->data[1] = size & 0xFF;
|
||||
|
||||
if (payload)
|
||||
memcpy(rpt->payload, payload, size);
|
||||
|
||||
return pkt_size;
|
||||
}
|
||||
|
||||
void jc_send_hid_output_rpt(u8 uart, u8 *payload, u16 size)
|
||||
{
|
||||
u8 rpt[0x50];
|
||||
memset(rpt, 0, sizeof(rpt));
|
||||
|
||||
u32 rpt_size = jc_hid_output_rpt_craft((jc_wired_hdr_t *)rpt, payload, size);
|
||||
|
||||
joycon_send_raw(uart, rpt, rpt_size);
|
||||
}
|
||||
|
||||
static u8 jc_hid_pkt_id_incr()
|
||||
{
|
||||
u8 curr_id = hid_pkt_inc;
|
||||
hid_pkt_inc++;
|
||||
|
||||
return (curr_id & 0xF);
|
||||
}
|
||||
|
||||
void jc_send_hid_cmd(u8 uart, u8 subcmd, u8 *data, u16 size)
|
||||
{
|
||||
u8 temp[0x30];
|
||||
u8 rumble_neutral[8] = {0x00, 0x01, 0x40, 0x40, 0x00, 0x01, 0x40, 0x40};
|
||||
u8 rumble_init[8] = {0xc2, 0xc8, 0x03, 0x72, 0xc2, 0xc8, 0x03, 0x72};
|
||||
|
||||
memset(temp, 0, sizeof(temp));
|
||||
|
||||
jc_hid_out_rpt_t *hid_pkt = (jc_hid_out_rpt_t *)temp;
|
||||
|
||||
memcpy(hid_pkt->rumble, rumble_neutral, sizeof(rumble_neutral));
|
||||
|
||||
if (subcmd == JC_HID_SUBCMD_SND_RUMBLE)
|
||||
{
|
||||
bool send_r_rumble = jc_r.connected && !jc_r.rumble_sent;
|
||||
bool send_l_rumble = jc_l.connected && !jc_l.rumble_sent;
|
||||
|
||||
// Enable rumble.
|
||||
hid_pkt->cmd = JC_HID_OUTPUT_RPT;
|
||||
hid_pkt->pkt_id = jc_hid_pkt_id_incr();
|
||||
hid_pkt->subcmd = JC_HID_SUBCMD_RUMBLE_CTL;
|
||||
hid_pkt->subcmd_data[0] = 1;
|
||||
if (send_r_rumble)
|
||||
jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 0x10);
|
||||
if (send_l_rumble)
|
||||
jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 0x10);
|
||||
|
||||
// Send rumble.
|
||||
hid_pkt->cmd = JC_HID_RUMBLE_RPT;
|
||||
hid_pkt->pkt_id = jc_hid_pkt_id_incr();
|
||||
memcpy(hid_pkt->rumble, rumble_init, sizeof(rumble_init));
|
||||
if (send_r_rumble)
|
||||
jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 10);
|
||||
if (send_l_rumble)
|
||||
jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 10);
|
||||
|
||||
msleep(15);
|
||||
|
||||
// Disable rumble.
|
||||
hid_pkt->cmd = JC_HID_OUTPUT_RPT;
|
||||
hid_pkt->pkt_id = jc_hid_pkt_id_incr();
|
||||
hid_pkt->subcmd = JC_HID_SUBCMD_RUMBLE_CTL;
|
||||
hid_pkt->subcmd_data[0] = 0;
|
||||
memcpy(hid_pkt->rumble, rumble_neutral, sizeof(rumble_neutral));
|
||||
if (send_r_rumble)
|
||||
jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 0x10);
|
||||
if (send_l_rumble)
|
||||
jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 0x10);
|
||||
}
|
||||
else
|
||||
{
|
||||
hid_pkt->cmd = JC_HID_OUTPUT_RPT;
|
||||
hid_pkt->pkt_id = jc_hid_pkt_id_incr();
|
||||
hid_pkt->subcmd = subcmd;
|
||||
if (data)
|
||||
memcpy(hid_pkt->subcmd_data, data, size);
|
||||
|
||||
u8 pkt_size = sizeof(jc_hid_out_rpt_t) + size;
|
||||
|
||||
if (subcmd != JC_HID_SUBCMD_SPI_READ)
|
||||
jc_send_hid_output_rpt(uart, (u8 *)hid_pkt, pkt_size);
|
||||
else
|
||||
{
|
||||
jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, pkt_size);
|
||||
jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, pkt_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void jc_charging_decider(u8 batt, u8 uart)
|
||||
{
|
||||
u32 system_batt_enough = max17050_get_cached_batt_volt() > 4000;
|
||||
|
||||
// Power supply control based on battery levels and charging.
|
||||
if ((batt >> 1 << 1) < JC_BATT_LOW) // Level without checking charging.
|
||||
jc_power_supply(uart, true);
|
||||
else if (batt > (system_batt_enough ? JC_BATT_FULL : JC_BATT_MID)) // Addresses the charging bit.
|
||||
jc_power_supply(uart, false);
|
||||
}
|
||||
|
||||
static void jc_parse_wired_hid(joycon_ctxt_t *jc, const u8* packet, u32 size)
|
||||
{
|
||||
u32 btn_tmp;
|
||||
jc_hid_in_rpt_t *hid_pkt = (jc_hid_in_rpt_t *)packet;
|
||||
|
||||
switch (hid_pkt->cmd)
|
||||
{
|
||||
case JC_HID_INPUT_RPT:
|
||||
btn_tmp = hid_pkt->btn_right | hid_pkt->btn_shared << 8 | hid_pkt->btn_left << 16;
|
||||
|
||||
if (jc->type & JC_ID_L)
|
||||
{
|
||||
jc_gamepad.buttons &= ~JC_BTN_MASK_L;
|
||||
jc_gamepad.buttons |= (btn_tmp & JC_BTN_MASK_L);
|
||||
|
||||
jc_gamepad.lstick_x = hid_pkt->stick_h_left | ((hid_pkt->stick_m_left & 0xF) << 8);
|
||||
jc_gamepad.lstick_y = (hid_pkt->stick_m_left >> 4) | (hid_pkt->stick_v_left << 4);
|
||||
|
||||
jc_gamepad.batt_info_l = hid_pkt->batt_info;
|
||||
}
|
||||
else if (jc->type & JC_ID_R)
|
||||
{
|
||||
jc_gamepad.buttons &= ~JC_BTN_MASK_R;
|
||||
jc_gamepad.buttons |= (btn_tmp & JC_BTN_MASK_R);
|
||||
|
||||
jc_gamepad.rstick_x = hid_pkt->stick_h_right | ((hid_pkt->stick_m_right & 0xF) << 8);
|
||||
jc_gamepad.rstick_y = (hid_pkt->stick_m_right >> 4) | (hid_pkt->stick_v_right << 4);
|
||||
|
||||
jc_gamepad.batt_info_r = hid_pkt->batt_info;
|
||||
}
|
||||
|
||||
jc_gamepad.conn_l = jc_l.connected;
|
||||
jc_gamepad.conn_r = jc_r.connected;
|
||||
|
||||
jc_charging_decider(hid_pkt->batt_info, jc->uart);
|
||||
break;
|
||||
case JC_HID_SUBMCD_RPT:
|
||||
if (hid_pkt->subcmd == JC_HID_SUBCMD_SPI_READ)
|
||||
{
|
||||
jc_bt_conn_t *bt_conn;
|
||||
|
||||
if (jc->type & JC_ID_L)
|
||||
bt_conn = &jc_gamepad.bt_conn_l;
|
||||
else
|
||||
bt_conn = &jc_gamepad.bt_conn_r;
|
||||
|
||||
jc_hid_in_spi_read_t *spi_info = (jc_hid_in_spi_read_t *)hid_pkt->subcmd_data;
|
||||
jc_hid_in_pair_data_t *pair_data = (jc_hid_in_pair_data_t *)spi_info->data;
|
||||
|
||||
// Check if we reply is pairing info.
|
||||
if (spi_info->addr == 0x2000 && spi_info->size == 0x1A && pair_data->magic == 0x95)
|
||||
{
|
||||
bt_conn->type = jc->type;
|
||||
|
||||
memcpy(bt_conn->mac, jc->mac, 6);
|
||||
memcpy(bt_conn->host_mac, pair_data->mac, 6);
|
||||
for (u32 i = 16; i > 0; i--)
|
||||
bt_conn->ltk[16 - i] = pair_data->ltk[i - 1];
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
jc->last_received_time = get_tmr_ms();
|
||||
}
|
||||
|
||||
static void jc_parse_wired_init(joycon_ctxt_t *jc, const u8* data, u32 size)
|
||||
{
|
||||
switch (data[0])
|
||||
{
|
||||
case JC_WIRED_CMD_MAC:
|
||||
for (int i = 12; i > 6; i--)
|
||||
jc->mac[12 - i] = data[i];
|
||||
jc->type = data[6];
|
||||
jc->connected = true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void jc_uart_pkt_parse(joycon_ctxt_t *jc, const u8* packet, size_t size)
|
||||
{
|
||||
jc_wired_hdr_t *pkt = (jc_wired_hdr_t *)packet;
|
||||
switch (pkt->cmd)
|
||||
{
|
||||
case JC_WIRED_HID:
|
||||
jc_parse_wired_hid(jc, pkt->payload, (pkt->data[0] << 8) | pkt->data[1]);
|
||||
break;
|
||||
case JC_WIRED_INIT_REPLY:
|
||||
jc_parse_wired_init(jc, pkt->data, size - sizeof(jc_uart_hdr_t) - 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void jc_rcv_pkt(joycon_ctxt_t *jc)
|
||||
{
|
||||
if (gpio_read(GPIO_PORT_E, GPIO_PIN_6) && jc->uart == UART_C)
|
||||
return;
|
||||
else if (gpio_read(GPIO_PORT_H, GPIO_PIN_6) && jc->uart == UART_B)
|
||||
return;
|
||||
|
||||
// Check if device stopped sending data.
|
||||
u32 uart_irq = uart_get_IIR(jc->uart);
|
||||
if ((uart_irq & 0x8) != 0x8)
|
||||
return;
|
||||
|
||||
u32 len = uart_recv(jc->uart, (u8 *)jc->buf, 0);
|
||||
|
||||
// Check valid size and uart reply magic.
|
||||
if (len > 7 && !memcmp(jc->buf, "\x19\x81\x03", 3))
|
||||
{
|
||||
jc_wired_hdr_t *pkt = (jc_wired_hdr_t *)(jc->buf);
|
||||
|
||||
jc_uart_pkt_parse(jc, jc->buf, pkt->uart_hdr.total_size_lsb + sizeof(jc_uart_hdr_t));
|
||||
}
|
||||
}
|
||||
|
||||
static bool jc_send_init_rumble(joycon_ctxt_t *jc)
|
||||
{
|
||||
// Send init rumble or request nx pad status report.
|
||||
if ((jc_r.connected && !jc_r.rumble_sent) || (jc_l.connected && !jc_l.rumble_sent))
|
||||
{
|
||||
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
|
||||
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
|
||||
|
||||
jc_send_hid_cmd(jc->uart, JC_HID_SUBCMD_SND_RUMBLE, NULL, 0);
|
||||
|
||||
if (jc_l.connected)
|
||||
jc_l.rumble_sent = true;
|
||||
if (jc_r.connected)
|
||||
jc_r.rumble_sent = true;
|
||||
|
||||
if (jc->uart != UART_B)
|
||||
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
|
||||
else
|
||||
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void jc_req_nx_pad_status(joycon_ctxt_t *jc)
|
||||
{
|
||||
bool sent_rumble = jc_send_init_rumble(jc);
|
||||
|
||||
if (sent_rumble)
|
||||
return;
|
||||
|
||||
if (jc->last_status_req_time > get_tmr_ms() || !jc->connected)
|
||||
return;
|
||||
|
||||
// Turn off Joy-Con detect.
|
||||
if (jc->uart == UART_B)
|
||||
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
|
||||
else
|
||||
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
|
||||
|
||||
joycon_send_raw(jc->uart, nx_pad_status, sizeof(nx_pad_status));
|
||||
|
||||
// Turn Joy-Con detect on.
|
||||
if (jc->uart == UART_B)
|
||||
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
|
||||
else
|
||||
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||
|
||||
jc->last_status_req_time = get_tmr_ms() + 15;
|
||||
}
|
||||
|
||||
jc_gamepad_rpt_t *jc_get_bt_pairing_info()
|
||||
{
|
||||
u8 retries;
|
||||
jc_bt_conn_t *bt_conn;
|
||||
|
||||
bt_conn = &jc_gamepad.bt_conn_l;
|
||||
memset(bt_conn->host_mac, 0, 6);
|
||||
memset(bt_conn->ltk, 0, 16);
|
||||
|
||||
bt_conn = &jc_gamepad.bt_conn_r;
|
||||
memset(bt_conn->host_mac, 0, 6);
|
||||
memset(bt_conn->ltk, 0, 16);
|
||||
|
||||
while (jc_l.last_status_req_time > get_tmr_ms())
|
||||
{
|
||||
jc_rcv_pkt(&jc_r);
|
||||
jc_rcv_pkt(&jc_l);
|
||||
}
|
||||
|
||||
jc_hid_in_spi_read_t subcmd_data;
|
||||
subcmd_data.addr = 0x2000;
|
||||
subcmd_data.size = 0x1A;
|
||||
|
||||
// Turn off Joy-Con detect.
|
||||
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
|
||||
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
|
||||
|
||||
bool jc_r_found = jc_r.connected ? false : true;
|
||||
bool jc_l_found = jc_l.connected ? false : true;
|
||||
|
||||
u32 total_retries = 5;
|
||||
retry:
|
||||
retries = 10;
|
||||
while (retries)
|
||||
{
|
||||
if (jc_l.last_status_req_time < get_tmr_ms())
|
||||
{
|
||||
jc_send_hid_cmd(0, JC_HID_SUBCMD_SPI_READ, (u8 *)&subcmd_data, 5);
|
||||
jc_l.last_status_req_time = get_tmr_ms() + 15;
|
||||
jc_r.last_status_req_time = get_tmr_ms() + 15;
|
||||
retries--;
|
||||
}
|
||||
|
||||
if (!jc_r_found)
|
||||
{
|
||||
memset(jc_r.buf, 0, 0x100);
|
||||
jc_rcv_pkt(&jc_r);
|
||||
}
|
||||
|
||||
if (!jc_l_found)
|
||||
{
|
||||
memset(jc_l.buf, 0, 0x100);
|
||||
jc_rcv_pkt(&jc_l);
|
||||
}
|
||||
}
|
||||
|
||||
if (jc_l.connected &&
|
||||
memcmp(&jc_gamepad.bt_conn_l.ltk[0], "\x00\x00\x00\x00", 4) &&
|
||||
memcmp(&jc_gamepad.bt_conn_l.ltk[8], "\x00\x00\x00\x00", 4))
|
||||
jc_l_found = true;
|
||||
|
||||
if (jc_r.connected &&
|
||||
memcmp(&jc_gamepad.bt_conn_r.ltk[0], "\x00\x00\x00\x00", 4) &&
|
||||
memcmp(&jc_gamepad.bt_conn_r.ltk[8], "\x00\x00\x00\x00", 4))
|
||||
jc_r_found = true;
|
||||
|
||||
if (total_retries && (!jc_l_found || !jc_r_found))
|
||||
{
|
||||
total_retries--;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
// Turn Joy-Con detect on.
|
||||
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
|
||||
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||
|
||||
return &jc_gamepad;
|
||||
}
|
||||
|
||||
void jc_deinit()
|
||||
{
|
||||
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
|
||||
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
|
||||
|
||||
u8 data = HCI_STATE_SLEEP;
|
||||
|
||||
if (jc_r.connected)
|
||||
{
|
||||
jc_send_hid_cmd(UART_B, JC_HID_SUBCMD_HCI_STATE, &data, 1);
|
||||
msleep(1);
|
||||
jc_rcv_pkt(&jc_r);
|
||||
}
|
||||
if (jc_l.connected)
|
||||
{
|
||||
jc_send_hid_cmd(UART_C, JC_HID_SUBCMD_HCI_STATE, &data, 1);
|
||||
msleep(1);
|
||||
jc_rcv_pkt(&jc_l);
|
||||
}
|
||||
|
||||
jc_power_supply(UART_B, false);
|
||||
jc_power_supply(UART_C, false);
|
||||
}
|
||||
|
||||
static void jc_init_conn(joycon_ctxt_t *jc)
|
||||
{
|
||||
if (((u32)get_tmr_ms() - jc->last_received_time) > 1000)
|
||||
{
|
||||
jc_power_supply(jc->uart, true);
|
||||
|
||||
// Turn off Joy-Con detect.
|
||||
if (jc->uart == UART_B)
|
||||
{
|
||||
jc_gamepad.buttons &= ~JC_BTN_MASK_R;
|
||||
jc_gamepad.conn_r = false;
|
||||
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
|
||||
}
|
||||
else
|
||||
{
|
||||
jc_gamepad.buttons &= ~JC_BTN_MASK_L;
|
||||
jc_gamepad.conn_l = false;
|
||||
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
|
||||
}
|
||||
|
||||
uart_init(jc->uart, 1000000);
|
||||
uart_invert(jc->uart, true, UART_INVERT_TXD);
|
||||
uart_set_IIR(jc->uart);
|
||||
|
||||
joycon_send_raw(jc->uart, init_jc, 4);
|
||||
joycon_send_raw(jc->uart, init_handshake, sizeof(init_handshake));
|
||||
|
||||
msleep(5);
|
||||
jc_rcv_pkt(jc);
|
||||
|
||||
joycon_send_raw(jc->uart, init_get_info, sizeof(init_get_info));
|
||||
msleep(5);
|
||||
jc_rcv_pkt(jc);
|
||||
|
||||
joycon_send_raw(jc->uart, init_finilize, sizeof(init_finilize));
|
||||
msleep(5);
|
||||
jc_rcv_pkt(jc);
|
||||
|
||||
// Turn Joy-Con detect on.
|
||||
if (jc->uart == UART_B)
|
||||
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
|
||||
else
|
||||
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||
|
||||
jc->last_received_time = get_tmr_ms();
|
||||
|
||||
if (jc->connected)
|
||||
jc_power_supply(jc->uart, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void jc_conn_check()
|
||||
{
|
||||
// Check if a Joy-Con was disconnected.
|
||||
if (gpio_read(GPIO_PORT_E, GPIO_PIN_6))
|
||||
{
|
||||
jc_power_supply(UART_C, false);
|
||||
|
||||
hid_pkt_inc = 0;
|
||||
|
||||
jc_l.connected = false;
|
||||
jc_l.rumble_sent = false;
|
||||
|
||||
jc_gamepad.buttons &= ~JC_BTN_MASK_L;
|
||||
jc_gamepad.conn_l = false;
|
||||
|
||||
jc_gamepad.batt_info_l = 0;
|
||||
jc_gamepad.bt_conn_l.type = 0;
|
||||
}
|
||||
|
||||
if (gpio_read(GPIO_PORT_H, GPIO_PIN_6))
|
||||
{
|
||||
jc_power_supply(UART_B, false);
|
||||
|
||||
hid_pkt_inc = 0;
|
||||
|
||||
jc_r.connected = false;
|
||||
jc_r.rumble_sent = false;
|
||||
|
||||
jc_gamepad.buttons &= ~JC_BTN_MASK_R;
|
||||
jc_gamepad.conn_r = false;
|
||||
|
||||
jc_gamepad.batt_info_r = 0;
|
||||
jc_gamepad.bt_conn_r.type = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void jc_power_supply(u8 uart, bool enable)
|
||||
{
|
||||
if (enable)
|
||||
{
|
||||
if (regulator_get_5v_dev_enabled(1 << uart))
|
||||
return;
|
||||
|
||||
regulator_enable_5v(1 << uart);
|
||||
|
||||
if (jc_init_done)
|
||||
{
|
||||
if (uart == UART_C)
|
||||
gpio_write(GPIO_PORT_CC, GPIO_PIN_3, GPIO_HIGH);
|
||||
else
|
||||
gpio_write(GPIO_PORT_K, GPIO_PIN_3, GPIO_HIGH);
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart == UART_C)
|
||||
{
|
||||
// Joy-Con(L) Charge Detect.
|
||||
PINMUX_AUX(PINMUX_AUX_SPDIF_IN) = PINMUX_PULL_DOWN | 1;
|
||||
gpio_config(GPIO_PORT_CC, GPIO_PIN_3, GPIO_MODE_GPIO);
|
||||
gpio_output_enable(GPIO_PORT_CC, GPIO_PIN_3, GPIO_OUTPUT_ENABLE);
|
||||
gpio_write(GPIO_PORT_CC, GPIO_PIN_3, GPIO_HIGH);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Joy-Con(R) Charge Detect.
|
||||
PINMUX_AUX(PINMUX_AUX_GPIO_PK3) = PINMUX_DRIVE_4X | PINMUX_PULL_DOWN | 2;
|
||||
gpio_config(GPIO_PORT_K, GPIO_PIN_3, GPIO_MODE_GPIO);
|
||||
gpio_output_enable(GPIO_PORT_K, GPIO_PIN_3, GPIO_OUTPUT_ENABLE);
|
||||
gpio_write(GPIO_PORT_K, GPIO_PIN_3, GPIO_HIGH);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!regulator_get_5v_dev_enabled(1 << uart))
|
||||
return;
|
||||
|
||||
regulator_disable_5v(1 << uart);
|
||||
|
||||
if (uart == UART_C)
|
||||
gpio_write(GPIO_PORT_CC, GPIO_PIN_3, GPIO_LOW);
|
||||
else
|
||||
gpio_write(GPIO_PORT_K, GPIO_PIN_3, GPIO_LOW);
|
||||
}
|
||||
}
|
||||
|
||||
void jc_init_hw()
|
||||
{
|
||||
jc_l.uart = UART_C;
|
||||
jc_r.uart = UART_B;
|
||||
|
||||
#if (LV_LOG_PRINTF != 1)
|
||||
jc_power_supply(UART_C, true);
|
||||
jc_power_supply(UART_B, true);
|
||||
|
||||
// Joy-Con (R) IsAttached.
|
||||
PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
|
||||
gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_GPIO);
|
||||
|
||||
// Joy-Con (L) IsAttached.
|
||||
PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
|
||||
gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO);
|
||||
|
||||
// Configure pinmuxing for UART B and C.
|
||||
pinmux_config_uart(UART_B);
|
||||
pinmux_config_uart(UART_C);
|
||||
|
||||
// Ease the stress to APB.
|
||||
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
|
||||
|
||||
// Enable UART B and C clocks.
|
||||
clock_enable_uart(UART_B);
|
||||
clock_enable_uart(UART_C);
|
||||
|
||||
// Restore OC.
|
||||
bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST);
|
||||
|
||||
// Turn Joy-Con detect on.
|
||||
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
|
||||
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||
|
||||
jc_init_done = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
jc_gamepad_rpt_t *joycon_poll()
|
||||
{
|
||||
if (!jc_init_done)
|
||||
return NULL;
|
||||
|
||||
if (!gpio_read(GPIO_PORT_H, GPIO_PIN_6))
|
||||
jc_init_conn(&jc_r);
|
||||
if (!gpio_read(GPIO_PORT_E, GPIO_PIN_6))
|
||||
jc_init_conn(&jc_l);
|
||||
|
||||
if (!gpio_read(GPIO_PORT_H, GPIO_PIN_6))
|
||||
jc_req_nx_pad_status(&jc_r);
|
||||
if (!gpio_read(GPIO_PORT_E, GPIO_PIN_6))
|
||||
jc_req_nx_pad_status(&jc_l);
|
||||
|
||||
if (!gpio_read(GPIO_PORT_H, GPIO_PIN_6))
|
||||
jc_rcv_pkt(&jc_r);
|
||||
if (!gpio_read(GPIO_PORT_E, GPIO_PIN_6))
|
||||
jc_rcv_pkt(&jc_l);
|
||||
|
||||
jc_conn_check();
|
||||
|
||||
return &jc_gamepad;
|
||||
}
|
98
source/hid/joycon.h
Normal file
98
source/hid/joycon.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Ambient light sensor driver for Nintendo Switch's Rohm BH1730
|
||||
*
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __JOYCON_H_
|
||||
#define __JOYCON_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define JC_BTNS_DIRECTION_PAD 0xF0000
|
||||
#define JC_BTNS_PREV_NEXT 0x800080
|
||||
#define JC_BTNS_ENTER 0x400008
|
||||
#define JC_BTNS_ESC 0x4
|
||||
|
||||
#define JC_BTNS_ALL (JC_BTNS_PREV_NEXT | JC_BTNS_ENTER | JC_BTNS_DIRECTION_PAD | JC_BTNS_ESC)
|
||||
|
||||
typedef struct _jc_bt_conn_t
|
||||
{
|
||||
u8 type;
|
||||
u8 mac[6];
|
||||
u8 host_mac[6];
|
||||
u8 ltk[16];
|
||||
} jc_bt_conn_t;
|
||||
|
||||
typedef struct _jc_gamepad_rpt_t
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
// Joy-Con (R).
|
||||
u32 y:1;
|
||||
u32 x:1;
|
||||
u32 b:1;
|
||||
u32 a:1;
|
||||
u32 sr_r:1;
|
||||
u32 sl_r:1;
|
||||
u32 r:1;
|
||||
u32 zr:1;
|
||||
|
||||
// Shared
|
||||
u32 minus:1;
|
||||
u32 plus:1;
|
||||
u32 r3:1;
|
||||
u32 l3:1;
|
||||
u32 home:1;
|
||||
u32 cap:1;
|
||||
u32 pad:1;
|
||||
u32 wired:1;
|
||||
|
||||
// Joy-Con (L).
|
||||
u32 down:1;
|
||||
u32 up:1;
|
||||
u32 right:1;
|
||||
u32 left:1;
|
||||
u32 sr_l:1;
|
||||
u32 sl_l:1;
|
||||
u32 l:1;
|
||||
u32 zl:1;
|
||||
};
|
||||
u32 buttons;
|
||||
};
|
||||
|
||||
u16 lstick_x;
|
||||
u16 lstick_y;
|
||||
u16 rstick_x;
|
||||
u16 rstick_y;
|
||||
bool center_stick_l;
|
||||
bool center_stick_r;
|
||||
bool conn_l;
|
||||
bool conn_r;
|
||||
u8 batt_info_l;
|
||||
u8 batt_info_r;
|
||||
jc_bt_conn_t bt_conn_l;
|
||||
jc_bt_conn_t bt_conn_r;
|
||||
} jc_gamepad_rpt_t;
|
||||
|
||||
void jc_power_supply(u8 uart, bool enable);
|
||||
void jc_init_hw();
|
||||
void jc_deinit();
|
||||
jc_gamepad_rpt_t *joycon_poll();
|
||||
jc_gamepad_rpt_t *jc_get_bt_pairing_info();
|
||||
|
||||
#endif
|
76
source/power/regulator_5v.c
Normal file
76
source/power/regulator_5v.c
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../soc/gpio.h"
|
||||
#include "../soc/pinmux.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../utils/types.h"
|
||||
|
||||
static u8 reg_5v_dev = 0;
|
||||
|
||||
void regulator_enable_5v(u8 dev)
|
||||
{
|
||||
// The power supply selection from battery or USB is automatic.
|
||||
if (!reg_5v_dev)
|
||||
{
|
||||
// Fan and Rail power from internal 5V regulator (battery).
|
||||
PINMUX_AUX(PINMUX_AUX_SATA_LED_ACTIVE) = 1;
|
||||
gpio_config(GPIO_PORT_A, GPIO_PIN_5, GPIO_MODE_GPIO);
|
||||
gpio_output_enable(GPIO_PORT_A, GPIO_PIN_5, GPIO_OUTPUT_ENABLE);
|
||||
gpio_write(GPIO_PORT_A, GPIO_PIN_5, GPIO_HIGH);
|
||||
|
||||
// Fan and Rail power from USB 5V VDD.
|
||||
PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN0) = PINMUX_LPDR | 1;
|
||||
gpio_config(GPIO_PORT_CC, GPIO_PIN_4, GPIO_MODE_GPIO);
|
||||
gpio_output_enable(GPIO_PORT_CC, GPIO_PIN_4, GPIO_OUTPUT_ENABLE);
|
||||
gpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_HIGH);
|
||||
|
||||
// Make sure GPIO power is enabled.
|
||||
PMC(APBDEV_PMC_NO_IOPOWER) &= ~PMC_NO_IOPOWER_GPIO_IO_EN;
|
||||
// Override power detect for GPIO AO IO rails.
|
||||
PMC(APBDEV_PMC_PWR_DET_VAL) &= ~PMC_PWR_DET_GPIO_IO_EN;
|
||||
}
|
||||
reg_5v_dev |= dev;
|
||||
}
|
||||
|
||||
void regulator_disable_5v(u8 dev)
|
||||
{
|
||||
reg_5v_dev &= ~dev;
|
||||
|
||||
if (!reg_5v_dev)
|
||||
{
|
||||
// Rail power from internal 5V regulator (battery).
|
||||
gpio_write(GPIO_PORT_A, GPIO_PIN_5, GPIO_LOW);
|
||||
gpio_output_enable(GPIO_PORT_A, GPIO_PIN_5, GPIO_OUTPUT_DISABLE);
|
||||
gpio_config(GPIO_PORT_A, GPIO_PIN_5, GPIO_MODE_SPIO);
|
||||
PINMUX_AUX(PINMUX_AUX_SATA_LED_ACTIVE) = PINMUX_PARKED | PINMUX_INPUT_ENABLE;
|
||||
|
||||
// Rail power from USB 5V VDD.
|
||||
gpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_LOW);
|
||||
gpio_output_enable(GPIO_PORT_CC, GPIO_PIN_4, GPIO_OUTPUT_DISABLE);
|
||||
gpio_config(GPIO_PORT_CC, GPIO_PIN_4, GPIO_MODE_SPIO);
|
||||
PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN0) = PINMUX_IO_HV | PINMUX_LPDR | PINMUX_PARKED | PINMUX_INPUT_ENABLE;
|
||||
|
||||
// GPIO AO IO rails.
|
||||
PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_GPIO_IO_EN;
|
||||
}
|
||||
}
|
||||
|
||||
bool regulator_get_5v_dev_enabled(u8 dev)
|
||||
{
|
||||
return (reg_5v_dev & dev);
|
||||
}
|
34
source/power/regulator_5v.h
Normal file
34
source/power/regulator_5v.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _REGULATOR_5V_H_
|
||||
#define _REGULATOR_5V_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
enum
|
||||
{
|
||||
REGULATOR_5V_FAN = (1 << 0),
|
||||
REGULATOR_5V_JC_R = (1 << 1),
|
||||
REGULATOR_5V_JC_L = (1 << 2),
|
||||
REGULATOR_5V_ALL = 0xFF
|
||||
};
|
||||
|
||||
void regulator_enable_5v(u8 dev);
|
||||
void regulator_disable_5v(u8 dev);
|
||||
bool regulator_get_5v_dev_enabled(u8 dev);
|
||||
|
||||
#endif
|
|
@ -6,6 +6,7 @@
|
|||
#include "../../utils/util.h"
|
||||
#include "../../mem/minerva.h"
|
||||
#include "../../soc/gpio.h"
|
||||
#include "../../hid/hid.h"
|
||||
|
||||
extern void sd_unmount();
|
||||
extern bool sd_inited;
|
||||
|
@ -60,10 +61,13 @@ void _printentry(menu_entry entry, bool highlighted, bool refresh){
|
|||
}
|
||||
}
|
||||
|
||||
bool disableB = false;
|
||||
int menu_make(menu_entry *entries, int amount, char *toptext){
|
||||
int currentpos = 0, res = 0, offset = 0, delay = 300, minscreen = 0, maxscreen = 29, calculatedamount = 0;
|
||||
int currentpos = 0, offset = 0, delay = 300, minscreen = 0, maxscreen = 29, calculatedamount = 0;
|
||||
u32 scrolltimer, timer;
|
||||
bool refresh = false;
|
||||
Inputs *input = hidRead();
|
||||
input->buttons = 0;
|
||||
|
||||
gfx_clearscreen();
|
||||
|
||||
|
@ -85,7 +89,7 @@ int menu_make(menu_entry *entries, int amount, char *toptext){
|
|||
gfx_printlength(42, toptext);
|
||||
RESETCOLOR;
|
||||
|
||||
while (!(res & BTN_POWER)){
|
||||
while (!(input->a)){
|
||||
gfx_con_setpos(0, 47);
|
||||
timer = get_tmr_ms();
|
||||
refresh = false;
|
||||
|
@ -119,47 +123,54 @@ int menu_make(menu_entry *entries, int amount, char *toptext){
|
|||
|
||||
gfx_printf("\n%k%K %s %s\n\nTime taken for screen draw: %dms ", COLOR_BLUE, COLOR_DEFAULT, (offset + 30 < amount) ? "v" : " ", (offset > 0) ? "^" : " ", get_tmr_ms() - timer);
|
||||
|
||||
while (btn_read() & BTN_POWER);
|
||||
while ((input = hidRead())->buttons & (KEY_B | KEY_A));
|
||||
|
||||
res = 0;
|
||||
while (!res){
|
||||
input->buttons = 0;
|
||||
while (!(input->buttons & (KEY_A | KEY_LDOWN | KEY_LUP | KEY_B | KEY_RUP | KEY_RDOWN))){
|
||||
if (sd_inited && !!gpio_read(GPIO_PORT_Z, GPIO_PIN_1)){
|
||||
gfx_errDisplay("menu", ERR_SD_EJECTED, 0);
|
||||
sd_unmount();
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = btn_read();
|
||||
input = hidRead();
|
||||
|
||||
if (!res)
|
||||
if (!(input->buttons & (KEY_A | KEY_LDOWN | KEY_LUP | KEY_B | KEY_RUP | KEY_RDOWN)))
|
||||
delay = 300;
|
||||
|
||||
if (delay < 300){
|
||||
scrolltimer = get_tmr_ms();
|
||||
while (res){
|
||||
while (input->buttons & (KEY_A | KEY_LDOWN | KEY_LUP | KEY_B | KEY_RUP | KEY_RDOWN)){
|
||||
if (scrolltimer + delay <= get_tmr_ms())
|
||||
break;
|
||||
|
||||
res = btn_read();
|
||||
input = hidRead();
|
||||
}
|
||||
}
|
||||
|
||||
if (delay > 46 && res)
|
||||
if (delay > 46 && input->buttons & (KEY_A | KEY_LDOWN | KEY_LUP | KEY_B | KEY_RUP | KEY_RDOWN))
|
||||
delay -= 45;
|
||||
|
||||
if (input->buttons & (KEY_RUP | KEY_RDOWN))
|
||||
delay = 1;
|
||||
}
|
||||
|
||||
if (res & BTN_VOL_UP && currentpos >= 1){
|
||||
if (input->buttons & (KEY_LUP | KEY_RUP) && currentpos >= 1){
|
||||
currentpos--;
|
||||
while(entries[currentpos].property & (ISSKIP | ISHIDE) && currentpos >= 1)
|
||||
currentpos--;
|
||||
}
|
||||
|
||||
else if (res & BTN_VOL_DOWN && currentpos < amount - 1){
|
||||
else if (input->buttons & (KEY_LDOWN | KEY_RDOWN) && currentpos < amount - 1){
|
||||
currentpos++;
|
||||
while(entries[currentpos].property & (ISSKIP | ISHIDE) && currentpos < amount - 1)
|
||||
currentpos++;
|
||||
}
|
||||
|
||||
else if (input->b && !disableB){
|
||||
currentpos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
minerva_periodic_training();
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include "emmc/emmcoperations.h"
|
||||
#include "emmc/emmcmenu.h"
|
||||
#include "../storage/nx_sd.h"
|
||||
//#include "../hid/joycon.h"
|
||||
#include "../hid/hid.h"
|
||||
/*
|
||||
extern bool sd_mount();
|
||||
extern void sd_unmount();
|
||||
|
@ -25,6 +27,7 @@ extern void sd_unmount();
|
|||
extern int launch_payload(char *path);
|
||||
extern bool sd_inited;
|
||||
extern bool sd_mounted;
|
||||
extern bool disableB;
|
||||
|
||||
int res = 0, meter = 0;
|
||||
|
||||
|
@ -102,8 +105,6 @@ void MainMenu_Credits(){
|
|||
if (++meter >= 3)
|
||||
gfx_errDisplay("credits", 53, 0);
|
||||
gfx_message(COLOR_WHITE, mainmenu_credits);
|
||||
int frii = 10/0;
|
||||
gfx_printf("%d", frii);
|
||||
}
|
||||
|
||||
void MainMenu_Exit(){
|
||||
|
@ -172,6 +173,8 @@ void te_main(){
|
|||
|
||||
disconnect_mmc();
|
||||
|
||||
hidInit();
|
||||
|
||||
while (1){
|
||||
//fillmainmenu();
|
||||
|
||||
|
@ -187,7 +190,10 @@ void te_main(){
|
|||
setter = sd_inited;
|
||||
SETBIT(mainmenu_main[5].property, ISHIDE, !setter);
|
||||
|
||||
disableB = true;
|
||||
res = menu_make(mainmenu_main, 8, "-- Main Menu --") + 1;
|
||||
disableB = false;
|
||||
|
||||
RunMenuOption(res);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue