From 74439c06d7a06dbf75e512b47a735dc45a41c148 Mon Sep 17 00:00:00 2001 From: ykpmusicstudio Date: Sat, 6 Jun 2026 21:25:44 +0200 Subject: [PATCH 1/4] fix(gip) remove delayed auth, fix sequence number, add full debug. --- bus/bus.h | 1 + bus/protocol.c | 59 ++++++++++++++++++++++++++++++++++++++++-------- driver/gamepad.c | 52 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 96 insertions(+), 16 deletions(-) diff --git a/bus/bus.h b/bus/bus.h index 95c483f..1690794 100644 --- a/bus/bus.h +++ b/bus/bus.h @@ -56,6 +56,7 @@ struct gip_adapter { spinlock_t send_lock; u8 data_sequence; + u8 auth_sequence; u8 audio_sequence; }; diff --git a/bus/protocol.c b/bus/protocol.c index 9152be5..09097de 100644 --- a/bus/protocol.c +++ b/bus/protocol.c @@ -323,6 +323,17 @@ static int gip_decode_header(struct gip_header *hdr, u8 *data, int len) return hdr_len; } +static int gip_has_capability(struct gip_info_element *caps, u8 command) +{ + for(int i=0; icount; i++) { + if (caps->data[i] == command) { + return 0; + } + } + return -ENOTSUPP; +} + + static int gip_init_chunk_buffer(struct gip_client *client, struct gip_header *hdr, struct gip_chunk_buffer **buf, @@ -389,6 +400,15 @@ static int gip_send_pkt_simple(struct gip_client *client, /* set actual length */ buf.length = hdr_len + hdr->packet_length; + gip_dbg(client, "%s: seq=0x%02x, cmd=0x%02x, len=0x%04x flags=[%s %s %s] pkt=[%*ph]\n", + __func__, + hdr->sequence, + hdr->command, hdr->packet_length, + hdr->options & GIP_OPT_CHUNK_START? "Ini":"...", + hdr->options & GIP_OPT_ACKNOWLEDGE? "Ack":"...", + hdr->options & GIP_OPT_INTERNAL? "Sys":"...", + buf.length,buf.data); + /* debug message sent */ // gip_dbg(client, "%s: cmd=0x%02x len=0x%04x seq=0x%02x offset=0x%04x\n", // __func__, hdr->command, buf.length, hdr->sequence, @@ -455,8 +475,8 @@ static int gip_acknowledge_pkt(struct gip_client *client, if ((ack->options & GIP_OPT_CHUNK) && buf) pkt.remaining = cpu_to_le16(buf->length - len); - // gip_dbg(client, "%s: ACME(host) command=0x%02x, length=0x%04x\n", - // __func__, pkt.command, len); + gip_dbg(client, "%s: seq=0x%02x, cmd=0x%02x, len=0x%04x ACME(host)\n", + __func__, hdr.sequence, pkt.command, len); return gip_send_pkt(client, &hdr, &pkt); } @@ -495,6 +515,12 @@ int gip_send_authenticate(struct gip_client *client, void *pkt, u32 len, hdr.options = client->id | GIP_OPT_INTERNAL; hdr.packet_length = len; + /* sequence number is always greater than zero */ + if (!++client->adapter->auth_sequence) + ++client->adapter->auth_sequence; + + hdr.sequence = client->adapter->auth_sequence; + if (acknowledge) hdr.options |= GIP_OPT_ACKNOWLEDGE; @@ -611,6 +637,11 @@ EXPORT_SYMBOL_GPL(gip_set_led_mode); int gip_send_get_serial_number(struct gip_client *client) { + int ierr = gip_has_capability(client->capabilities_out, GIP_CMD_EXTENDED); + if (ierr) { + gip_warn(client,"%s: no GIP_OPT_INTERNAL capability, skipping message.",__func__); + return ierr; + } struct gip_header hdr = { .command = GIP_CMD_EXTENDED, .options = client->id | GIP_OPT_INTERNAL, @@ -1118,11 +1149,15 @@ static int gip_handle_pkt_acknowledge(struct gip_client *client, if (len != sizeof(*pkt)) return -EINVAL; - if (!buf) + if (!buf) { + gip_dbg(client, "%s: cmd=0x%02x, len=0x%04x ACME(dev)\n", + __func__, pkt->command, le16_to_cpu(pkt->length)); + return 0; + } - gip_dbg(client, "%s: ACME(dev) cmd=0x%02x/0x%02x, len=0x%04x/0x%04x\n", - __func__, pkt->command, buf->header.command, + gip_dbg(client, "%s: seq=0x%02x, cmd=0x%02x, len=0x%04x/0x%04x ACME(dev)\n", + __func__, buf->header.sequence, pkt->command, le16_to_cpu(pkt->length), buf->length); /* acknowledgment for different command */ @@ -1609,11 +1644,8 @@ static int gip_process_pkt_chunked(struct gip_client *client, int err; u32 len; - gip_dbg(client, "%s: flags=[%s %s %s], offset=0x%04x, length=0x%04x\n", + gip_dbg(client, "%s: offset=0x%04x, length=0x%04x\n", __func__, - hdr->options & GIP_OPT_CHUNK_START? "Ini":"...", - hdr->options & GIP_OPT_ACKNOWLEDGE? "Ack":"...", - hdr->options & GIP_OPT_INTERNAL? "Sys":"...", hdr->chunk_offset, hdr->packet_length); if (!buf) { @@ -1701,6 +1733,15 @@ int gip_process_buffer(struct gip_adapter *adap, void *data, int len) if (IS_ERR(client)) return PTR_ERR(client); + gip_dbg(client, "%s: seq=0x%02x, cmd=0x%02x, len=0x%04x flags=[%s %s %s] data=[%*ph]\n", + __func__, + hdr.sequence, + hdr.command, hdr.packet_length, + hdr.options & GIP_OPT_CHUNK_START? "Ini":"...", + hdr.options & GIP_OPT_ACKNOWLEDGE? "Ack":"...", + hdr.options & GIP_OPT_INTERNAL? "Sys":"...", + len,data); + err = gip_process_pkt(client, &hdr, data + hdr_len); if (err) return err; diff --git a/driver/gamepad.c b/driver/gamepad.c index dec6856..8c31bc2 100644 --- a/driver/gamepad.c +++ b/driver/gamepad.c @@ -78,6 +78,10 @@ enum gip_gamepad_motor { GIP_GP_MOTOR_LT = BIT(3), }; +enum gip_init_state { + GIP_GP_AUTHENTICATING = 0x10, + GIP_GP_READY = 0xFF, +}; /* * Remember, xpad keeps the 4 bytes. * Paddles are at [18] in xpad, so, [14] here. @@ -141,11 +145,15 @@ struct gip_gamepad { struct gip_led led; struct gip_input input; + //u8 state; + bool supports_share; bool supports_dli; PaddleCapability paddle_support; struct gip_gamepad_rumble rumble; + + // struct work_struct state_work; }; static void gip_gamepad_send_rumble(struct timer_list *timer) @@ -329,6 +337,14 @@ static int gip_gamepad_op_battery(struct gip_client *client, gip_report_battery(&gamepad->battery, type, level); + // handle pdp gamepad that need delayed authentication + /* + if (gamepad->state == GIP_GP_AUTHENTICATING) + { + gamepad->state = GIP_GP_READY; + schedule_work(&gamepad->state_work); + }*/ + return 0; } @@ -352,9 +368,26 @@ static int gip_gamepad_op_guide_button(struct gip_client *client, bool down) static int gip_gamepad_op_authenticated(struct gip_client *client) { + struct gip_gamepad *gamepad = dev_get_drvdata(&client->dev); + int err = gip_gamepad_init_input(gamepad); + if (err) + return err; + return 0; } +/* +static void gip_gamepad_start_handshake(struct work_struct *work) +{ + struct gip_gamepad *gamepad = container_of(work, struct gip_gamepad, state_work); + int err = gip_auth_start_handshake(&gamepad->auth, gamepad->client); + if (err) { + dev_dbg(&gamepad->client->dev, "%s: gamepad handshake failed err=%d.\n", __func__, err); + return; + } +} +*/ + static int gip_gamepad_op_firmware(struct gip_client *client, void *data, u32 len) { @@ -485,6 +518,10 @@ static int gip_gamepad_probe(struct gip_client *client) if (!gamepad) return -ENOMEM; + + //INIT_WORK(&gamepad->state_work, gip_gamepad_start_handshake); + //gamepad->state = GIP_GP_READY;//AUTHENTICATING; + gamepad->client = client; err = gip_set_power_mode(client, GIP_PWR_ON); @@ -512,18 +549,18 @@ static int gip_gamepad_probe(struct gip_client *client) if (err) return err; - err = gip_auth_start_handshake(&gamepad->auth, client); - if (err) - return err; - + dev_dbg(&gamepad->client->dev, "%s: before gip_init_input.\n", __func__); err = gip_init_input(&gamepad->input, client, GIP_GP_NAME); if (err) return err; - err = gip_gamepad_init_input(gamepad); - if (err) + dev_dbg(&gamepad->client->dev, "%s: before handshake.\n", __func__); + err = gip_auth_start_handshake(&gamepad->auth, gamepad->client); + if (err) { + dev_dbg(&gamepad->client->dev, "%s: gamepad handshake failed err=%d.\n", __func__, err); return err; - + } + dev_set_drvdata(&client->dev, gamepad); return 0; @@ -532,6 +569,7 @@ static int gip_gamepad_probe(struct gip_client *client) static void gip_gamepad_remove(struct gip_client *client) { struct gip_gamepad *gamepad = dev_get_drvdata(&client->dev); + //cancel_work_sync(&gamepad->state_work); #if LINUX_VERSION_CODE < KERNEL_VERSION(6,15,0) del_timer_sync(&gamepad->rumble.timer); From 6b15f59f731eb2dbabba20c6fd361d00b4192b6a Mon Sep 17 00:00:00 2001 From: ykpmusicstudio Date: Sun, 7 Jun 2026 07:34:43 +0200 Subject: [PATCH 2/4] fix(gamepad): init input and move rumble init --- driver/gamepad.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/driver/gamepad.c b/driver/gamepad.c index 8c31bc2..432919f 100644 --- a/driver/gamepad.c +++ b/driver/gamepad.c @@ -304,29 +304,30 @@ static int gip_gamepad_init_input(struct gip_gamepad *gamepad) input_set_abs_params(dev, ABS_HAT0X, -1, 1, 0, 0); input_set_abs_params(dev, ABS_HAT0Y, -1, 1, 0, 0); - err = gip_gamepad_init_rumble(gamepad); +/* err = gip_gamepad_init_rumble(gamepad); if (err) { dev_err(&gamepad->client->dev, "%s: init rumble failed: %d\n", __func__, err); goto err_delete_timer; } - +*/ err = input_register_device(dev); if (err) { dev_err(&gamepad->client->dev, "%s: register failed: %d\n", __func__, err); - goto err_delete_timer; +/* goto err_delete_timer;*/ + return err; } return 0; - +/* err_delete_timer: #if LINUX_VERSION_CODE < KERNEL_VERSION(6,15,0) del_timer_sync(&gamepad->rumble.timer); #else timer_delete_sync(&gamepad->rumble.timer); #endif - return err; + return err;*/ } static int gip_gamepad_op_battery(struct gip_client *client, @@ -369,10 +370,22 @@ static int gip_gamepad_op_guide_button(struct gip_client *client, bool down) static int gip_gamepad_op_authenticated(struct gip_client *client) { struct gip_gamepad *gamepad = dev_get_drvdata(&client->dev); + /* int err = gip_gamepad_init_input(gamepad); if (err) return err; - + */ + int err = gip_gamepad_init_rumble(gamepad); + if (err) { + dev_err(&gamepad->client->dev, "%s: init rumble failed: %d\n", + __func__, err); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6,15,0) + del_timer_sync(&gamepad->rumble.timer); +#else + timer_delete_sync(&gamepad->rumble.timer); +#endif + return err; + } return 0; } @@ -560,6 +573,10 @@ static int gip_gamepad_probe(struct gip_client *client) dev_dbg(&gamepad->client->dev, "%s: gamepad handshake failed err=%d.\n", __func__, err); return err; } + + err = gip_gamepad_init_input(gamepad); + if (err) + return err; dev_set_drvdata(&client->dev, gamepad); From efdce09fc579cd075e13cc8ba32272beee622037 Mon Sep 17 00:00:00 2001 From: ykpmusicstudio Date: Fri, 10 Jul 2026 13:20:54 +0200 Subject: [PATCH 3/4] reintroduce delayed handshake after CMD_STATUS --- bus/protocol.c | 1 + driver/gamepad.c | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/bus/protocol.c b/bus/protocol.c index 09097de..3b97be0 100644 --- a/bus/protocol.c +++ b/bus/protocol.c @@ -1706,6 +1706,7 @@ static int gip_process_pkt(struct gip_client *client, hdr->chunk_offset = 0; } + /* some gamepads send empty packets with chunk flag : dispatch them */ if (hdr->options & GIP_OPT_CHUNK) return gip_process_pkt_chunked(client, hdr, data); diff --git a/driver/gamepad.c b/driver/gamepad.c index 432919f..47e1f1d 100644 --- a/driver/gamepad.c +++ b/driver/gamepad.c @@ -27,6 +27,7 @@ #define GIP_GP_RUMBLE_DELAY msecs_to_jiffies(10) #define GIP_GP_RUMBLE_MAX 100 +#define GIP_GP_AUTH_DELAY msecs_to_jiffies(50) /* button offset from end of packet */ #define GIP_GP_BTN_SHARE_OFFSET 18 @@ -145,7 +146,7 @@ struct gip_gamepad { struct gip_led led; struct gip_input input; - //u8 state; + u8 state; bool supports_share; bool supports_dli; @@ -153,7 +154,7 @@ struct gip_gamepad { struct gip_gamepad_rumble rumble; - // struct work_struct state_work; + struct delayed_work state_work; }; static void gip_gamepad_send_rumble(struct timer_list *timer) @@ -339,13 +340,13 @@ static int gip_gamepad_op_battery(struct gip_client *client, gip_report_battery(&gamepad->battery, type, level); // handle pdp gamepad that need delayed authentication - /* if (gamepad->state == GIP_GP_AUTHENTICATING) { + dev_dbg(&gamepad->client->dev, "%s: before handshake (delayed).\n", __func__); gamepad->state = GIP_GP_READY; - schedule_work(&gamepad->state_work); - }*/ - + schedule_delayed_work(&gamepad->state_work,GIP_GP_AUTH_DELAY ); + } + return 0; } @@ -389,17 +390,16 @@ static int gip_gamepad_op_authenticated(struct gip_client *client) return 0; } -/* static void gip_gamepad_start_handshake(struct work_struct *work) { - struct gip_gamepad *gamepad = container_of(work, struct gip_gamepad, state_work); + struct gip_gamepad *gamepad = container_of(to_delayed_work(work), + struct gip_gamepad, state_work); int err = gip_auth_start_handshake(&gamepad->auth, gamepad->client); if (err) { dev_dbg(&gamepad->client->dev, "%s: gamepad handshake failed err=%d.\n", __func__, err); return; } } -*/ static int gip_gamepad_op_firmware(struct gip_client *client, void *data, u32 len) @@ -532,8 +532,8 @@ static int gip_gamepad_probe(struct gip_client *client) return -ENOMEM; - //INIT_WORK(&gamepad->state_work, gip_gamepad_start_handshake); - //gamepad->state = GIP_GP_READY;//AUTHENTICATING; + INIT_DELAYED_WORK(&gamepad->state_work, gip_gamepad_start_handshake); + gamepad->state = GIP_GP_AUTHENTICATING; gamepad->client = client; @@ -567,12 +567,12 @@ static int gip_gamepad_probe(struct gip_client *client) if (err) return err; - dev_dbg(&gamepad->client->dev, "%s: before handshake.\n", __func__); +/* dev_dbg(&gamepad->client->dev, "%s: before handshake.\n", __func__); err = gip_auth_start_handshake(&gamepad->auth, gamepad->client); if (err) { dev_dbg(&gamepad->client->dev, "%s: gamepad handshake failed err=%d.\n", __func__, err); return err; - } + }*/ err = gip_gamepad_init_input(gamepad); if (err) @@ -586,7 +586,7 @@ static int gip_gamepad_probe(struct gip_client *client) static void gip_gamepad_remove(struct gip_client *client) { struct gip_gamepad *gamepad = dev_get_drvdata(&client->dev); - //cancel_work_sync(&gamepad->state_work); + cancel_delayed_work_sync(&gamepad->state_work); #if LINUX_VERSION_CODE < KERNEL_VERSION(6,15,0) del_timer_sync(&gamepad->rumble.timer); From 6c5dc2b156845a3f64ef9e80b56247f7fd516611 Mon Sep 17 00:00:00 2001 From: ykpmusicstudio Date: Wed, 29 Jul 2026 23:56:18 +0200 Subject: [PATCH 4/4] fix(Auth): delay all auth messages by 50ms --- driver/gamepad.c | 58 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/driver/gamepad.c b/driver/gamepad.c index 47e1f1d..db8b293 100644 --- a/driver/gamepad.c +++ b/driver/gamepad.c @@ -80,7 +80,8 @@ enum gip_gamepad_motor { }; enum gip_init_state { - GIP_GP_AUTHENTICATING = 0x10, + GIP_GP_HANDSHAKE = 0x10, + GIP_GP_AUTHENTICATING = 0x20, GIP_GP_READY = 0xFF, }; /* @@ -147,6 +148,8 @@ struct gip_gamepad { struct gip_input input; u8 state; + void *auth_pkt; + u32 auth_pkt_sz; bool supports_share; bool supports_dli; @@ -340,11 +343,10 @@ static int gip_gamepad_op_battery(struct gip_client *client, gip_report_battery(&gamepad->battery, type, level); // handle pdp gamepad that need delayed authentication - if (gamepad->state == GIP_GP_AUTHENTICATING) + if (gamepad->state == GIP_GP_HANDSHAKE) { dev_dbg(&gamepad->client->dev, "%s: before handshake (delayed).\n", __func__); - gamepad->state = GIP_GP_READY; - schedule_delayed_work(&gamepad->state_work,GIP_GP_AUTH_DELAY ); + schedule_delayed_work(&gamepad->state_work, GIP_GP_AUTH_DELAY); } return 0; @@ -355,7 +357,15 @@ static int gip_gamepad_op_authenticate(struct gip_client *client, { struct gip_gamepad *gamepad = dev_get_drvdata(&client->dev); - return gip_auth_process_pkt(&gamepad->auth, data, len); + gamepad->auth_pkt = kzalloc(len, GFP_ATOMIC); + if (!gamepad->auth_pkt) + return -ENOMEM; + + memcpy(gamepad->auth_pkt, data, len); + gamepad->auth_pkt_sz = len; + schedule_delayed_work(&gamepad->state_work, GIP_GP_AUTH_DELAY); + + return 0; } static int gip_gamepad_op_guide_button(struct gip_client *client, bool down) @@ -376,6 +386,7 @@ static int gip_gamepad_op_authenticated(struct gip_client *client) if (err) return err; */ + gamepad->state = GIP_GP_READY; int err = gip_gamepad_init_rumble(gamepad); if (err) { dev_err(&gamepad->client->dev, "%s: init rumble failed: %d\n", @@ -394,11 +405,36 @@ static void gip_gamepad_start_handshake(struct work_struct *work) { struct gip_gamepad *gamepad = container_of(to_delayed_work(work), struct gip_gamepad, state_work); - int err = gip_auth_start_handshake(&gamepad->auth, gamepad->client); - if (err) { - dev_dbg(&gamepad->client->dev, "%s: gamepad handshake failed err=%d.\n", __func__, err); - return; - } + if(gamepad->state == GIP_GP_HANDSHAKE) + { + gamepad->state = GIP_GP_AUTHENTICATING; + int err = gip_auth_start_handshake(&gamepad->auth, gamepad->client); + if (err) { + dev_err(&gamepad->client->dev, "%s: gamepad handshake failed err=%d.\n", __func__, err); + return; + } + } + else if(gamepad->state == GIP_GP_AUTHENTICATING) + { + if (!gamepad->auth_pkt) + { + dev_err(&gamepad->client->dev, "%s: gamepad delayed auth msg has no buffer allocated.\n", + __func__); + return; + } + + int err = gip_auth_process_pkt(&gamepad->auth, gamepad->auth_pkt, gamepad->auth_pkt_sz); + if (err) + { + dev_err(&gamepad->client->dev, "%s: gamepad auth command failed err=%d.\n", __func__, err); + } + + kfree(gamepad->auth_pkt); + gamepad->auth_pkt = NULL; + gamepad->auth_pkt_sz = 0; + + return; + } } static int gip_gamepad_op_firmware(struct gip_client *client, void *data, @@ -533,7 +569,7 @@ static int gip_gamepad_probe(struct gip_client *client) INIT_DELAYED_WORK(&gamepad->state_work, gip_gamepad_start_handshake); - gamepad->state = GIP_GP_AUTHENTICATING; + gamepad->state = GIP_GP_HANDSHAKE; gamepad->client = client;