Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ A collection of Linux drivers of various components for Gigabyte devices.
| Gigabyte Aorus 15P (RTX 30 series) | 1044:7A3B |
| Gigabyte Aorus 15G | 1044:7A3C |
| Gigabyte Aorus 17G YC (RTX 30 series) | 1044:7A3C |
| Gigabyte Aero 17 XE5 | 1044:7A40 |



Expand Down
166 changes: 164 additions & 2 deletions driver/gigabytekbd_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,135 @@ MODULE_LICENSE("GPL v2");
#define HIDRAW_FN_F10 0x04000081
#define HIDRAW_FN_F11 0x04000082
#define HIDRAW_FN_F12 0x04000083
#define HIDRAW_FN_F12_AERO17XE5 0x04000088

#define HIDRAW_FN_SPACE_KDB_LIGHT_OFF 0x04010000
#define HIDRAW_FN_SPACE_KDB_LIGHT_HALF 0x04011900
#define HIDRAW_FN_SPACE_KDB_LIGHT_FULL 0x04013200

#define make_u32(a, b, c, d) a << 24 | b << 16 | c << 8 | d

#define MOD_CODE_LEFT_CTRL 0x01
#define MOD_CODE_LEFT_SUPER 0x08

#define KEY_CODE_P 0x13
#define KEY_CODE_XF86_TOUCHPAD_OFF 0x72
#define KEY_CODE_MYSTERIOUS 0x73

struct gigabyte_kbd_aero17xe5_drvdata {
u8 fn_f10_seq;
bool fn_f10_ctrl_down;
};

static void gigabyte_kbd_util_remove_first_byte(u8 *rd, int size)
{
for (int i = 1; i < size; i++) {
rd[i - 1] = rd[i];
}
rd[size - 1] = 0x0;
}

static void gigabyte_kbd_util_remove_byte_occurrences(u8 *rd, u8 byte, int size)
{
for (int i = 0; i < size; i++) {
while (rd[i] == byte) {
for (int j = i + 1; j < size; j++) {
rd[j - 1] = rd[j];
}
rd[size - 1] = 0x00;
}
}
}

static int gigabyte_kbd_raw_event_aero17xe5(struct hid_device *hdev, struct hid_report *report, u8 *rd, int size)
{
if (report->id == 0 && report->type == HID_INPUT_REPORT && size == 36) {
struct gigabyte_kbd_aero17xe5_drvdata *data = hid_get_drvdata(hdev);
if (!(rd[0] & (MOD_CODE_LEFT_CTRL | MOD_CODE_LEFT_SUPER)) && rd[2] != KEY_CODE_XF86_TOUCHPAD_OFF) {
data->fn_f10_seq = 0;
data->fn_f10_ctrl_down = false;
}
// Pressing Fn.
else if (data->fn_f10_seq == 0 && rd[2] == KEY_CODE_XF86_TOUCHPAD_OFF) {
gigabyte_kbd_util_remove_first_byte(&rd[2], 34);
data->fn_f10_seq = 1;
}
// Holding Fn.
else if (data->fn_f10_seq == 1 && !(rd[0] & MOD_CODE_LEFT_SUPER) && rd[2] == KEY_CODE_XF86_TOUCHPAD_OFF) {
gigabyte_kbd_util_remove_first_byte(&rd[2], 34);
}
// Holding Fn and pressing F10 (first event) or pressing Super.
else if (data->fn_f10_seq == 1 && rd[0] & MOD_CODE_LEFT_SUPER && rd[2] == KEY_CODE_XF86_TOUCHPAD_OFF) {
rd[0] &= ~MOD_CODE_LEFT_SUPER;
gigabyte_kbd_util_remove_first_byte(&rd[2], 34);
data->fn_f10_seq = 2;
}
// Holding Fn and releasing Super.
else if (data->fn_f10_seq == 2 && !(rd[0] & MOD_CODE_LEFT_SUPER) && rd[2] == KEY_CODE_XF86_TOUCHPAD_OFF) {
gigabyte_kbd_util_remove_first_byte(&rd[2], 34);
data->fn_f10_seq = 1;
}
// Holding Fn+Super.
else if (data->fn_f10_seq == 2 && rd[0] & MOD_CODE_LEFT_SUPER && rd[2] == KEY_CODE_XF86_TOUCHPAD_OFF && !memchr(&rd[3], KEY_CODE_MYSTERIOUS, 33)) {
// This check is needed to passthrough Fn+F5 which generates Super+p sequence which is used for changing video setup (for Windows it works in the same way though).
if (!memchr(&rd[3], KEY_CODE_P, 33)) {
rd[0] &= ~MOD_CODE_LEFT_SUPER;
}
if (data->fn_f10_ctrl_down) {
rd[0] &= ~MOD_CODE_LEFT_CTRL;
}
gigabyte_kbd_util_remove_first_byte(&rd[2], 34);
}
// Holding Fn and pressing F10 (second event).
else if (data->fn_f10_seq == 2 && rd[0] & (MOD_CODE_LEFT_SUPER | MOD_CODE_LEFT_CTRL) && rd[2] == KEY_CODE_XF86_TOUCHPAD_OFF && memchr(&rd[3], KEY_CODE_MYSTERIOUS, 33)) {
rd[0] &= ~MOD_CODE_LEFT_SUPER;
rd[0] &= ~MOD_CODE_LEFT_CTRL;
gigabyte_kbd_util_remove_first_byte(&rd[2], 34);
gigabyte_kbd_util_remove_byte_occurrences(&rd[2], KEY_CODE_MYSTERIOUS, 34);
data->fn_f10_seq = 3;
data->fn_f10_ctrl_down = true;
}
// Holding Fn+F10.
else if (data->fn_f10_seq == 3 && rd[0] & (MOD_CODE_LEFT_SUPER | MOD_CODE_LEFT_CTRL) && (rd[2] == KEY_CODE_XF86_TOUCHPAD_OFF && memchr(&rd[3], KEY_CODE_MYSTERIOUS, 33))) {
rd[0] &= ~MOD_CODE_LEFT_SUPER;
rd[0] &= ~MOD_CODE_LEFT_CTRL;
gigabyte_kbd_util_remove_first_byte(&rd[2], 34);
gigabyte_kbd_util_remove_byte_occurrences(&rd[2], KEY_CODE_MYSTERIOUS, 34);
}
// Releasing F10 or Fn.
else if (data->fn_f10_seq == 3 && rd[0] & (MOD_CODE_LEFT_SUPER | MOD_CODE_LEFT_CTRL) && ((rd[2] == KEY_CODE_XF86_TOUCHPAD_OFF && !memchr(&rd[3], KEY_CODE_MYSTERIOUS, 33)) || memchr(&rd[2], KEY_CODE_MYSTERIOUS, 34))) {
rd[0] &= ~MOD_CODE_LEFT_SUPER;
rd[0] &= ~MOD_CODE_LEFT_CTRL;
if (rd[2] == KEY_CODE_XF86_TOUCHPAD_OFF) {
gigabyte_kbd_util_remove_first_byte(&rd[2], 34);
}
else {
gigabyte_kbd_util_remove_byte_occurrences(&rd[2], KEY_CODE_MYSTERIOUS, 34);
}
data->fn_f10_seq = 4;
}
// Holding Fn and pressing F10 (again).
else if (data->fn_f10_seq == 4 && rd[0] & (MOD_CODE_LEFT_SUPER | MOD_CODE_LEFT_CTRL) && rd[2] == KEY_CODE_XF86_TOUCHPAD_OFF) {
rd[0] &= ~MOD_CODE_LEFT_SUPER;
rd[0] &= ~MOD_CODE_LEFT_CTRL;
gigabyte_kbd_util_remove_first_byte(&rd[2], 34);
data->fn_f10_seq = 2;
}
// Releasing Fn.
else if (data->fn_f10_seq == 4 && rd[0] & (MOD_CODE_LEFT_SUPER | MOD_CODE_LEFT_CTRL) && rd[2] != KEY_CODE_XF86_TOUCHPAD_OFF && !memchr(&rd[2], KEY_CODE_MYSTERIOUS, 34)) {
rd[0] &= ~MOD_CODE_LEFT_SUPER;
rd[0] &= ~MOD_CODE_LEFT_CTRL;
data->fn_f10_seq = 5;
}
// This will remove Xf86TouchpadOff then Fn has been pressed after another button.
else {
gigabyte_kbd_util_remove_byte_occurrences(&rd[3], KEY_CODE_XF86_TOUCHPAD_OFF, 33);
}
}

return 0;
}

static int gigabyte_kbd_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *rd, int size)
{
if (report->id == 4 && size == 4)
Expand All @@ -49,27 +175,63 @@ static int gigabyte_kbd_raw_event(struct hid_device *hdev, struct hid_report *re
break;
}
}
if (hdev->product == USB_DEVICE_ID_GIGABYTE_AERO17XE5) {
return gigabyte_kbd_raw_event_aero17xe5(hdev, report, rd, size);
}
return 0;
}

static int gigabyte_kbd_probe_aero17xe5(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret = 0;
struct gigabyte_kbd_aero17xe5_drvdata *data;

data = devm_kzalloc(&hdev->dev, sizeof(struct gigabyte_kbd_aero17xe5_drvdata), GFP_KERNEL);
if (data == NULL) {
hid_err(hdev, "Could not allocate memory for driver data\n");
ret = -ENOMEM;
return ret;
}
data->fn_f10_seq = 0;
data->fn_f10_ctrl_down = false;
hid_set_drvdata(hdev, data);

return ret;
}

static int gigabyte_kbd_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
// printk("Gigabyte kbd driver loaded.");
int ret;
hdev->quirks |= HID_QUIRK_INPUT_PER_APP;

ret = hid_parse(hdev);
if (ret)
if (ret) {
hid_err(hdev, "hid_parse failed\n");
return ret;
}

ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
hid_err(hdev, "hid_hw_start failed\n");
return ret;
}

if (hdev->product == USB_DEVICE_ID_GIGABYTE_AERO17XE5) {
ret = gigabyte_kbd_probe_aero17xe5(hdev, id);
if (ret)
return ret;
}

return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
return ret;
}

static const struct hid_device_id gigabyte_kbd_devices[] = {
{HID_USB_DEVICE(USB_VENDOR_ID_GIGABYTE_AERO15XV8, USB_DEVICE_ID_GIGABYTE_AERO15XV8)},
{HID_USB_DEVICE(USB_VENDOR_ID_GIGABYTE_AERO15SA, USB_DEVICE_ID_GIGABYTE_AERO15SA)},
{HID_USB_DEVICE(USB_VENDOR_ID_GIGABYTE_AORUS15P, USB_DEVICE_ID_GIGABYTE_AORUS15P)},
{HID_USB_DEVICE(USB_VENDOR_ID_GIGABYTE_AORUS15G, USB_DEVICE_ID_GIGABYTE_AORUS15G)},
{HID_USB_DEVICE(USB_VENDOR_ID_GIGABYTE_AERO17XE5, USB_DEVICE_ID_GIGABYTE_AERO17XE5)},
{}
};
MODULE_DEVICE_TABLE(hid, gigabyte_kbd_devices);
Expand Down
3 changes: 3 additions & 0 deletions driver/gigabytekbd_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@
#define USB_VENDOR_ID_GIGABYTE_AORUS15G 0x1044
#define USB_DEVICE_ID_GIGABYTE_AORUS15G 0x7A3C

#define USB_VENDOR_ID_GIGABYTE_AERO17XE5 0x1044
#define USB_DEVICE_ID_GIGABYTE_AERO17XE5 0x7A40

#endif
2 changes: 1 addition & 1 deletion install_files/udev/99-gigabyte.rules
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ GOTO="gigabyte_end"
LABEL="gigabyte_vendor"

# Keyboards
ATTRS{idProduct}=="7A39|7A3F|7A3B|7A3C", \
ATTRS{idProduct}=="7A39|7A3F|7A3B|7A3C|7A40", \
ATTRS{idVendor}=="1044", \
ENV{GIGABYTE_DRIVER}="gigabytekbd"

Expand Down