/*! * Copyright (c) 2018-2020 TUXEDO Computers GmbH * * This file is part of tuxedo-keyboard. * * tuxedo-keyboard is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This software is distributed in the hope that 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 software. If not, see . */ #define pr_fmt(fmt) "tuxedo_keyboard" ": " fmt #include "tuxedo_keyboard_common.h" #include "clevo_keyboard.h" #include "uniwill_keyboard.h" #include MODULE_AUTHOR("TUXEDO Computers GmbH "); MODULE_DESCRIPTION("TUXEDO Computers keyboard & keyboard backlight Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION("3.0.4"); MODULE_ALIAS("wmi:" UNIWILL_WMI_EVENT_GUID_0); MODULE_ALIAS("wmi:" UNIWILL_WMI_EVENT_GUID_1); MODULE_ALIAS("wmi:" UNIWILL_WMI_EVENT_GUID_2); MODULE_SOFTDEP("pre: tuxedo-cc-wmi"); static DEFINE_MUTEX(tuxedo_keyboard_init_driver_lock); static struct tuxedo_keyboard_driver *driver_list[] = { &uniwill_keyboard_driver }; static int tuxedo_input_init(const struct key_entry key_map[]) { int err; tuxedo_input_device = input_allocate_device(); if (unlikely(!tuxedo_input_device)) { TUXEDO_ERROR("Error allocating input device\n"); return -ENOMEM; } tuxedo_input_device->name = "TUXEDO Keyboard"; tuxedo_input_device->phys = DRIVER_NAME "/input0"; tuxedo_input_device->id.bustype = BUS_HOST; tuxedo_input_device->dev.parent = &tuxedo_platform_device->dev; if (key_map != NULL) { err = sparse_keymap_setup(tuxedo_input_device, key_map, NULL); if (err) { TUXEDO_ERROR("Failed to setup sparse keymap\n"); goto err_free_input_device; } } err = input_register_device(tuxedo_input_device); if (unlikely(err)) { TUXEDO_ERROR("Error registering input device\n"); goto err_free_input_device; } return 0; err_free_input_device: input_free_device(tuxedo_input_device); return err; } struct platform_device *tuxedo_keyboard_init_driver(struct tuxedo_keyboard_driver *tk_driver) { int err; struct platform_device *new_platform_device = NULL; TUXEDO_DEBUG("init driver start\n"); mutex_lock(&tuxedo_keyboard_init_driver_lock); if (!IS_ERR_OR_NULL(tuxedo_platform_device)) { // If already initialized, don't proceed TUXEDO_DEBUG("platform device already initialized\n"); goto init_driver_exit; } else { // Otherwise, attempt to initialize structures TUXEDO_DEBUG("create platform bundle\n"); new_platform_device = platform_create_bundle( tk_driver->platform_driver, tk_driver->probe, NULL, 0, NULL, 0); tuxedo_platform_device = new_platform_device; if (IS_ERR_OR_NULL(tuxedo_platform_device)) { // Normal case probe failed, no init goto init_driver_exit; } TUXEDO_DEBUG("initialize input device\n"); if (tk_driver->key_map != NULL) { err = tuxedo_input_init(tk_driver->key_map); if (unlikely(err)) { TUXEDO_ERROR("Could not register input device\n"); tk_driver->input_device = NULL; } else { TUXEDO_DEBUG("input device registered\n"); tk_driver->input_device = tuxedo_input_device; } } current_driver = tk_driver; } init_driver_exit: mutex_unlock(&tuxedo_keyboard_init_driver_lock); return new_platform_device; } EXPORT_SYMBOL(tuxedo_keyboard_init_driver); static void __exit tuxedo_input_exit(void) { if (unlikely(!tuxedo_input_device)) { return; } input_unregister_device(tuxedo_input_device); { tuxedo_input_device = NULL; } } static int __init tuxedo_keyboard_init(void) { int i; int num_drivers = sizeof(driver_list) / sizeof(*driver_list); TUXEDO_INFO("Model '%s' found\n", dmi_get_system_info(DMI_PRODUCT_NAME)); // Attempt to load each available driver // Associated probe decides if it fits // Driver from first successful probe is used i = 0; while (IS_ERR_OR_NULL(tuxedo_platform_device) && i < num_drivers) { current_driver = driver_list[i]; tuxedo_keyboard_init_driver(current_driver); ++i; } if (IS_ERR_OR_NULL(tuxedo_platform_device)) { TUXEDO_DEBUG("No matching hardware found on init\n"); current_driver = NULL; } return 0; } static void __exit tuxedo_keyboard_exit(void) { TUXEDO_DEBUG("tuxedo_input_exit()\n"); tuxedo_input_exit(); TUXEDO_DEBUG("platform_device_unregister()\n"); if (!IS_ERR_OR_NULL(tuxedo_platform_device)) platform_device_unregister(tuxedo_platform_device); TUXEDO_DEBUG("platform_driver_unregister()\n"); if (!IS_ERR_OR_NULL(current_driver)) platform_driver_unregister(current_driver->platform_driver); TUXEDO_DEBUG("exit\n"); } module_init(tuxedo_keyboard_init); module_exit(tuxedo_keyboard_exit);