Advertisement
Coproscefalo

toshiba_bluetooth.c

Feb 26th, 2015
479
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.33 KB | None | 0 0
  1. /*
  2.  * Toshiba Bluetooth Enable Driver
  3.  *
  4.  * Copyright (C) 2009 Jes Sorensen <Jes.Sorensen@gmail.com>
  5.  * Copyright (C) 2015 Azael Avalos <coproscefalo@gmail.com>
  6.  *
  7.  * Thanks to Matthew Garrett for background info on ACPI innards which
  8.  * normal people aren't meant to understand :-)
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License version 2 as
  12.  * published by the Free Software Foundation.
  13.  *
  14.  * Note the Toshiba Bluetooth RFKill switch seems to be a strange
  15.  * fish. It only provides a BT event when the switch is flipped to
  16.  * the 'on' position. When flipping it to 'off', the USB device is
  17.  * simply pulled away underneath us, without any BT event being
  18.  * delivered.
  19.  */
  20.  
  21. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  22.  
  23. #include <linux/kernel.h>
  24. #include <linux/module.h>
  25. #include <linux/init.h>
  26. #include <linux/types.h>
  27. #include <linux/acpi.h>
  28.  
  29. #define BT_KILLSWITCH_MASK  0x01
  30. #define BT_PLUGGED_MASK     0x40
  31. #define BT_POWER_MASK       0x80
  32.  
  33. MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@gmail.com>");
  34. MODULE_DESCRIPTION("Toshiba Laptop ACPI Bluetooth Enable Driver");
  35. MODULE_LICENSE("GPL");
  36.  
  37. static int toshiba_bluetooth_add(struct acpi_device *device);
  38. static int toshiba_bluetooth_remove(struct acpi_device *device);
  39. static void toshiba_bluetooth_notify(struct acpi_device *device, u32 event);
  40.  
  41. static const struct acpi_device_id toshiba_bluetooth_device_ids[] = {
  42.     { "TOS6205", 0},
  43.     { "", 0},
  44. };
  45. MODULE_DEVICE_TABLE(acpi, toshiba_bluetooth_device_ids);
  46.  
  47. #ifdef CONFIG_PM_SLEEP
  48. static int toshiba_bluetooth_resume(struct device *dev);
  49. #endif
  50. static SIMPLE_DEV_PM_OPS(toshiba_bluetooth_pm, NULL, toshiba_bluetooth_resume);
  51.  
  52. static struct acpi_driver toshiba_bluetooth_driver = {
  53.     .name =     "Toshiba BT",
  54.     .class =    "Toshiba",
  55.     .ids =      toshiba_bluetooth_device_ids,
  56.     .ops =      {
  57.                 .add =      toshiba_bluetooth_add,
  58.                 .remove =   toshiba_bluetooth_remove,
  59.                 .notify =   toshiba_bluetooth_notify,
  60.             },
  61.     .owner =    THIS_MODULE,
  62.     .drv.pm =   &toshiba_bluetooth_pm,
  63. };
  64.  
  65. static int toshiba_bluetooth_present(acpi_handle handle)
  66. {
  67.     acpi_status result;
  68.     u64 bt_present;
  69.  
  70.     /*
  71.      * Some Toshiba laptops may have a fake TOS6205 device in
  72.      * their ACPI BIOS, so query the _STA method to see if there
  73.      * is really anything there.
  74.      */
  75.     result = acpi_evaluate_integer(handle, "_STA", NULL, &bt_present);
  76.     if (ACPI_FAILURE(result)) {
  77.         pr_err("ACPI call to query Bluetooth presence failed");
  78.         return -ENXIO;
  79.     } else if (!bt_present) {
  80.         pr_info("Bluetooth device not present\n");
  81.         return -ENODEV;
  82.     }
  83.  
  84.     return 0;
  85. }
  86.  
  87. static int toshiba_bluetooth_status(acpi_handle handle)
  88. {
  89.     acpi_status result;
  90.     u64 status;
  91.  
  92.     result = acpi_evaluate_integer(handle, "BTST", NULL, &status);
  93.     if (ACPI_FAILURE(result)) {
  94.         pr_err("Could not get Bluetooth device status\n");
  95.         return -ENXIO;
  96.     }
  97.  
  98.     pr_info("Bluetooth status %llu\n", status);
  99.  
  100.     return status;
  101. }
  102.  
  103. static int toshiba_bluetooth_enable(acpi_handle handle)
  104. {
  105.     acpi_status result;
  106.  
  107.     result = acpi_evaluate_object(handle, "AUSB", NULL, NULL);
  108.     if (ACPI_FAILURE(result)) {
  109.         pr_err("Could not attach USB Bluetooth device\n");
  110.         return -ENXIO;
  111.     }
  112.  
  113.     result = acpi_evaluate_object(handle, "BTPO", NULL, NULL);
  114.     if (ACPI_FAILURE(result)) {
  115.         pr_err("Could not power ON Bluetooth device\n");
  116.         return -ENXIO;
  117.     }
  118.  
  119.     return 0;
  120. }
  121.  
  122. static int toshiba_bluetooth_disable(acpi_handle handle)
  123. {
  124.     acpi_status result;
  125.  
  126.     result = acpi_evaluate_object(handle, "BTPF", NULL, NULL);
  127.     if (ACPI_FAILURE(result)) {
  128.         pr_err("Could not power OFF Bluetooth device\n");
  129.         return -ENXIO;
  130.     }
  131.  
  132.     result = acpi_evaluate_object(handle, "DUSB", NULL, NULL);
  133.     if (ACPI_FAILURE(result)) {
  134.         pr_err("Could not detach USB Bluetooth device\n");
  135.         return -ENXIO;
  136.     }
  137.  
  138.     return 0;
  139. }
  140.  
  141. static void toshiba_bluetooth_notify(struct acpi_device *device, u32 event)
  142. {
  143.     int status;
  144.  
  145.     pr_info("Received event %x\n", event);
  146.  
  147.     /* Query the status of the Bluetooth device */
  148.     status = toshiba_bluetooth_status(device->handle);
  149.     if (status < 0)
  150.         pr_err("Error while querying Bluetooth status\n");
  151.  
  152.     pr_info("Switch status %x\n", status & BT_KILLSWITCH_MASK);
  153.     pr_info("Power status %x\n", status & BT_POWER_MASK);
  154.     pr_info("Plug status %x\n", status & BT_PLUGGED_MASK);
  155.  
  156.     /* TODO: Add event handling here depending on Bluetooth status */
  157. }
  158.  
  159. #ifdef CONFIG_PM_SLEEP
  160. static int toshiba_bluetooth_resume(struct device *dev)
  161. {
  162.     return toshiba_bluetooth_enable(to_acpi_device(dev)->handle);
  163. }
  164. #endif
  165.  
  166. static int toshiba_bluetooth_add(struct acpi_device *device)
  167. {
  168.     int result;
  169.  
  170.     result = toshiba_bluetooth_present(device->handle);
  171.     if (result)
  172.         return result;
  173.  
  174.     pr_info("Toshiba ACPI Bluetooth device driver\n");
  175.  
  176.     /* Enable the BT device */
  177.     result = toshiba_bluetooth_enable(device->handle);
  178.     if (result)
  179.         return result;
  180.  
  181.     /* Query the status of the BT device */
  182.     result = toshiba_bluetooth_status(device->handle);
  183.     if (result < 0)
  184.         return result;
  185.  
  186.     pr_info("Switch status %x\n", result & BT_KILLSWITCH_MASK);
  187.     pr_info("Power status %x\n", result & BT_POWER_MASK);
  188.     pr_info("Plug status %x\n", result & BT_PLUGGED_MASK);
  189.  
  190.     return 0;
  191. }
  192.  
  193. static int toshiba_bluetooth_remove(struct acpi_device *device)
  194. {
  195.     /* Clean up */
  196.     return toshiba_bluetooth_disable(device->handle);
  197. }
  198.  
  199. module_acpi_driver(toshiba_bluetooth_driver);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement