bdk: joycon: improve charger config

Utilize charger config set command which allows for supplement mode.
Additionally, remove ping config when SIO and parse buttons/sticks on subcmd reports.
This commit is contained in:
CTCaer
2025-12-27 06:06:17 +02:00
parent acb50dad7b
commit c03757e73d
2 changed files with 191 additions and 69 deletions

View File

@@ -1,7 +1,7 @@
/* /*
* Joy-Con UART driver for Nintendo Switch * Joy-Con UART driver for Nintendo Switch
* *
* Copyright (c) 2019-2024 CTCaer * Copyright (c) 2019-2025 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -65,6 +65,7 @@
#define JC_HID_SUBCMD_SPI_READ 0x10 #define JC_HID_SUBCMD_SPI_READ 0x10
#define SPI_READ_OFFSET 0x20 #define SPI_READ_OFFSET 0x20
#define JC_HID_SUBCMD_RUMBLE_CTL 0x48 #define JC_HID_SUBCMD_RUMBLE_CTL 0x48
#define JC_HID_SUBCMD_CHARGE_SET 0x51
#define JC_HID_SUBCMD_SND_RUMBLE 0xFF #define JC_HID_SUBCMD_SND_RUMBLE 0xFF
#define JC_SIO_OUTPUT_RPT 0x91 #define JC_SIO_OUTPUT_RPT 0x91
@@ -102,11 +103,25 @@ enum
enum enum
{ {
JC_BATT_EMTPY = 0, JC_BATT_EMPTY = 0,
JC_BATT_CRIT = 1, JC_BATT_CRIT = 1, // 3300 - 3599 mV.
JC_BATT_LOW = 2, JC_BATT_LOW = 2, // 3600 - 3759 mV.
JC_BATT_MID = 3, JC_BATT_MID = 3, // 3760 - 3899 mV.
JC_BATT_FULL = 4 JC_BATT_FULL = 4 // 3900 - 4200 mV.
};
#define JC_CHRG_CFG_SUPL0 0x00 // 100 OFF.
#define JC_CHRG_CFG_SUPL1 0x10 // EN2 OFF.
#define JC_CHRG_CFG_100MA 0x04 // 100 ON.
#define JC_CHRG_CFG_200MA 0x14 // EN2 ON.
enum
{
JC_CHRG_STATE_INIT = 0,
JC_CHRG_STATE_OFF = 1, // Regulator OFF.
JC_CHRG_STATE_SUPL = 2, // JC_CHRG_CFG_SUPL0.
JC_CHRG_STATE_SLOW = 3, // JC_CHRG_CFG_100MA.
JC_CHRG_STATE_FAST = 4, // JC_CHRG_CFG_200MA.
}; };
static const u8 sio_init[] = { static const u8 sio_init[] = {
@@ -146,7 +161,7 @@ static const u8 init_get_info[] = {
static const u8 init_switch_brate[] = { static const u8 init_switch_brate[] = {
0x19, 0x01, 0x03, 0x0F, 0x00, // Uart header. 0x19, 0x01, 0x03, 0x0F, 0x00, // Uart header.
JC_WIRED_CMD, JC_WIRED_CMD_SET_BRATE, // Wired cmd and subcmd. JC_WIRED_CMD, JC_WIRED_CMD_SET_BRATE, // Wired cmd and subcmd.
0x08, 0x00, 0x00, 0xBD, 0xB1, // Wired subcmd data, data crc and crc. 0x08, 0x00, 0x00, 0xBD, 0xB1, // Wired subcmd data size, data crc and crc.
// Baudrate 3 megabaud. // Baudrate 3 megabaud.
0xC0, 0xC6, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00 0xC0, 0xC6, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00
}; };
@@ -154,14 +169,14 @@ static const u8 init_switch_brate[] = {
static const u8 init_hid_disconnect[] = { static const u8 init_hid_disconnect[] = {
0x19, 0x01, 0x03, 0x07, 0x00, // Uart header. 0x19, 0x01, 0x03, 0x07, 0x00, // Uart header.
JC_WIRED_CMD, JC_WIRED_CMD_HID_DISC, // Wired cmd and subcmd. JC_WIRED_CMD, JC_WIRED_CMD_HID_DISC, // Wired cmd and subcmd.
0x00, 0x00, 0x00, 0x00, 0x0E // Wired subcmd data and crc. 0x00, 0x00, 0x00, 0x00, 0x0E // Wired subcmd data size and crc.
}; };
static const u8 init_set_hid_rate[] = { static const u8 init_set_hid_rate[] = {
0x19, 0x01, 0x03, 0x0B, 0x00, // Uart header. 0x19, 0x01, 0x03, 0x0B, 0x00, // Uart header.
JC_WIRED_CMD, JC_WIRED_CMD_SET_HIDRATE, // Wired cmd and subcmd. JC_WIRED_CMD, JC_WIRED_CMD_SET_HIDRATE, // Wired cmd and subcmd.
0x04, 0x00, 0x00, 0x12, 0xA6, // Wired subcmd data, data crc and crc. 0x04, 0x00, 0x00, 0x12, 0xA6, // Wired subcmd data size, data crc and crc.
// Output report rate 15 ms. // Output report rate 15 ms. (5 or 10 or 15 supported).
0x0F, 0x00, 0x00, 0x00 0x0F, 0x00, 0x00, 0x00
// 5 ms. // 5 ms.
@@ -315,15 +330,17 @@ typedef struct _joycon_ctxt_t
u8 buf[0x100]; //FIXME: If heap is used, dumping breaks. u8 buf[0x100]; //FIXME: If heap is used, dumping breaks.
u8 uart; u8 uart;
u8 type; u8 type;
u8 sio_mode;
u8 state; u8 state;
u32 last_received_time; u32 last_received_time;
u32 last_status_req_time; u32 last_status_req_time;
u32 last_chrger_chk_time;
u8 mac[6]; u8 mac[6];
u8 pkt_id; u8 pkt_id;
u8 rumble_sent; u8 rumble_sent;
u8 charger_req;
u8 connected; u8 connected;
u8 detected; u8 detected;
u8 sio_mode;
} joycon_ctxt_t; } joycon_ctxt_t;
static joycon_ctxt_t jc_l = {0}; static joycon_ctxt_t jc_l = {0};
@@ -444,34 +461,32 @@ static void _jc_conn_check()
// Check if a Joy-Con was disconnected. // Check if a Joy-Con was disconnected.
if (!jc_l.detected) if (!jc_l.detected)
{ {
if (jc_l.connected)
_jc_power_supply(UART_C, false);
jc_l.pkt_id = 0; jc_l.pkt_id = 0;
jc_l.connected = false; jc_l.connected = false;
jc_l.rumble_sent = false; jc_l.rumble_sent = false;
jc_l.charger_req = false;
jc_gamepad.conn_l = false; jc_gamepad.conn_l = false;
jc_gamepad.batt_info_l = 0; jc_gamepad.batt_info_l = 0;
jc_gamepad.batt_chrg_l = 0;
jc_gamepad.bt_conn_l.type = 0; jc_gamepad.bt_conn_l.type = 0;
jc_gamepad.buttons &= ~JC_BTN_MASK_L; jc_gamepad.buttons &= ~JC_BTN_MASK_L;
} }
if (!jc_r.detected) if (!jc_r.detected)
{ {
if (jc_r.connected)
_jc_power_supply(UART_B, false);
jc_r.pkt_id = 0; jc_r.pkt_id = 0;
jc_r.connected = false; jc_r.connected = false;
jc_r.rumble_sent = false; jc_r.rumble_sent = false;
jc_r.charger_req = false;
jc_gamepad.conn_r = false; jc_gamepad.conn_r = false;
jc_gamepad.batt_info_r = 0; jc_gamepad.batt_info_r = 0;
jc_gamepad.batt_chrg_r = 0;
jc_gamepad.bt_conn_r.type = 0; jc_gamepad.bt_conn_r.type = 0;
jc_gamepad.buttons &= ~JC_BTN_MASK_R; jc_gamepad.buttons &= ~JC_BTN_MASK_R;
} }
@@ -586,21 +601,36 @@ static void _jc_send_hid_cmd(joycon_ctxt_t *jc, u8 subcmd, const u8 *data, u16 s
} }
} }
static void _jc_charging_decider(u8 batt, u8 uart) static void _jc_parse_input(joycon_ctxt_t *jc, const jc_hid_in_rpt_t *hid_pkt)
{ {
u32 system_batt_enough = max17050_get_cached_batt_volt() > 4000; u32 btn_tmp;
btn_tmp = hid_pkt->btn_right | hid_pkt->btn_shared << 8 | hid_pkt->btn_left << 16;
// Power supply control based on battery levels and charging. if (jc->type & JC_ID_L)
if ((batt >> 1) < JC_BATT_LOW) // Level without checking charging. {
_jc_power_supply(uart, true); jc_gamepad.buttons &= ~JC_BTN_MASK_L;
else if (batt > (system_batt_enough ? JC_BATT_FULL : JC_BATT_MID) << 1) // Addresses the charging bit. jc_gamepad.buttons |= (btn_tmp & JC_BTN_MASK_L);
_jc_power_supply(uart, false);
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;
}
} }
static void _jc_parse_wired_hid(joycon_ctxt_t *jc, const u8 *packet, int size) static void _jc_parse_wired_hid(joycon_ctxt_t *jc, const u8 *packet, int size)
{ {
u32 btn_tmp; const jc_hid_in_rpt_t *hid_pkt = (jc_hid_in_rpt_t *)packet;
jc_hid_in_rpt_t *hid_pkt = (jc_hid_in_rpt_t *)packet;
switch (hid_pkt->cmd) switch (hid_pkt->cmd)
{ {
@@ -613,35 +643,12 @@ static void _jc_parse_wired_hid(joycon_ctxt_t *jc, const u8 *packet, int size)
if (size < 12) if (size < 12)
break; break;
btn_tmp = hid_pkt->btn_right | hid_pkt->btn_shared << 8 | hid_pkt->btn_left << 16; _jc_parse_input(jc, hid_pkt);
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_l = jc_l.connected;
jc_gamepad.conn_r = jc_r.connected; jc_gamepad.conn_r = jc_r.connected;
if (hid_pkt->cmd == JC_HID_INPUT_RPT)
_jc_charging_decider(hid_pkt->batt_info, jc->uart);
break; break;
case JC_HID_SUBMCD_RPT: case JC_HID_SUBMCD_RPT:
if (hid_pkt->subcmd == JC_HID_SUBCMD_SPI_READ) if (hid_pkt->subcmd == JC_HID_SUBCMD_SPI_READ)
{ {
@@ -666,7 +673,13 @@ static void _jc_parse_wired_hid(joycon_ctxt_t *jc, const u8 *packet, int size)
bt_conn->ltk[16 - i] = pair_data->ltk[i - 1]; bt_conn->ltk[16 - i] = pair_data->ltk[i - 1];
} }
} }
else if (hid_pkt->subcmd == JC_HID_SUBCMD_CHARGE_SET)
jc->charger_req = false;
_jc_parse_input(jc, hid_pkt);
break; break;
default: default:
break; break;
} }
@@ -686,12 +699,15 @@ static void _jc_parse_wired_init(joycon_ctxt_t *jc, const u8 *data, int size)
jc->type = data[6]; jc->type = data[6];
jc->connected = true; jc->connected = true;
break; break;
case JC_WIRED_CMD_SET_BRATE: case JC_WIRED_CMD_SET_BRATE:
jc->state = JC_STATE_BRATE_CHANGED; jc->state = JC_STATE_BRATE_CHANGED;
break; break;
case JC_WIRED_CMD_HID_DISC: case JC_WIRED_CMD_HID_DISC:
jc->state = JC_STATE_BRATE_OK; jc->state = JC_STATE_BRATE_OK;
break; break;
case JC_WIRED_CMD_HID_CONN: case JC_WIRED_CMD_HID_CONN:
case JC_WIRED_CMD_SET_HIDRATE: case JC_WIRED_CMD_SET_HIDRATE:
// done. // done.
@@ -708,12 +724,15 @@ static void _jc_uart_pkt_parse(joycon_ctxt_t *jc, const jc_wired_hdr_t *pkt, int
case JC_WIRED_HID: case JC_WIRED_HID:
_jc_parse_wired_hid(jc, pkt->payload, size - sizeof(jc_wired_hdr_t)); _jc_parse_wired_hid(jc, pkt->payload, size - sizeof(jc_wired_hdr_t));
break; break;
case JC_WIRED_INIT_REPLY: case JC_WIRED_INIT_REPLY:
_jc_parse_wired_init(jc, pkt->data, size - sizeof(jc_uart_hdr_t) - 1); _jc_parse_wired_init(jc, pkt->data, size - sizeof(jc_uart_hdr_t) - 1);
break; break;
case JC_INIT_HANDSHAKE: case JC_INIT_HANDSHAKE:
jc->state = JC_STATE_HANDSHAKED; jc->state = JC_STATE_HANDSHAKED;
break; break;
default: default:
break; break;
} }
@@ -745,6 +764,7 @@ static void _jc_sio_parse_payload(joycon_ctxt_t *jc, u8 cmd, const u8 *payload,
jc_gamepad.conn_l = jc_l.connected; jc_gamepad.conn_l = jc_l.connected;
jc_gamepad.conn_r = jc_l.connected; jc_gamepad.conn_r = jc_l.connected;
break; break;
default: default:
break; break;
} }
@@ -761,14 +781,17 @@ static void _jc_sio_uart_pkt_parse(joycon_ctxt_t *jc, const jc_sio_in_rpt_t *pkt
case JC_SIO_CMD_INIT: case JC_SIO_CMD_INIT:
jc->connected = pkt->status == 0; jc->connected = pkt->status == 0;
break; break;
case JC_SIO_CMD_VER_RPT: case JC_SIO_CMD_VER_RPT:
if (jc->connected) if (jc->connected)
jc->connected = pkt->status == 0; jc->connected = pkt->status == 0;
break; break;
case JC_SIO_CMD_IAP_VER: case JC_SIO_CMD_IAP_VER:
case JC_SIO_CMD_STATUS: case JC_SIO_CMD_STATUS:
_jc_sio_parse_payload(jc, cmd, pkt->payload, size - sizeof(jc_sio_in_rpt_t)); _jc_sio_parse_payload(jc, cmd, pkt->payload, size - sizeof(jc_sio_in_rpt_t));
break; break;
case JC_SIO_CMD_UNK02: case JC_SIO_CMD_UNK02:
case JC_SIO_CMD_UNK20: case JC_SIO_CMD_UNK20:
case JC_SIO_CMD_UNK21: case JC_SIO_CMD_UNK21:
@@ -809,10 +832,98 @@ static void _jc_rcv_pkt(joycon_ctxt_t *jc)
} }
} }
static bool _jc_handle_charging(joycon_ctxt_t *jc)
{
if (jc->last_chrger_chk_time > get_tmr_ms())
return false;
jc->last_chrger_chk_time = get_tmr_ms() + 5000;
u8 old_mode, batt_now;
if (jc->uart == UART_B)
{
batt_now = jc_gamepad.batt_info_r;
old_mode = jc_gamepad.batt_chrg_r;
}
else
{
batt_now = jc_gamepad.batt_info_l;
old_mode = jc_gamepad.batt_chrg_l;
}
// Let battery level settle if init.
u8 new_mode = old_mode;
if (!old_mode)
{
new_mode = JC_CHRG_STATE_SUPL;
if ((batt_now >> 1) <= JC_BATT_LOW)
new_mode = JC_CHRG_STATE_SLOW;
goto set_mode;
}
// Resend if no reply.
if (jc->charger_req)
goto set_mode;
// Power supply control based on battery levels and charging.
switch (batt_now >> 1)
{
case JC_BATT_EMPTY:
case JC_BATT_CRIT:
case JC_BATT_LOW:
new_mode = JC_CHRG_STATE_SLOW;
break;
case JC_BATT_MID:
if (!(batt_now & 1))
new_mode = JC_CHRG_STATE_SUPL;
break;
case JC_BATT_FULL:
new_mode = JC_CHRG_STATE_OFF;
break;
}
// Check if already configured.
if (new_mode == old_mode)
return false;
set_mode:
if (jc->uart == UART_B)
jc_gamepad.batt_chrg_r = new_mode;
else
jc_gamepad.batt_chrg_l = new_mode;
switch (new_mode)
{
case JC_CHRG_STATE_OFF:
_jc_power_supply(jc->uart, false);
new_mode = JC_CHRG_CFG_SUPL0;
break;
case JC_CHRG_STATE_SUPL:
_jc_power_supply(jc->uart, true);
new_mode = JC_CHRG_CFG_SUPL0;
break;
case JC_CHRG_STATE_SLOW:
_jc_power_supply(jc->uart, true);
new_mode = JC_CHRG_CFG_100MA;
break;
}
_jc_send_hid_cmd(jc, JC_HID_SUBCMD_CHARGE_SET, (u8 *)&new_mode, sizeof(new_mode));
jc->charger_req = true;
jc->last_status_req_time = get_tmr_ms() + 15;
return true;
}
static bool _jc_send_init_rumble(joycon_ctxt_t *jc) static bool _jc_send_init_rumble(joycon_ctxt_t *jc)
{ {
// Send init rumble or request nx pad status report. // Send init rumble or request nx pad status report.
if ((jc_r.connected && !jc_r.rumble_sent) || (jc_l.connected && !jc_l.rumble_sent)) if ((jc_r.connected && !jc_r.rumble_sent) ||
(jc_l.connected && !jc_l.rumble_sent))
{ {
_jc_send_hid_cmd(jc, JC_HID_SUBCMD_SND_RUMBLE, NULL, 0); _jc_send_hid_cmd(jc, JC_HID_SUBCMD_SND_RUMBLE, NULL, 0);
@@ -821,13 +932,15 @@ static bool _jc_send_init_rumble(joycon_ctxt_t *jc)
if (jc_r.connected) if (jc_r.connected)
jc_r.rumble_sent = true; jc_r.rumble_sent = true;
jc->last_chrger_chk_time = get_tmr_ms() + 5000;
return 1; return 1;
} }
return 0; return 0;
} }
static void _jc_req_nx_pad_status(joycon_ctxt_t *jc) static void _jc_req_status(joycon_ctxt_t *jc)
{ {
if (!jc->detected) if (!jc->detected)
return; return;
@@ -837,11 +950,13 @@ static void _jc_req_nx_pad_status(joycon_ctxt_t *jc)
if (jc->last_status_req_time > get_tmr_ms() || !jc->connected) if (jc->last_status_req_time > get_tmr_ms() || !jc->connected)
return; return;
// Init/maintenance for Joy-Con.
if (is_nxpad) if (is_nxpad)
{ {
bool sent_rumble = _jc_send_init_rumble(jc); if (_jc_send_init_rumble(jc))
return;
if (sent_rumble) if (_jc_handle_charging(jc))
return; return;
} }
@@ -1019,18 +1134,23 @@ static void _jc_init_conn(joycon_ctxt_t *jc)
if (!jc->detected) if (!jc->detected)
return; return;
// Try to reinit if no input report.
// Actual connection timeout is 2000ms on official Joycon.
if (((u32)get_tmr_ms() - jc->last_received_time) > 1000) if (((u32)get_tmr_ms() - jc->last_received_time) > 1000)
{ {
_jc_power_supply(jc->uart, true); if (!jc->sio_mode)
_jc_power_supply(jc->uart, true);
// Mask out buttons and set connected to false. // Mask out buttons and set connected to false.
if (jc->uart == UART_B) if (jc->uart == UART_B)
{ {
jc_gamepad.batt_chrg_r = 0;
jc_gamepad.buttons &= ~JC_BTN_MASK_R; jc_gamepad.buttons &= ~JC_BTN_MASK_R;
jc_gamepad.conn_r = false; jc_gamepad.conn_r = false;
} }
else else
{ {
jc_gamepad.batt_chrg_l = 0;
jc_gamepad.buttons &= ~JC_BTN_MASK_L; jc_gamepad.buttons &= ~JC_BTN_MASK_L;
jc_gamepad.conn_l = false; jc_gamepad.conn_l = false;
} }
@@ -1040,6 +1160,7 @@ static void _jc_init_conn(joycon_ctxt_t *jc)
if (!jc->sio_mode) if (!jc->sio_mode)
{ {
jc_gamepad.buttons = 0;
jc->state = JC_STATE_START; jc->state = JC_STATE_START;
// Set TX and RTS inversion for Joycon. // Set TX and RTS inversion for Joycon.
@@ -1143,9 +1264,6 @@ static void _jc_init_conn(joycon_ctxt_t *jc)
out: out:
jc->last_received_time = get_tmr_ms(); jc->last_received_time = get_tmr_ms();
if (!jc->sio_mode && jc->connected && !(jc->type & JC_ID_HORI))
_jc_power_supply(jc->uart, false);
} }
} }
@@ -1158,9 +1276,6 @@ void jc_init_hw()
jc_gamepad.sio_mode = jc_l.sio_mode; jc_gamepad.sio_mode = jc_l.sio_mode;
#if !defined(DEBUG_UART_PORT) || !(DEBUG_UART_PORT) #if !defined(DEBUG_UART_PORT) || !(DEBUG_UART_PORT)
_jc_power_supply(UART_C, true);
_jc_power_supply(UART_B, true);
// Sio Initialization. // Sio Initialization.
if (jc_gamepad.sio_mode) if (jc_gamepad.sio_mode)
{ {
@@ -1190,6 +1305,11 @@ void jc_init_hw()
PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN1) = PINMUX_IO_HV | PINMUX_LPDR | 1; PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN1) = PINMUX_IO_HV | PINMUX_LPDR | 1;
gpio_direction_output(GPIO_PORT_CC, GPIO_PIN_5, GPIO_LOW); gpio_direction_output(GPIO_PORT_CC, GPIO_PIN_5, GPIO_LOW);
} }
else
{
_jc_power_supply(UART_C, true);
_jc_power_supply(UART_B, true);
}
#if 0 // Already set by hw init. #if 0 // Already set by hw init.
// Set Joy-Con IsAttached pinmux. Shared with UARTB/UARTC TX. // Set Joy-Con IsAttached pinmux. Shared with UARTB/UARTC TX.
@@ -1220,12 +1340,12 @@ void jc_deinit()
if (!jc_init_done) if (!jc_init_done)
return; return;
// Disable power.
_jc_power_supply(UART_B, false);
_jc_power_supply(UART_C, false);
if (!jc_gamepad.sio_mode) if (!jc_gamepad.sio_mode)
{ {
// Disable power.
_jc_power_supply(UART_B, false);
_jc_power_supply(UART_C, false);
// Send sleep command. // Send sleep command.
u8 data = HCI_STATE_SLEEP; u8 data = HCI_STATE_SLEEP;
if (jc_r.connected && !(jc_r.type & JC_ID_HORI)) if (jc_r.connected && !(jc_r.type & JC_ID_HORI))
@@ -1264,8 +1384,8 @@ jc_gamepad_rpt_t *joycon_poll()
_jc_init_conn(&jc_r); _jc_init_conn(&jc_r);
_jc_init_conn(&jc_l); _jc_init_conn(&jc_l);
_jc_req_nx_pad_status(&jc_r); _jc_req_status(&jc_r);
_jc_req_nx_pad_status(&jc_l); _jc_req_status(&jc_l);
_jc_rcv_pkt(&jc_r); _jc_rcv_pkt(&jc_r);
_jc_rcv_pkt(&jc_l); _jc_rcv_pkt(&jc_l);

View File

@@ -1,7 +1,7 @@
/* /*
* Ambient light sensor driver for Nintendo Switch's Rohm BH1730 * Ambient light sensor driver for Nintendo Switch's Rohm BH1730
* *
* Copyright (c) 2018 CTCaer * Copyright (c) 2018-2025 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -86,6 +86,8 @@ typedef struct _jc_gamepad_rpt_t
bool sio_mode; bool sio_mode;
u8 batt_info_l; // Also Sio Connected status. u8 batt_info_l; // Also Sio Connected status.
u8 batt_info_r; // Also Sio IRQ. u8 batt_info_r; // Also Sio IRQ.
u8 batt_chrg_l;
u8 batt_chrg_r;
jc_bt_conn_t bt_conn_l; jc_bt_conn_t bt_conn_l;
jc_bt_conn_t bt_conn_r; jc_bt_conn_t bt_conn_r;
} jc_gamepad_rpt_t; } jc_gamepad_rpt_t;